Currying and binding

If you wonder where the term currying is coming form, the answer is in the Haskell Brooks Curry logician name, and it refers to the partial application of parameters to a function. In JavaScript this is done by the bind() method, defined in ECMAScript 5.

And if you wonder what is all this fuss about binding and currying, you probably don't have a background in functional programming or, as it is my case, in C++. But don't worry, it is easy to catch up, and I reckon you are going to fall in love with them too.

Say that you have written a complicated function, you spent a lot of time to develop, test, and maintain it. You are very happy with it, and your users too. Let's simulate it with something a bit simpler:
function sum(x, y) {
    return x + y;
}
Then you find out that your cool function is often used passing always only a "real" parameter, being the other just a constant. In my example, the story would be that I wrote a sum() function, but I find out that the users often need just an increase(). Duplicating the code looks a poor solution, it would be better to create an adapter that provides just a more natural interface to the user, but keep almost all the coding effort in the original function.

Here I define next(), as a synonym of sum() that always uses 1 as a first parameter, and lets the user specify the other one:
var next = sum.bind(null, 1);

console.log("original interface", sum(42, 1));
console.log("more natural solution", next(42));
Good. But what is the null I passed to bind() as first parameter?

The fact is that JavaScript() bind() is not only about currying but, as its name suggests, it also performs an optional binding of the function to a specified object. In the previous case we didn't have any object interested in this feature, so I just passed a null instead.

To see bind() in full action, let's change a bit the startup condition. We already have an increasing function, but now it is a method, bound to an object:
var calculator = {
    step: 1,
    increase: function(x) {
        return this.step + x;
    }
};
console.log(calculator.increase(42));
calculator.step = 2; // 1
console.log("Double step: ", calculator.increase(42));
As we see in (1) it is pretty simple to change the increasing step in my calculator, but the user it is not completely happy with this solution. He didn't care of such a flexible solution, what he needs is just a function that returns its passed parameter increased by 2.

Luckily, we know that using bind() we can associate a function to different object, like this:
var step2 = calculator.increase.bind({step: 2}); 
console.log(step2(42));
We call bind() on the calculator.increase() method, and we pass to it as first (and only) parameter its new "this". In this case we don't want the step to be modifiable by the user, so we pass the object anonymously, making its reference lost to the outside world.

No comments:

Post a Comment