Partial Application in JavaScript

"Cowboy" Ben Alman | January 13, 2011

 

Unless you've used a functional programming language such as ML or Haskell, concepts such as partial application and currying may be foreign to you. Since JavaScript supports first-class functions, once you understand these concepts, you can put them to use in your code.

Let's dive right in and take a look at a completely contrived example:

function add( a, b ) {
  return a + b;
}

add( 1, 2 );    // 3
add( 1, 3 );    // 4
add( 1, 10 );   // 11
add( 1, 9000 ); // 9001

While this example is very simple, try to envision a scenario in which you must repeatedly invoke a function, passing the same first argument every single time. Since needless repetition tends to be a major cause of errors, one way to address this and DRY up that code is to store the value of the repeated argument in a variable, then reference that variable each time.

function add( a, b ) {
  return a + b;
}

var one = 1;

add( one, 2 );    // 3
add( one, 3 );    // 4
add( one, 10 );   // 11
add( one, 9000 ); // 9001

In this example, using a variable as an argument substitute definitely makes this code more easily updatable, which makes it more maintainable. On the other hand, if adding one is going to be done a lot, it might be more beneficial to create a more specialized function that has this functionality built-in.

A Common Use-Case

Whether writing code just for yourself or presenting an API to your users, it's often helpful to create a more specialized function as a "wrapper" to a more generalized function if you expect to be performing a task repetitively. One way to do this would be to just define the functions manually.

// More general function.

function add( a, b ) {
  return a + b;
}

// More specific functions.

function add1( b ) {
  return add( 1, b );
}

function add10( b ) {
  return add( 10, b );
}

add( 1, 2 );  // 3
add( 10, 3 ); // 13

add1( 2 );    // 3
add1( 3 );    // 4

add10( 2 );   // 12
add10( 3 );   // 13

While defining a few specialized functions in this manner is very simple and straightforward, if you have enough of them it can add a lot of extra code, which then has to be maintained.

A Not-Very-Flexible Solution

Because of the functional nature of JavaScript, it is possible to create a generic makeAdder function that behaves as-follows: The makeAdder function, when invoked with an argument, returns a new function. This returned function, when invoked with an argument, adds the new value to the initially-specified value, returning that result. The argument initially passed in to the makeAdder function is effectively "locked in" at its value.

// More-general function.

 function add( a, b ) {
  return a + b;
}

// More-specific function generator.

function makeAdder( a ) {
  return function( b ) {
    return a + b;
  };
}

add( 1, 2 );  // 3
add( 10, 3 ); // 13

var add1 = makeAdder( 1 );
add1( 2 );    // 3
add1( 3 );    // 4

var add10 = makeAdder( 10 );
add10( 2 );   // 12
add10( 3 );   // 13

Of course, while this offers the convenience of allowing you to call add1( 2 ) instead of add( 1, 2 ), it doesn't come without a price. First, the actual adding logic is duplicated in both the add and makeAdder functions, which for less contrived and more complex examples can be problematic since the code is no longer as DRY as it could be. Second, for every different function you want to handle in this manner, you need to create a new makeAdder-type function-returning function.

A Slightly More Flexible Solution

The next logical step is to create a more generalized version of the makeAdder function that not only accepts an argument to be "locked in" but also accepts a function to be invoked. This way, you can easily reuse this functionality to create locked in versions of other functions.

// More-general functions.

function add( a, b ) {
  return a + b;
}

function multiply( a, b ) {
  return a * b;
}

// Relatively flexible more-specific function generator.

function lockInFirstArg( fn, a ) {
  return function( b ) {
    return fn( a, b );
  };
}

var add1 = lockInFirstArg( add, 1 );
add1( 2 );    // 3
add1( 3 );    // 4
add1( 10 );   // 11
add1( 9000 ); // 9001

var mult10 = lockInFirstArg( multiply, 10 );
mult10( 2 );    // 20
mult10( 3 );    // 30
mult10( 10 );   // 100
mult10( 9000 ); // 90000

So what if you want to be able to "lock in" more than just that first argument? What if you have a function that accepts three arguments and you want to lock in either the first argument or both of the first two arguments, depending on the circumstance? Even though this solution is more flexible than before, it can still be improved.

Partial Application

Partial application can be described as taking a function that accepts some number of arguments, binding values to one or more of those arguments, and returning a new function that only accepts the remaining, un-bound arguments.

What this means is that, given any arbitrary function, a new function can be generated that has one or more arguments "locked in," or partially applied. If you've been paying attention, you should have realized that the previous few examples have all demonstrated partial application, albeit in a not-very-generalized way.

If you're familiar with the ECMAScript 5 bind function, which not only allows a function to have its context (the this value) overridden but some of its arguments specified as well, you've been exposed to partial application (in this example, it might help to think of this as an implicit 0th argument that gets partially applied).

The following example is significantly more flexible than the previous examples, because it uses the arguments object to determine how many arguments need to be partially applied.

Note that the arguments object is an array-like object created when a function is invoked, accessible only inside that function, containing all of the arguments passed into that function. While arguments is array-like, it is not an array. This means that while it has a .length property and numeric indices, it doesn't have the normal Array.concat or .slice methods. In order to convert the arguments object into an array, the native Array``.slice method (Array.prototype.slice) is invoked as if it existed on the arguments object via call.

Here, the partial function returns a function ƒ that, when invoked, invokes the originally-specified fn function with the originally-specified arguments, followed by all arguments passed to ƒ.

function partial( fn /*, args...*/) {
  var aps = Array.prototype.slice,
    args = aps.call( arguments, 1 );
  
  return function() {
    return fn.apply( this, args.concat( aps.call( arguments ) ) );
  };
}

// VERY BORING EXAMPLE

function add( a, b ) {
  return a + b;
}

var add1 = partial( add, 1 );
add1( 2 ); // 3
add1( 3 ); // 4
add1();    // NaN

var add10 = partial( add, 10 );
add10( 2 ); // 12
add10( 3 ); // 13
add10();    // NaN

This works because the originally passed arguments (sans the first fn argument, which is sliced off) are stored as the args array inside the closure that's created when the partial function is invoked. Since the function that gets returned has access to that args array, every time it is invoked, it invokes the originally-passed fn function using apply. Because apply accepts an array of arguments and concat joins two arrays, it is easy to invoke the fn function with the just-passed arguments "appended" to the originally-specified args arguments.

Note that add1() and add10() invoked without a numeric argument return NaN because, while a is a number, b is undefined, and adding a number to undefined evaluates to NaN.

Of course, partial application is most useful if you only partially apply the function arguments. If you choose to satisfy all the function arguments by specifying them all up front, you'll just end up with a function that behaves as if all its arguments had been hard-coded.

Function add( a, b ) {
  return a + b;
}

var return9 = partial( add, 4, 5 );
return9();       // 9
return9( 1 );    // 9 - this is like calling add( 4, 5, 1 )
return9( 9001 ); // 9 - this is like calling add( 4, 5, 9001 )

Note that until this point, all partial examples have only shown one specific variation of partial application, in which the leftmost function arguments are partially applied.

Partial Application: Variations

Using very similar code, it would be very easy to make a partialRight function that applies the rightmost function arguments. In fact, all that needs to be changed is the order in which the original, partially applied, arguments are concatenated with the remaining arguments.

In this example, the partialRight function returns a function ƒ that, when invoked, invokes the originally-specified fn function with the arguments passed to ƒ, followed by all the originally-specified arguments.

function partialRight( fn /*, args...*/) {
  var aps = Array.prototype.slice,
    args = aps.call( arguments, 1 );
  
  return function() {
    return fn.apply( this, aps.call( arguments ).concat( args ) );
  };
}

// SOMEWHAT GRATUITOUS EXAMPLE

function wedgie( a, b ) {
  return a + ' gives ' + b + ' a wedgie.'
}

var joeGivesWedgie = partial( wedgie, 'Joe' );
joeGivesWedgie( 'Ron' ); // "Joe gives Ron a wedgie."
joeGivesWedgie( 'Bob' ); // "Joe gives Bob a wedgie."

var joeReceivesWedgie = partialRight( wedgie, 'Joe' );
joeReceivesWedgie( 'Ron' ); // "Ron gives Joe a wedgie."
joeReceivesWedgie( 'Bob' ); // "Bob gives Joe a wedgie."

While the partial and partialRight functions partially apply arguments to either the left or right end, there's nothing stopping us from going one step further and creating a function that allows you to cherry-pick arguments to be partially applied. The wu.js and Functional Javascript libraries both have a method called partial that allows you to accomplish this using a placeholder value. In the following example, I'm going to name this function partialAny.

In this example, the partialAny function returns a function ƒ that, when invoked, invokes the originally-specified fn function with the originally-specified arguments. However, any "placeholder" originally-specified arguments (specified with partialAny._) will be replaced, in-order, with arguments passed when ƒ is invoked. Any remaining arguments passed to ƒ are added to the end.

Note: read up on immediately-invoked function expressions if you're unfamiliar with the (function(){ /* code */ })(); syntax.

var partialAny = (function(aps){
  
  // This function will be returned as a result of the immediately-
  // invoked function expression and assigned to the `partialAny` var.
  function func( fn /*, args...*/) {
    var argsOrig = aps.call( arguments, 1 );
    
    return function() {
      var args = [],
        argsPartial = aps.call( arguments ),
        i = 0;
      
      // Iterate over all the originally-specified arguments. If that
      // argument was the `partialAny._` placeholder, use the next just-
      // passed-in argument, otherwise use the originally-specified
      // argument.
      for ( ; i < argsOrig.length; i++ ) {
        args[i] = argsOrig[i] === func._
          ? argsPartial.shift()
          : argsOrig[i];
      }
      
      // If any just-passed-in arguments remain, add them to the end.
      return fn.apply( this, args.concat( argsPartial ) );
    };
  }
  
  // This is used as the placeholder argument.
  func._ = {};
  
  return func;
})(Array.prototype.slice);

// SLIGHTLY MORE LEGITIMATE EXAMPLE

function hex( r, g, b ) {
  return '#' + r + g + b;
}

var redMax = partialAny( hex, 'ff', partialAny._, partialAny._ );
redMax( '11', '22' ); // "#ff1122"

// Because `__` is easier on the eyes than `partialAny._`, let's use
// that instead. This is, of course, entirely optional, and the name
// could just as well be `foo` or `PLACEHOLDER` instead of `__`.

var __ = partialAny._;

var greenMax = partialAny( hex, __, 'ff' );
greenMax( '33', '44' ); // "#33ff44"

var blueMax = partialAny( hex, __, __, 'ff' );
blueMax( '55', '66' ); // "#5566ff"

var magentaMax = partialAny( hex, 'ff', __, 'ff' );
magentaMax( '77' ); // "#ff77ff"

While some libraries expose this partialAny functionality as partial, they are only able to use this name because they don't have another function called partial. That's because they name that functionality curry, but for the most part, that's not really the correct name for what their curry function is doing.

Since there appears to be some confusion around currying in general, I'm going to attempt to clear things up.

Currying

Currying can be described as transforming a function of N arguments in such a way that it can be called as a chain of N functions each with a single argument.

Once a function has been curried, it is effectively "primed" for partial application, because as soon as you start passing arguments into a curried function, you are partially applying it.

The following curry function returns a function ƒ that, when invoked, first checks to see if all of the fn function arguments have been satisfied. If so, fn is invoked with the originally-specified arguments, followed by all arguments passed to ƒ. If not, a function ƒ1 is returned (recursively), that behaves like function ƒ. Only once all the fn function arguments are satisfied is fn invoked.

Semantically, the following curry implementation could best be described as "transforming a function of N arguments in such a way that it can be called as a chain of functions each accepting zero or more arguments, until all N arguments have been satisfied." While this technically differs from the definition of currying, it can still emulate currying, and is arguably more flexible (which is possible because JavaScript is so flexible).

Note that while functions have a .length property that specifies the number of arguments expected by the function, in certain circumstances JavaScript cannot determine the number of expected arguments (for example, when a function uses the arguments object instead of individual arguments). In this case, you can specify a numeric value n before the function that will be used instead of the fn.length property.

function curry(/* n,*/ fn /*, args...*/) {
  var n,
    aps = Array.prototype.slice,
    orig_args = aps.call( arguments, 1 );
  
  if ( typeof fn === 'number' ) {
    n = fn;
    fn = orig_args.shift();
  } else {
    n = fn.length;
  }
  
  return function() {
    var args = orig_args.concat( aps.call( arguments ) );
    
    return args.length < n
      ? curry.apply( this, [ n, fn ].concat( args ) )
      : fn.apply( this, args );
  };
}

// TOTALLY CONTRIVED EXAMPLE

var i = 0;
function a( x, y, z ) {
  console.log( ++i + ': ' + x + ' and ' + y + ' or ' + z );
};

a( 'x', 'y', 'z' );     // "1: x and y or z"

var b = curry( a );
b();                    // nothing logged, `a` not invoked
b( 'x' );               // nothing logged, `a` not invoked
b( 'x', 'y' );          // nothing logged, `a` not invoked
b( 'x' )( 'y' );        // nothing logged, `a` not invoked
b( 'x' )( 'y' )( 'z' ); // "2: x and y or z"
b( 'x', 'y', 'z' );     // "3: x and y or z"

var c = curry( a, 'x' );
c();                    // nothing logged, `a` not invoked
c( 'y' );               // nothing logged, `a` not invoked
c( 'y', 'z' );          // "4: x and y or z"
c( 'y' )( 'z' );        // "5: x and y or z"

var d = curry( c, 'y' );
d();                    // nothing logged, `c` not invoked
d( 'z' );               // "6: x and y or z"

var e = curry( a, 'x', 'y' );
e();                    // nothing logged, `a` not invoked
e( 'z' );               // "7: x and y or z"

var f = curry( a, 'x', 'y', 'z' );
f();                    // "8: x and y or z"

// THE OPTIONAL `n` ARGUMENT

function aNoLength() {
  var x = arguments[0], y = arguments[1], z = arguments[2];
  console.log( ++i + ': ' + x + ' and ' + y + ' or ' + z );
};

// You must specify `n` of 3 here since aNoLength.length === 0!

var g = curry( 3, aNoLength );
g();                    // nothing logged, `aNoLength` not invoked
g( 'x' );               // nothing logged, `aNoLength` not invoked
g( 'x', 'y' );          // nothing logged, `aNoLength` not invoked
g( 'x' )( 'y' );        // nothing logged, `aNoLength` not invoked
g( 'x' )( 'y' )( 'z' ); // "9: x and y or z"
g( 'x', 'y', 'z' );     // "10: x and y or z"

var h = curry( 3, aNoLength, 'x' );
h();                    // nothing logged, `a` not invoked
h( 'y' );               // nothing logged, `a` not invoked
h( 'y', 'z' );          // "11: x and y or z"
h( 'y' )( 'z' );        // "12: x and y or z"

Partial Application vs Currying

In terms of real-world use, what's the difference between partial application and currying? Take a look at how partially applied functions and curried functions behave in yet another contrived example:

function add( a, b, c ) {
  var total = a + b + c;
  return a + '+' + b + '+' + c + '=' + total;
}

add( 1, 2, 3 ); // "1+2+3=6"

// Partial application

var add1partial = partial( add, 1 );
add1partial( 2, 3 ); // "1+2+3=6"
add1partial( 2 );    // "1+2+undefined=NaN"

// Currying

var add1curry = curry( add, 1 );
add1curry( 2, 3 ); // "1+2+3=6"
add1curry( 2 );    // a function is returned (what?!)

Unlike partial application, which invokes the partially applied function whether all of its arguments have been satisfied or not, a curried function will only be invoked once all of its arguments have been satisfied, otherwise a function will be returned.

But the function that gets returned, just like any other function, can be assigned to a variable and invoked, like so:

function add( a, b, c ) {
  var total = a + b + c;
  return a + '+' + b + '+' + c + '=' + total;
}

var add1curry = curry( add, 1 );
add1curry( 2, 3 );  // "1+2+3=6"
add1curry( 4, 5 );  // "1+4+5=10"

var add1and2curry = add1curry( 2 );
add1and2curry( 3 ); // "1+2+3=6"
add1and2curry( 4 ); // "1+2+4=7"

Of course, just like with immediately-invoked function expressions, functions don't need to be assigned to a named variable to be invoked, all you need to do is put () after them. And since curried functions keep returning a function until all their arguments have been satisfied, you can write some pretty crazy looking, yet totally valid, JavaScript.

curry( add, 1 )( 2 )( 3 );             // "1+2+3=6"
curry( add, 1, 2 )( 3 );               // "1+2+3=6"
curry( add, 1, 2, 3 )();               // "1+2+3=6"
curry( add )( 1 )( 2 )( 3 );           // "1+2+3=6"
curry( add, 1 )()( 2 )()( 3 );         // "1+2+3=6"
curry( add )()( 1 )()( 2 )()( 3 );     // "1+2+3=6"
curry( add, 1 )()()()( 2 )()()()( 3 ); // "1+2+3=6"

Maybe that last example isn't exactly real-world, but doesn't it look cool?

Currying in JavaScript

In JavaScript, while currying is clearly possible, it's arguably not quite as useful as in certain "other" functional programming languages like ML and Haskell. This is mainly due to the fact that JavaScript functions behave somewhat differently than in these other languages.

In the Learn You a Haskell for Great Good!Higher order functions chapter, it is explained that, "Every function in Haskell officially only takes one parameter. So how is it possible that we defined and used several functions that take more than one parameter so far? Well, it's a clever trick! All the functions that accepted several parameters so far have been curried functions."

It turns out that in these other languages, defining a function that takes multiple arguments is really syntactic sugar for defining a series of functions each taking a single argument, as currying is built-in to the language at a very low level. This is because, in these languages, "function" doesn't really mean the same thing that it does in JavaScript. It's more like a function in mathematics, where you pass in a value and get some output, as in ƒ(x) = x + 1.

Since every function in those other languages is curried, every function can be partially applied simply by passing less-than-all of its expected arguments. If you do that, you just get back the partially applied function.

In JavaScript, because function arguments are optional (defaulting to undefined if omitted), you can't partially apply them without first using special functions like partial or curry, because a function called with less-than-all of its expected arguments behaves as if undefined was passed for those missing arguments.

Final Words

Partial application is most commonly used to apply one or more arguments at the beginning of a function, as in the partial examples. Its utility can most readily be seen in the ECMAScript 5 bind function, which not only allows a function to not only have its context overridden, but its arguments to be partially applied at the beginning as well.

While the other variations or partial application are also useful, they are not nearly as prevalent. That being said, the ability to "lock in" function arguments allows you to use partial application to take any function that accepts arguments and make it more specialized and easier to use.

Even though I've written some handy utility functions here, I recommend looking at the well documented and popular wu.js and Functional Javascript libraries, as well as the popular Underscore.js library, as they support most, if not all the functionality you'll typically need to leverage partial application in your JavaScript.

 

About the Author

Ben Alman currently works at Bocoup as Director of Training and Pluginization, where he is responsible for the development of beginner and advanced JavaScript, jQuery and HTML5 training curricula. In addition to his training and client work at Bocoup, Ben writes articles and gives presentations advocating JavaScript and jQuery code organization techniques and best practices.

Ben has created and maintains a number of very popular open source JavaScript projects and jQuery plugins and is a frequent contributor to the open source jQuery, jQuery Mobile and Modernizr projects. As an avid photographer and funk bass player, Ben loves spending time taking photos and jamming in the greater Boston area.

Find Ben on: