Forked from cowboy/is-this-partial-application.js
Created
September 17, 2010 03:07
-
-
Save fearphage/583589 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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