Partial Application in JavaScript

Partially applying a function is a, particularly, interesting technique in which you can pre-fill-in arguments to a function before it is ever executed. In effect, partially applying a function returns a new function which you can call. This is best understood through an example:

  String.prototype.csv = String.prototype.split.partial(/,\s*/);
  
  var results = "John, Resig, Boston".csv();
  alert( (results[1] == "Resig") + " The text values were split properly" );

In the above case we’ve taken a common function – a String’s .split() method – and have pre-filled-in the regular expression upon which to split. The result is a new function, .csv() that we can call at any point to convert a list of comma-separated values into an array. Filling in the first couple arguments of a function (and returning a new function) is typically called currying. With that in mind, let’s look at how currying is, roughly, implemented in the Prototype library:

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

This is a good case of using a closure to remember state. In this case we want to remember the arguments that were pre-filled-in (args) and transfer them to the newly-constructed function. This new function will have the filled-in arguments and the new arguments concat’d together and passed in. The result is a method that allows us to fill in arguments, giving us a new function that we can use.

Now, this style of partial application is perfectly useful, but we can do better. What if we wanted to fill in any missing argument from a given function – not just the first ones. Implementations of this style of partial application have existed in other languages but Oliver Steele was one of the first to demonstrate it with his Functional.js library. Let’s take a look at a possible implementation:

  Function.prototype.partial = function(){
    var fn = this, args = Array.prototype.slice.call(arguments);
    return function(){
      var arg = 0;
      for ( var i = 0; i < args.length && arg < arguments.length; i++ )
        if ( args&#91;i&#93; === undefined )
          args&#91;i&#93; = arguments&#91;arg++&#93;;
      return fn.apply(this, args);
    };
  };&#91;/js&#93;

This implementation is fundamentally similar to the <code>.curry()</code> method, but has a couple important differences. Notably, when called, the user can specify arguments that will be filled in later by specifying <code>undefined</code>, for it. To accommodate this we have to increase the ability of our arguments-merging technique. Effectively, we have to loop through the arguments that are passed in and look for the appropriate gaps, filling in the missing pieces that were specified.

We already had the example of constructing a string splitting function, above, but let's look at some other ways in which this new functionality could be used.  To start we could construct a function that's able to be easily delayed:

[js]  var delay = setTimeout.partial(undefined, 10);
  
  delay(function(){
    alert( "A call to this function will be temporarily delayed." );
  });

This means that we now have a new function, named delay, which we can pass another function in to, at any time, to have it be called asynchronously (after 10 milliseconds).

We could, also create a simple function for binding events:

  var bindClick = document.body.addEventListener
    .partial("click", undefined, false);
  
  bindClick(function(){
    alert( "Click event bound via curried function." );
  });

This technique could be used to construct simple helper methods for event binding in a library. The result would be a simpler API where the end-user wouldn’t be inconvenienced by unnecessary function arguments, reducing them to a single function call with the partial application.

In the end we’ve used closures to easily, and simply, reduce the complexity of some code, easily demonstrating some of the power that functional JavaScript programming has.


This is an excerpt from my work-in-progress book: Secrets of the JavaScript Ninja. To be released Fall 2008.

Posted: February 14th, 2008


Subscribe for email updates

22 Comments (Show Comments)



Comments are closed.
Comments are automatically turned off two weeks after the original post. If you have a question concerning the content of this post, please feel free to contact me.


Secrets of the JavaScript Ninja

Secrets of the JS Ninja

Secret techniques of top JavaScript programmers. Published by Manning.

John Resig Twitter Updates

@jeresig / Mastodon

Infrequent, short, updates and links.