Currying JavaScript Functions

Currying a function is the act of transforming a function that takes n arguments into a function that takes n - 1 arguments. Essentially, currying is the act of binding the first argument of a function to a specific value, creating a new function that takes the remaining arguments. Here's a simple example:

function add(x, y) {
    return x + y;
}

// produces 7
add(3, 4);

// produces a function with x bound to 3 that takes y as an argument
var add3 = curry(add, 3);

// produces 7
add3(4);

In this example, we curry the add(x, y) function to produce the add3(y) function that always adds 3 to its only argument. While this may seem useless initially, currying is very useful in the context of Ajax callbacks. For example, say you want to add a constant amount 4 to a counter every time a button is clicked? Just curry!

button.onclick = curry(callback(this, addToTotal), 4);

Thanks to the functional parts of JavaScript and the ability to access JavaScript function arguments as an array with the arguments variable, implementing the curry function is easy, as this recipe illustrates:

function curry(method) {
    var curried = [];
    for (var i = 1; i < arguments.length; i++) {
        curried.push(arguments[i]);
    }
    return function() {
        var args = [];
        for (var i = 0; i < curried.length; i++) {
            args.push(curried[i]);
        }
        for (var i = 0; i < arguments.length; i++) {
            args.push(arguments[i]);
        }
        return method.apply(null, args);
    }
}

This curry function is more flexible than the formal definition of the term: you can bind as many arguments as you want when you call curry, like this example, where we bind the first two arguments of a function to produce a function that only takes one argument:

function add(x, y, z) {
    return x + y + z;
}

var add3 = curry(add, 2, 1); // binds x to 2 and y to 1
add3(5); // produces 8

See the example

Comments

Humm, well, why not use the slice method to get the curried arguments ? Because arguments is not a real array, well that's not a problem for javascript :

var curried = Array.prototype.slice.apply(arguments, [1]);

Another "problem" here, the variable i is declared twice in the same function scope, that's not really harming browsers, but that's a bad practice.
<p>To call the curried method add3() with arbitrary user input I discovered that you need to explicitly cast the user input to a js Number. e.g. If you've got a text input with id='userIn' on your page,
<pre>
var toAdd = Number(document.getElementById('userIn').value);
alert("add3 returns: " + add3(toAdd));
</pre>
or else the interpreter will treat the user input as a string (which is reasonable but not what we want).</p>
<p>Otherwise this is a great example, I had no idea that js could do such ruby-like stuff. ;-)</p>
Laurent: a variable declared within a for loop is declared within the scope of the for loop, so it is not declared twice.
There's no block scope in JavaScript.
See Ecma 262-3 sections 12.6.3 and 12.2.
Andy: I stand corrected! Thanks for pointing that out.
"a variable declared within a for loop is declared within the scope of the for loop, so it is not declared twice"

Ah ?! You are really sure ? Do you have any paragraph in ECMA262 I should read again ?

As far I know there is not such thing as "scope of the for loop", but let me try to proove it to you.

<script type="text/javascript">
alert(myVar + ' ' + typeof myVar);
</script>

This will broke with an error saying something pretty close to : myVar is not defined

Now, let's do it again but we add a for loop where we will declare the variable

<script type="text/javascript">
alert(myVar + ' ' + typeof myVar);
for ( var myVar = 0; myVar < 5; myVar++ ) {}
</script>

Now it does not break anymore, however the alert reports : undefined undefined

The "var myVar" within the for loop does not really looks declared only within the "for loop scope" as you stated.

Basically because the interpretor has transformed the code to this :

<script type="text/javascript">
var myVar;
alert(myVar + ' ' + typeof myVar);
for ( myVar = 0; myVar < 5; myVar++ ) {}
</script>

Let's keep testing your assertion. If you are right, the following source should break or at least reports "undefined undefined"

<script type="text/javascript">
for ( var i = 0; i < 2; i++ ) {}
for ( var k = 0; k < 1; k++ )
{
alert(i + ' ' + typeof i);
}
</script>

As expected it does not break, it alerts "2 number" which definitively means there is no such thing as the "scope of the for loop".

So as I said, your example is declaring twice the same variable "i". It does not really do any harm, but that is just a bad practice !!!

var i;
for (i = 0; i < curried.length; i++) { args.push(curried[i]); }
for (i = 0; i < arguments.length; i++) { args.push(arguments[i]); }
@Laurent: I think you're being a little precious here and I don't see how it is bad practice (!!!). Declaring a variable close to where it is being used is generally considered good practice. I agree that the scoping rules in javascript can be a little surprising but I would argue that the following is absolutely good practice:

for (var i = 0; i &lt; curried.length; i ) { args.push(curried[i]); }
for (var i = 0; i &lt; arguments.length; i ) { args.push(arguments[i]); }

Actually I would go further and write:

for (var i = 0, len = curried.length; i &lt; len; i ) { args.push(curried[i]); }
for (var i = 0, len = arguments.length; i &lt; len; i ) { args.push(arguments[i]); }

In your example, if you forget to declare &quot;var i&quot;, the i suddenly becomes a global. There are no bad side effects to declaring &quot;var i&quot; twice within the function as long as you are aware of javascript scoping rules. This is also good for when you or someone else maintaining the code, for example, deletes the first loop and the &quot;var i&quot; without realising that &quot;i&quot; is used in a second loop.
Aah great, I can never figure out when I need to escape. Let me try again.

Declaring a variable close to where it is being used is generally considered good practice. I agree that the scoping rules in javascript can be a little surprising but I would argue that the following is absolutely good practice:

for (var i = 0; i < curried.length; i++) { args.push(curried[i]); }
for (var i = 0; i < arguments.length; i++) { args.push(arguments[i]); }

Actually I would go further and write:

for (var i = 0, len = curried.length; i < len; i++) { args.push(curried[i]); }
for (var i = 0, len = arguments.length; i < len; i++) { args.push(arguments[i]); }

In your example, if you forget to declare "var i", the i suddenly becomes a global. There are no bad side effects to declaring "var i" twice within the function as long as you are aware of javascript scoping rules. This is also good for when you or someone else maintaining the code, for example, deletes the first loop and the "var i" without realising that "i" is used in a second loop. It's not such an issue for compiled languages where a compiler will catch this kind of mistake.
why not use concat()?

Write a Comment