Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save fearphage/583589 to your computer and use it in GitHub Desktop.

Select an option

Save fearphage/583589 to your computer and use it in GitHub Desktop.
// So what I'm doing here seems cool, but I'm not sure exactly what it should be
// called. Is this partial application? Currying? Something else? Vindaloo maybe?
//
// Either way, it's a pretty interesting pattern.. I wonder if it has any
// real-world application. Probably not.
//
// Invoking the partially applied 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 ).
//
// (Note that I'm not doing anything smart here with execution context)
(function(ap, name) {
var
slice = ap.slice
,push = ap.push
;
this[name] = function( orig_func ) {
var
target_length = orig_func.length
,args = slice.call( arguments, 1 );
;
return function fn() {
return (fn = function() {
push.apply( args, arguments );
return ( args.length < target_length ? fn : orig_func.apply( this, args.splice(0) ) );
}).apply(this, arguments);
};
};
})(Array.prototype, 'partial');
function a( x, y, z ) {
console.log( x + ' and ' + y + ' or ' + z );
};
a( 'x', 'y', 'z' ); // "x and y or z"
var b = partial( a );
b( 'u' )( 'v' )( 'w' ); // "u and v or w"
b( 'u', 'v', 'w' ); // "u and v or w"
b( 'u' )( 'v' ); // nothing logged, `a` not invoked
b( 'u', 'v' ); // nothing logged, `a` not invoked
b( 'u' ); // nothing logged, `a` not invoked
b(); // nothing logged, `a` not invoked
var c = partial( a, 'r' );
c( 's' )( 't' ); // "r and s or t"
c( 's', 't' ); // "r and s or t"
c( 's' ); // nothing logged, `a` not invoked
c(); // nothing logged, `a` not invoked
var d = partial( a, 'o', 'p' );
d( 'q' ); // "o and p or q"
d(); // nothing logged, `a` not invoked
// Contrast that with this "basic" currying approach. 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 curry( 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 f = curry( a );
f( 'u', 'v', 'w' ); // "u and v or w"
f( 'u', 'v' ); // "u and v or undefined"
f( 'u' ); // "u and undefined or undefined"
f(); // "undefined and undefined or undefined"
var g = curry( a, 'r' );
g( 's', 't' ); // "r and s or t"
g( 's' ); // "r and s or undefined"
g(); // "r and undefined or undefined"
var h = curry( a, 'o', 'p' );
h( 'q' ); // "o and p or q"
h(); // "o and p or undefined"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment