Currying and Partial Application in JavaScript

Image

In my current journey to improve my knowledge of frontend JavaScript, I decided to read through Douglas Crockford’s book JavaScript: The Good Parts. A few of the functional features piqued my interest, and in particular, currying.

Currying allows a function to be broken up into nested functions, each with some of the arguments from the original signature. This can be useful for binding data to certain arguments of a function for later reusability. We’ll start with an example of a perimeter calculator for regular (all sides are equal length) shapes.

function calculatePerimeter(name, sides, length) {
    return ’This ’ + name + ' has ' + sides + ' sides and a perimeter of ' + sides*length;
};
output = calculatePerimeter(“Triangle”, 3, 10);  // This Triangle has 3 sides and a perimeter of 30

Every time we want a perimeter of a given shape, we need to pass in all three arguments. But what if we’re only dealing with triangles for a given period of time? Breaking calculatePerimeter into nested function calls would allow us to accommodate this.

function calculatePerimeter (name) {
    return function (sides) {
      return function (length) {
        return 'This ' + name + ' has ' + sides + ' sides and a perimeter of ' + sides*length;
    }
  }
}

//Using arrow notation
var calculatePerimeter = name => sides => length => 'This ' + name + ' has ' + sides + ' sides and a perimeter of ' + sides*length;

This function is now considered ‘curried.’ We can feed in arguments one by one with subsequent calls and be given back a function each time until all arguments are filled. Now let’s create a trianglePerimeter function.

var trianglePerimeter = calculatePerimeter(“Triangle”)(3);
var perimeterA = trianglePerimeter(9);  //This Triangle has 3 sides and a perimeter of 27
var perimeterB = trianglePerimeter(6)   //This Triangle has 3 sides and a perimeter of 18

We created a reusable function to get the perimeter specifically for triangles and we only sent arguments to calculatePerimeter once. Since we broke up the original calculatePerimeter into a separate function for each argument, we had to invoke one function to set name and another to set sides . This is the reason for two sets of parentheses at calculatePerimeter: after we send the name we are returned a new function awaiting the number of sides, and we immediately call it with 3. A final function is returned only needing the length, which we set to trianglePerimeter.

Breaking functions up by hand like this can be quite annoying and ugly. Plus, we might only want a curried version of a function in specific cases. Crockford provides a way to handle on-the-fly currying by modifying the Function prototype. From the book:

Function.prototype.curry = function() {
    var slice = Array.prototype.slice,
        args = slice.apply(arguments),
          that = this;
  return function() {
      return that.apply(null, args.concat(slice.apply(arguments)));
  };
};

This method actually allows multiple arguments to be given to bind several parameters at once. Now, using our original calculatePerimeter function, we can achieve the effects of a currying whenever we need them.

function calculatePerimeter(name, sides, length) {
    return ’This ’ + name + ' has ' + sides + ' sides and a perimeter of ' + sides*length;
};
var hexagonPerimeter = calculatePerimeter.curry(“Hexagon", 6);
perimeter = hexagonPerimeter(7);  //This Hexagon has 6 sides and a perimeter of 42

It should be noted that even though Crockford named this method ‘curry,’ this is actually a different yet related concept called ‘partial application.’ True currying in the mathematical sense requires there to be a series of one-argument/1-arity functions for each argument in the original. A new function for the next argument is received from each call, until the last one is satisfied. Partial application allows some of the parameters of a function to be filled, and returns a new function asking for the rest of the remaining functions. With this curry function we can do:

mysteryPerimeter = calculatePerimeter.curry(“Mystery Shape”);
perimeter = mysteryPerimeter(5, 12); //This Mystery Shape has 5 sides and a perimeter of 60

mysteryPerimeter is not a chain of functions, but instead a single function that you can call with the remaining missing parameters. “Real” currying can be emulated by making repeated calls to curry with a singular argument. In practice, there are probably not too many instances where currying is actually needed over partial application. During my time looking through online communities, the two terms are often confused and used interchangeably — at least when discussing JS.

The curry package provides a hybrid solution. Functions are curried in the true sense, but are also allowed to be used with partial application. Using our example:

curriedPerimeter = curry(calculatePerimeter);
perimeter = curriedPerimeter(“Triangle”)(3)(10);
perimeter = curriedPerimeter(“Triangle”, 3)(10);
perimeter = curriedPerimeter(“Triangle”)(3, 10);
perimeter = curriedPerimeter(“Triangle”, 3, 10);

All of these are valid and achieve the same result. It bridges the gap between currying and partial application — and might add to the confusion of the two concepts.

Being able to use curried and partially-applied functions adds a large amount of flexibility to your code. More abstract functions can be configured into smaller, more easily understood functions. And, of course, lots of repetition can be avoided.

New call-to-action

Photo credit: Keith Allison from Hanover, MD, USA – Stephen Curry
CC BY-SA 2.0

Currying and Partial Application in JavaScript

Leave a Reply

Your email address will not be published. Required fields are marked *