18.8.07

Currying in JavaScript

We can make our functions curried in JavaScript:
function curry(f, needed_len) {
    if (needed_len == undefined)
        needed_len = f.length;
        
    var curried = function() {
        var curried_args = arguments;
        if (curried_args.length >= needed_len) {
            return f.apply(this, arguments);
        }
        else {
            var curry_result_function = function() {
                var args = [];
                for(var i=0; i<curried_args.length; i++)
                    args[args.length] = curried_args[i];
                
                for(var i=0; i<arguments.length; i++)
                    args[args.length] = arguments[i];

                return f.apply(this, args);
            };
            return curry(curry_result_function, needed_len-curried_args.length);
        }
    };
    return curried;
}
And usage:
var curried_add = curry(function (a, b, c) {
    return a + b + c;
});

print(curried_add(1)(2)(3));
print(curried_add(1)()(2)()(3));
print(curried_add(1,2,3));
print(curried_add(1)(2,3));
print(curried_add(1,2)(3));
See also next pages for other implementations: http://www.dustindiaz.com/javascript-curry http://www.svendtofte.com/code/curried_javascript/
 
Note: after some more googling about currying in JavaScript, it's very interesting to see that http://www.coryhudson.com/blog/2007/03/10/javascript-currying-redux/ contains an almost identical implementation.

3 comments:

Anonymous said...

selam,

scope problemini asmak icin buna benzer bir fonksiyon yazmistim ben de, soyle bisey:

Function.prototype.curry = function(scope){
var fn = this;
var scope = scope||window;
var args = Array.prototype.slice.call(arguments,1);
return function(){
args.push.apply(args,Array.prototype.slice.call(arguments,0));
return fn.apply(scope,args);
};
};

herhangibiri said...

Evet, hem de bu gercek hayatta gercekten ise yarayacak bir fonksiyon, ozellikle fonksiyonel programlamada.

Bir ornek verelim de kullanimi kafamizda canlansin:

var str = "hello world";
var indices = [1,3,8,9];
str = map(str.charAt.curry(str), indices).join('');

herhangibiri said...

Kucuk bir hata buldum. Icteki fonksiyon distaki args nesnesini degistirdigi icin fonksiyon birden fazla cagrilamiyor. Sanirim kopya yanlislikla dista alinmis. Su sekilde calisiyor:

Function.prototype.curry = function(scope){
var fn = this;
var scope = scope||window;
var args = arguments;
return function(){
var argsCopy = Array.prototype.slice.call(args,1);
argsCopy.push.apply(argsCopy, arguments);
return fn.apply(scope, argsCopy);
};
};