Partial application in JavaScript?

|

I’ve been learning more about functional programming lately, and after seeing a few interesting things on the interwebs, I decided to spend a little more time experimenting with partial application in JavaScript.

Now, I’m far from an expert in functional programming. What I’ve done here seems strange and exciting to me, and I have absolutely no idea how I would use it, or even what it’s called.

Is this partial application? Currying? Something else? (Vindaloo maybe?)

Note that an in-depth follow-up to this article titled Partial Application in JavaScript has been published, so check that out if you want to know the actual difference between partial application and currying!

The new

In the following code sample, invoking the curried function will always return a function until all arguments are satisfied, at which point the original function is invoked, returning its result. This means that all function arguments are required, which also allows the function to be called either like foo( 1, 2, 3 ) or foo( 1 )( 2 )( 3 ). This also means that if any argument is omitted, the original function is never invoked.

(Note that I’m not doing anything smart here with execution context)

function curry( orig_func ) {
  var ap = Array.prototype,
    args = arguments;

  function fn() {
    ap.push.apply( fn.args, arguments );

    return fn.args.length < orig_func.length
      ? fn
      : orig_func.apply( this, fn.args );
  };

  return function() {
    fn.args = ap.slice.call( args, 1 );
    return fn.apply( this, arguments );
  };
};

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 “knew”

Contrast that with this partial application approach (which I had incorrectly learned as “currying”). Invoking the partially applied function will always invoke the original function, and if any arguments are omitted, they are simply undefined. This allows for any number of arguments, but must be called like foo( 1, 2, 3 ) and not foo( 1 )( 2 )( 3 ).

function partial( orig_func ) {
  var aps = Array.prototype.slice,
    args = aps.call( arguments, 1 );

  return function() {
    return orig_func.apply( this, args.concat( aps.call( arguments ) ) );
  };
};

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

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

var n = partial( m );
n();                    // "2: undefined and undefined or undefined"
n( 'x' );               // "3: x and undefined or undefined"
n( 'x', 'y' );          // "4: x and y or undefined"
n( 'x', 'y', 'z' );     // "5: x and y or z"

var o = partial( m, 'x' );
o();                    // "6: x and undefined or undefined"
o( 'y' );               // "7: x and y or undefined"
o( 'y', 'z' );          // "8: x and y or z"

var p = partial( o, 'y' );
p();                    // "9: x and y or undefined"
p( 'z' );               // "10: x and y or z"

var q = partial( m, 'x', 'y' );
q();                    // "11: x and y or undefined"
q( 'z' );               // "12: x and y or z"

Questions, questions

I’d only ever seen partial application done like in the above partial function until recently, but a strange and confusing new world has been opened up to me here.. so, that being said, while the curry pattern is interesting, can I do anything useful with it?

If you’re curious, I have a gist you can fork as well.

Post A Comment

  • Any of these HTML tags may be used for style: a, b, i, br, p, strong, em, pre, code.
  • Multi-line JavaScript code should be wrapped in <pre class="brush:js"></pre>
    (supported syntax highlighting brushes: js, css, php, plain, bash, ruby, html, xml)
  • Use &lt; instead of < and &gt; instead of > in the examples themselves.