Currying in JavaScript

Currying is the process of converting a multi-argument function to a series of single-argument ones. For example:

Instead of
f(x, y) -> x + y

We do
f(x) -> g(y) -> x + y

Filling in the values, we get

Before currying
f(1, 2) -> 1 + 2

After currying
f(1) -> g(y)
and g(y) -> 1 + y
so, g(2) -> 1 + 2
or, f(1)(2) -> 1 + 2

Why Curry?

The wikipedia article on currying does a much better job than me of explaining the motivation behind currying in mathematics. Basically it boils down to the fact that it is just easier to analyze a single-argument function. However there are also interesting uses in programming.

While I was searching for good examples of practical applications of currying, I came across this reddit thread and specifically the following example

A real example I use in my own code, is to avoid creating sub-classes solely to pass in variables. For example in an AST I am currently building in JS, I have the constructor for literal values use currying. Such as:

var Literal = function( value, cssClass ) {
  // setup code here
}

var TrueLiteral = Literal.curry( true, 'literal-true' );
That is much shorter than ...
var TrueLiteral = function() {
  Literal.call( this, true, 'literal-true';
}
TrueLiteral.prototype = Literal.prototype;

When you are having to sub-class just to add on default parameters for the super-class, that is a use case for currying.

Implementation

Let us consider our first example, that of adding two numbers.

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

sum(2, 3); // 5

If we wanted to convert this to a sequence of functions that each expect only a single argument, we could do the following:

function curriedSum(x) {
  return function (y) {
    x + y;
  }
}

curriedSum(2)(3);  // 5

Note how sum only expects a single argument, and returns another function which also expects a single argument. From a function that expected two arguments we now have two functions which expect one argument each.

This is however a naive implementation where the number of closures can quickly become unwieldy as the number of arguments increases. Moreover it is inconvenient to hand-craft curried versions of each function that we want to curry. An ideal implementation would be a curry function which could be used in the following manner:

function foo() {
  ...
}

var curriedFoo = curry(foo);

Simple, but incorrect (still useful though)

A simple implementation is done using partial application. However this solution is incorrect because curried functions always expect a single argument while partial application does not necessarily care about the number of arguments in each call. In the following example note that we can provide multiple arguments to the (incorrectly? impurely?) curried functions and they will be accepted.

function curry(fn) {
  var args = [];
  var innerCurry = function innerCurry() {
    args = args.concat(Array.from(arguments));
    if (args.length >= fn.length) {   // Remember JS just ignores extra arguments
      return fn.apply(null, args);    // Bind your functions if you care about context

    } else {
      // We need more arguments
      return innerCurry;
    }
  }

  return innerCurry;
}


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

// The following should all print the same output (9)
console.log(sum(2, 3, 4));
console.log(curry(sum)(2, 3, 4));
console.log(curry(sum)(2, 3)(4));
console.log(curry(sum)(2)(3)(4));
console.log(curry(sum)(2)(3, 4));

Correct

As per the definition of currying, the curried function should always expect a single argument. And in JavaScript, extra arguments are just ignored. So considering both of these our implementation should only consider the first argument and ignore the rest in each call. Here it is:

function curry(fn) {
  var args = [];
  var innerCurry = function innerCurry(x) {
    args.push(x);
    if (args.length === fn.length)
      return fn.apply(this, args);

    else
      return innerCurry;
  }

  return innerCurry;
}


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

console.log(sum(1, 2, 3));         // control. Result is 9
console.log(curry(sum)(1)(2)(3));  // correct application. Result is 9
console.log(curry(sum)()(2)(3));   // the empty parenthesis means x is undefined. Result is NaN
console.log(curry(sum)(1, 2)(3));  // x is 1, y is 3 (and not 2). 2 is ignored. Result is a function. Must be invoked once more.
console.log(curry(sum)(1, 2, 3));  // x is 1. 2 and 3 are ignored. Result is a function, must be invoked two more times.

Further reading

The Wikipedia articles on currying and partial application are both very informative by themselves. I also found some blogs to be very helpful in preparing this post. Here is the list:

CodePens

You can experiment with the two curry implementations using the following codepens. Note that despite the name both are implemented using partial application; the second version sticks to the mathematical definition by ignoring extra arguments.