Last active
January 3, 2016 14:19
-
-
Save barnabee/8475352 to your computer and use it in GitHub Desktop.
Example of a function that can wrap any function to make it support partial application. Relies on fun.length returning the number of expected arguments (e.g. all arguments included in function definition, not variable/implied from arguments object).
This file contains 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
/** | |
** Example for creating curryable functions | |
**/ | |
// Helper to splice together 2 arrays, like arr.concat() except elements in 'arr1' containig 'empty' | |
// are first "filled" with elements from arr2. | |
// e.g. splice(['a', undefined, 'b'], ['c', 'd', 'e']) --> ['a', 'c', 'b', 'd', 'e'] | |
var splice = function (arr1, arr2, empty) { | |
var arr2_ = Array.prototype.slice.call(arr2, 0), // so this works with arguments objects | |
result = Array.prototype.slice.call(arr1, 0); | |
for (var i = 0; i < result.length && arr2_.length > 0; ++i) { | |
if(result[i] === empty) result[i] = arr2_.shift(); | |
} | |
return result.concat(arr2_); | |
} | |
/// Wrap a function to allow partial application, optional specify argument value to mean argument | |
/// is being skipped (to allow currying from the right) - defaults to using undefined. | |
var curryable = function(fn, maybeArgs) { | |
var argValues = maybeArgs === undefined ? [] : maybeArgs, | |
capturedContext = this; | |
return function() { | |
// Update argument values with those supplied in this call (perform partial application) | |
newArgValues = splice(argValues, arguments, undefined); | |
// Check if sufficient arguments are provided then call the function with correct context if so, | |
// otherwise return wrapper again passing values that were supplied for partial application | |
if(newArgValues.length === fn.length && newArgValues.indexOf(undefined) === -1) { | |
return fn.apply(capturedContext, newArgValues); | |
} | |
else { | |
return curryable(fn, newArgValues); | |
} | |
}; | |
}; | |
// Export curryable (to test as node module) | |
if (module) module.exports = curryable; | |
// Example of use | |
if (require && require.main === module) { | |
var __ = undefined | |
var adder = curryable( function(a, b, c) { | |
return (a + b) * c; | |
}); | |
var add1 = adder(1); | |
var add2 = adder(__, 2); | |
console.log(adder(10, 20, 1)); | |
console.log(add1(100, 1)); | |
console.log(add2(200, 1)); | |
var double1 = add1(__, 2); | |
console.log(double1(50)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment