6 Feb 2012

Currying in JavaScript using bind()

Currying, or more accurately, partial application is the process of breaking down a function that takes multiple arguments into a series of functions that take parts of the arguments. It comes in handy whenever you don’t have all the required arguments to a function at the present time.

For example, consider a function add that takes 3 integers, and returns their sum. Using partial application, you can do this:

intermediate = add(1,2)
 
# .. do some other calculations ..
 
result = intermediate(3)  # 6

So, currying simply allows you to apply the arguments to a function in multiple steps. Some languages support curried functions out-of-the-box (like OCaml), while in other languages like JavaScript, you need to use a helper function to achieve this (side note: Functional.js and Underscore are both terrific libraries that offer various functional extensions to JavaScript, including currying).

ECMAScript 5 introduced bind() which brings (among other things) native currying to JavaScript. Once again, let’s take the add function.

function add(a,b,c) {
  return a+b+c;
}

This is how you curry it using bind().

var intermediate = add.bind(undefined, 1, 2);
var result = intermediate(3);   // 6

The first argument to bind() actually sets the infamous this context of the function. We can leave it undefined here, since it has no effect.

So, why curry? Currying is both elegant and useful when you want to cache re-usable computations. I am going to steal this converter example, which I have refactored to use bind().

function converter(toUnit, factor, offset, input) {
    offset = offset || 0;
    return [((offset+input)*factor).toFixed(2), toUnit].join(" ");
}
 
var milesToKm = converter.bind(undefined, 'km', 1.60936, 0);
var poundsToKg = converter.bind(undefined, 'kg', 0.45460, 0);
var farenheitToCelsius = converter.bind(undefined, 'degrees C',0.5556, -32);
 
milesToKm(10);            // returns "16.09 km"
poundsToKg(2.5);          // returns "1.14 kg"
farenheitToCelsius(98);   // returns "36.67 degrees C"

You can follow me on Twitter right here.

Tagged with:

4 people have responded to this post.

Leave a Reply