Partial function application in JavaScript
Partial function application is a functional programming technique that allows you to transform functions that take N parameters into functions that take a subset of N parameters. For example, say you have this fairly useless function:
function add(a, b) {
return a + b;
}
Let's say that for some reason we need a version of "add
" that will always have the value 5 for the parameter "a
". One way we might do it is like so:
function add5(b) {
return add(5, b);
}
No black magic there. I was wondering if there might be some way that we can automate the process of generating functions with part of their arguments pre-bound. Here's what I came up with:
function partialBind(f, context) {
// arguments length MUST be greater than 2
if(arguments.length <= 2) {
// coz. what're you "partial binding" otherwise?!
return null;
}
// convert args to array excluding param "f" and "context"
var arrayProto = Array.prototype;
var params = arrayProto.slice.call(arguments, 2, arguments.length);
return function () {
// append params passed to this function to "params"
var args = params.slice(0, params.length);
if (arguments.length > 0) {
arrayProto.forEach.call(arguments, function (p) {
args.push(p);
});
}
// call the original function
return f.apply(context, args);
}
}
This function allows me to transform pretty much any function that takes at least 1 argument into a new function that takes a subset of the arguments. Transforming our "add
" function into a single parameter version with "a
" bound to 5 for instance, would now look like this:
var add5 = partialBind(add, null, 5);
var val = add5(10);
assert(val === 15);
Interestingly, "partialBind
" allows us to compose argument binding to multiple levels. If we wanted to take our "add5
" function and create another version that binds the second parameter to, say 20, then we can do this:
var add5_20 = partialBind(add5, null, 20);
var val = add5_20();
assert(val === 25);
Note that we are doing a partial bind of a function that is already a partial bind of another function. Turns out we can take this to as many levels as we want. The example given above is of course somewhat concocted because we could have achieved the same result with a single partial bind instead of doing it in two levels:
var add5_20 = partialBind(add, null, 5, 20);
var val = add5_20();
assert(val === 25);
All of this works because JavaScript supports closures. Pretty nifty don't you think?