Skip to content

Instantly share code, notes, and snippets.

@barnabee
Last active January 3, 2016 14:19
Show Gist options
  • Save barnabee/8475352 to your computer and use it in GitHub Desktop.
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).
/**
** 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