Skip to content

Instantly share code, notes, and snippets.

@cowboy
Created September 16, 2010 20:26
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save cowboy/583102 to your computer and use it in GitHub Desktop.
Save cowboy/583102 to your computer and use it in GitHub Desktop.
Is this partial application? Currying? Something else? Vindaloo maybe?
// See my blog post:
// http://benalman.com/news/2010/09/partial-application-in-javascript/
// 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.
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"
// 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"
@cowboy
Copy link
Author

cowboy commented Sep 17, 2010

Somewhat inspired by the "bonus" question in Rebecca Murphey's gist and Snover's JSfiddle plus a whole lot of "subconscious percolation."

@cowboy
Copy link
Author

cowboy commented Sep 17, 2010

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment