Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Currying with functions that take unlimited arguments

Tags:

javascript

Lets say i have the following add function that takes an unlimited number of arguments.

function add () {
    var total = 0;
    var args = Array.prototype.slice.call(arguments, 0);
    for (var i=0; i<args.length; i++) {
        total += arguments[i];
    }
    return total;
}

and the following curry function.

function curryFunction(orig_func) {
    var ap = Array.prototype;
    var args = arguments;
    function fn() {
        if (arguments.length != 0) {
            ap.push.apply(fn.args, arguments);
            return fn;
        } else {
            return orig_func.apply(this, fn.args);
        }
    };
    return function() {
        fn.args = ap.slice.call( args, 1 );
        return fn.apply( this, arguments );
    };
}

I then want to do something like:

var f = curryFunction(add);
var a = f(3)(4)(3);
var b = f(10)(3);
var result1 = a(); // returns 10
var result2 = b(); // returns 13 

However i always get 13 for both a() and b() i assume is because in line

fn.args = ap.slice.call(args, 1);

the existing array [3,4,3] is overwriting with []. Can someone please provide me with a hint on how to make this work? Thanks

like image 646
MrPeru Avatar asked Jan 08 '14 02:01

MrPeru


2 Answers

The problem is that fn is scoped to curryFunction and so is shared between a and b.

All you have to do is move the definition of fn into the anonymous return function. It's then created when you call f, and the problematic fn.args = line is only called once.

Proof: jsFiddle.

like image 112
bhamlin Avatar answered Nov 14 '22 21:11

bhamlin


Currying a function which takes indefinitely many arguments can be implemented as follows;

Lets say we have a function called addAll() which returns the sum of all provided arguments.

var addall = (...a) => a.reduce((p,c) => p + c);

And we have a curry function which takes a function and returns curried version ad infinitum up until the returned function is called with no arguments, only when the result of all previously provided arguments will be returned. OK here is the curry function.

 var curry = f => (...a) => a.length ? curry(f.bind(f,...a))
                                     : f();

Lets see it in action;

var addAll = (...a) => a.reduce((p,c) => p + c),
     curry = f => (...a) => a.length ? curry(f.bind(f,...a)) : f(),
   curried = curry(addAll),
    result = curried(10,11)(10)(37)(10,17,42)();
console.log(result);
result = curried("a","b")("c")("d")("e","f","g")();
console.log(result);
like image 26
Redu Avatar answered Nov 14 '22 21:11

Redu