Channels ▼
RSS

Web Development

Currying and Partial Functions in JavaScript


Currying

Currying has nothing to do with the spicy Indian dish; it comes from the name of the mathematician Haskell Curry. (The Haskell programming language is also named after him.) Currying is a transformation process — we transform a function. An alternative name for currying could be schönfinkelisation, after the name of another mathematician, Moses Schönfinkel, the original inventor of this transformation.

So how do we schönfinkelify (or schönfinkelize or curry) a function? Other functional languages may have that built right into the language itself and all functions are curried by default. In JavaScript we can modify the add() function into a curried one that will handle partial application. Let's take an example:

// a curried add()
// accepts partial list of arguments
function add(x, y) {
     var oldx = x, oldy = y;
     if (typeof oldy === "undefined") { // partial
        return function (newy) {
             return oldx + newy;
        };
     }
     // full application
     return x + y;
}

// test

typeof add(5); // "function"
add(3)(4); // 7
// create and store a new function
var add2000 = add(2000);
add2000(10); // 2010

In this snippet, the first time you call add(), it creates a closure around the inner function it returns. The closure stores the original values x and y into private variables oldx and oldy. The first one, oldx, is used when the inner function executes. If there's no partial application and both x and y are passed, the function proceeds to simply add them.

This implementation of add() is a little more verbose than needed, just for illustration purposes. A more compact version is shown in the next snippet, where there's no oldx and oldy, simply because the original x is stored in the closure implicitly and we reuse y as a local variable instead of creating a new variable newy as we did in the previous example:

// a curried add
// accepts partial list of arguments
function add(x, y) {
     if (typeof y === "undefined") { // partial
        return function (y) {
              return x + y;
        };
     }
   // full application
   return x + y;
}

In these examples, the function add() itself took care of partial applications. But can we do the same in a more generic fashion? In other words, can we transform any function into a new one that accepts partial parameters? The next snippet shows an example of a general-purpose function, let's call it schonfinkelize(), which does just that. We use the name schonfinkelize() partially because it's a challenge to pronounce and partially because it sounds like a verb (using "curry" could be ambiguous), and we need a verb to denote that this is a transformation of a function.

Here is the general-purpose currying function:

function schonfinkelize(fn) {
     var slice = Array.prototype.slice,
        stored_args = slice.call(arguments, 1);
     return function () {
        var new_args = slice.call(arguments),
              args = stored_args.concat(new_args);
        return fn.apply(null, args);
     };
}

The schonfinkelize() function is probably a little more complicated than it should be, but only because arguments is not a real array in JavaScript. Borrowing the slice() method from Array.prototype helps us turn arguments into an array and work more conveniently with it. When schonfinkelize() is called the first time, it stores a private reference to the slice() method (called slice) and also stores the arguments it was called with (into stored_args), only stripping the first, because the first argument is the function being curried. Then schonfinkelize() returns a new function. When the new function is called, it has access (via the closure) to the already privately stored arguments stored_args and the slice reference. The new function has to merge only the old partially applied arguments (stored_args) with the new ones (new_args) and then apply them to the original function fn (also privately available in the closure).

Now, armed with a general-purpose way of making any function curried, let's give it a try with a few tests:

// a normal function
function add(x, y) {
     return x + y;
}
// curry a function to get a new function
var newadd = schonfinkelize(add, 5);
newadd(4); // 9
// another option -- call the new function directly
schonfinkelize(add, 6)(7); // 13

The transformation function schonfinkelize() is not limited to single parameters or to single-step currying. Here are some more usage examples:

// a normal function
function add(a, b, c, d, e) {
     return a + b + c + d + e;
}
// works with any number of arguments
schonfinkelize(add, 1, 2, 3)(5, 5); // 16
// two-step currying
var addOne = schonfinkelize(add, 1);
addOne(10, 10, 10, 10); // 41
var addSix = schonfinkelize(addOne, 2, 3);
addSix(5, 5); // 16

When to Use Currying

When you find yourself calling the same function and passing mostly the same parameters, then the function is probably a good candidate for currying. You can create a new function dynamically by partially applying a set of arguments to your function. The new function will keep the repeated parameters stored (so you don't have to pass them every time) and will use them to pre-fill the full list of arguments that the original function expects.


This article was adapted from JavaScript Patterns, published by O'Reilly. See http://oreilly.com/catalog/9780596806767.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 
Dr. Dobb's TV