Skip to content

Instantly share code, notes, and snippets.

@alexpw
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexpw/61619aa5924514d1180a to your computer and use it in GitHub Desktop.
Save alexpw/61619aa5924514d1180a to your computer and use it in GitHub Desktop.
Example implementation of partial function application and currying in Javascript.
/**
* A partial function applicator.
*/
function partial() {
var fn = arguments[0];
var slice = Array.prototype.slice;
var partialArgs = slice.call(arguments, 1);
return function () {
var args = slice.apply(arguments);
return fn.apply(null, partialArgs.concat(args));
};
}
// Test of partial
function foo (a, b, c) {
return a + b + c;
}
partial(foo, 1)(2, 3);
// => 6
partial(foo, 1, 2)(3); // can be given any # of args
// => 6
/**
* "Proper" currying (1 arg fns).
*
* "...currying is the technique of translating the evaluation of a function that
* takes multiple arguments (or a tuple of arguments) into evaluating a sequence
* of functions, each with a single argument (partial application)." - wikipedia
*/
function curry(fn, numArgs) {
numArgs = numArgs || fn.length;
if (numArgs === 0) {
return fn;
}
var slice = Array.prototype.slice;
var currier = function (partialArgs) {
return function () {
var args = partialArgs.concat(slice.call(arguments, 0, 1));
if (args.length >= numArgs) {
return fn.apply(null, args.slice(0, numArgs));
} else {
return currier(args);
}
};
};
return currier([]);
}
var cfoo = curry(foo);
var cfoo1 = cfoo(1);
cfoo1(2)(3);
// => 6
// Reuse foo1 and branch from it.
cfoo1(10)(20);
// => 31
// Construction also accepts the # of arguments to support fns without explicit arglists.
curry(foo, 3)(1)(2)(3);
// => 6
/**
* "Greedy" currying. Instead of strictly using single arg fns, this version
* accepts any number of args, up until it satisfies it's requirement (argc).
*/
function gcurry(fn, numArgs) {
numArgs = numArgs || fn.length;
if (numArgs === 0) {
return fn;
}
var slice = Array.prototype.slice;
var currier = function (partialArgs) {
return function () {
var args = partialArgs.concat(slice.apply(arguments));
if (args.length >= numArgs) {
return fn.apply(null, args.slice(0, numArgs));
} else {
return currier(args);
}
};
};
return currier([]);
}
function foo (a, b, c, d) {
return a + b + c + d;
}
var gfoo = gcurry(foo);
var gfoo1 = gfoo(1);
gfoo1(2, 3)(4); // accepts more than 1 arg
// => 10
gfoo1(10, 20, 30); // branch from gfoo1
// => 61
// Construction also accepts the # of arguments
gcurry(foo, 4)(1)(2)(3)(4);
// => 10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment