Tuesday, July 28, 2009

Currying Curry functions in Javascript

Currying is a technique of transforming a function that takes multiple arguments into a partial application.

Here's an Example from Wikipedia:
f(x,y) = y / x.
g(y) = f(2,y) = y / 2
g(3) = 3 / 2.


At each partial application we end up with an executable function.

While reading about Currying in Functional programming for the rest of us, i came across this example:


pow(x,y) = x**y
square(x) = pow(x,2) = x**2


The idea of calling a function with partial arguments and getting back another function seemed interesting. I set out to implement it in, well Javascript, which is the only functional programming language i have ever used.


function pow(x,y){
return y == 0 ? 1 : x * pow(x,y-1);
}


square can be implemented in an imperative way by reusing pow:


function square(x){
return pow(x,2)
}


or by currying/partial application of pow:


var square = c(pow,2);
var cube = c(pow,3)
var sixteen = c(pow,2,4);


c is a function which allows currying, by remembering the curried args and returning a partial function which uses those arguments when calling the original function.


function c(f){
var cargs = Array.prototype.slice.call(arguments,1);
return function(){
Array.prototype.push.apply(arguments, cargs)
return f.apply(this, arguments);
}
}


The curried functions can be called like regular functions:


console.log(square(5));
console.log(sixteen())


Now if you notice, it works only if you want to partially apply args at the end. Consider another example, where you might want to apply curried args in the beginning:


function greet(message,name){
return message + ' ' + name;
}

function hello(name){
return greet('hello',name);
}

function goodbye(name){
return greet('goodbye',name);
}


Curried implementation of hello and goodbye would look like


var hello = c(greet,'hello');
var goodbye = c(greet,'goodbye');


c fn can only apply args at the end, so let's create another curry function which applies arguments at the beginning:


//curry args at the beginning
function _c(f){
var cargs = Array.prototype.slice.call(arguments,1);
return function(){
Array.prototype.push.apply(cargs, arguments)
return f.apply(this, cargs);
}
}

//curry args at the end
function c_(f){
var cargs = Array.prototype.slice.call(arguments,1);
return function(){
Array.prototype.push.apply(arguments, cargs)
return f.apply(this, arguments);
}
}

var square = c_(pow,2);
var cube = c_(pow,3)
var hello = _c(say,'hello');
var goodbye = _c(say,'goodbye');


c_ and _c is rather odd to denote the order of currying. Other than order, there is relatively no difference between the two functions. So let's refactor the curry functions with a higher order function:


function c(order){
return function(f){
var cargs = Array.prototype.slice.call(arguments,1);
return function(){
return f.apply(this, order(arguments,cargs));
}
}
}


c_ and _c can be obtained by currying c, a higher order function which takes order function as input and returns a curry function.


var _c = c(currybefore);
var c_ = c(curryafter);


currybefore and curryafter are functions which decide the order of currying:


function currybefore(args,curry_args){
return concat(curry_args,args);
}

function curryafter(args,curry_args){
return concat(args,curry_args);
}

function concat(list1,list2){
var result = [];
Array.prototype.push.apply(result,list1);
Array.prototype.push.apply(result,list2);
return result;
}


If you're tired after currying curry functions, go have some butter chicken curry:






* Array.prototype.push.apply(arguments, args) is a way to do pushall with push in javascript bcos apply splats array args
* Array.prototype.slice.call(arguments,1) is an idiom in javascript since arguments is not an actual array