This article is a part of the ReturnTrue series. Here we solve ReturnTrue puzzles and try to explain how we find solutions and why exactly they work.
The goal is not to show the answers but to dive deep into the elaborate internals of JavaScript and browsers. Yet, we recommend you try to find solutions yourself. It would be more interesting this way, be sure.
Alright, the disclaimer is over. Let’s continue with an introduction explaining what ReturnTrue is.
Introduction
ReturnTrue is a set of puzzles. Each of them is a tricky function.
You should pass arguments to such a function, and the result of its evaluation should be true
. Not “truthy value”, but exactly true
.
Erling Ellingsen, a programmer from Norway, created the game more than six years ago. Kudos to him and all the contributors!
Finally, let’s start.
ID
function id(x) {
return x;
}
Easy. The main goal of this task is to explain the rules.
The solution is obvious:
id(true)
The game assumes that the shorter solution the better. What is shorter than true
? Not-zero!
id(!0)
Two symbols. Not bad.
But wait, why is it called “id”?
Glad you asked!
The title “id” here is not by accident. There is a mathematical term called identity function. It is a function that returns its argument without changing it.
To explain when we may use it, let’s assume we want to go through an array of numbers and increase each odd value by 1. Here is how it may look in JavaScript:
arr.map(x => x % 2 ? x + 1 : x)
But even though we use map
here, the code is not “functional” enough. In functional programming, it is more common to use functions, not statements. In other words, programmers say what to do, not how. They are trying to be declarative, not to be imperative.
So, if our code was truly functional, it would look like this:
map(arr, when(isOdd, inc, id))
Here you can see a typical functional way to process data.
We pass data to a pipeline, which transforms it, and returns the result. No more of those nasty statements, my precious!
Usually, a functional programming language has the functions like those we used. For instance, Clojure has identity, F# has id, Elixir has identity/1, and so on.
But, JavaScript was not designed as a pure functional language. So, their implementation may look like this:
const isOdd = x => x % 2 === 1;
const inc = x => x + 1;
const id = x => x;
const when = (cond, thenFn, elseFn) => x => cond(x) ? thenFn(x) : elseFn(x);
const map = (xs, fn) => xs.map(fn);
And now you see when the function returning its argument may be handy.
Do we need such a function?
Yeah, it may look weird in the context of front-end development. One may even say that id
function is a kludge from FP world.
Sure, it may sound like a joke or a “bug” of programming language design. First, you define functions that can not be evaluated without passed arguments (e.g. when
function we defined above). Then, you define more functions to use them as a sticky patch for the previously defined.
However, the functional programming paradigm is trying to be as close as possible to math. id
function is a normal thing for this field of science.
It may not be obvious why exactly we need such a function. But, when we work with numbers, we use some special ones like 0 or 1.
When we work with arrays, the special one is an empty array. When we work with functions, we need a “special” one too. It is id
.
It may look like overhead sometimes, and you may think: "Why not define when
function another way, where elseFn
will not be required?". Sure, it’s possible. But explicit is better than implicit.
Originally published by Igor Adamenko in Uploadcare Blog
Top comments (0)