Currying a function that takes infinite arguments

Method 1: Using partial

A simple solution would be to use partial as follows:

Function.prototype.partial = function () {
    var args = Array.prototype.concat.apply([null], arguments);
    return Function.prototype.bind.apply(this, args);
};

var test = add.partial(1);

alert(test(2));     // 3
alert(test(2,3));   // 6
alert(test(4,5,6)); // 16

function add() {
    var sum = 0;
    var length = arguments.length;
    for (var i = 0; i < length; i++)
        sum += arguments[i];
    return sum;
}

Method 2: Single Level Currying

If you only want one level of currying then this is what I would do:

var test = add(1);

alert(test(2));     // 3
alert(test(2,3));   // 6
alert(test(4,5,6)); // 16

function add() {
    var runningTotal = 0;
    var length = arguments.length;
    for (var i = 0; i < length; i++)
        runningTotal += arguments[i];

    return function () {
        var sum = runningTotal;
        var length = arguments.length;
        for (var i = 0; i < length; i++)
            sum += arguments[i];
        return sum;
    };
}

Method 3: Infinite Level Currying

Now, here's a more general solution with infinite levels of currying:

var add = running(0);

var test = add(1);

alert(+test(2));     // 3
alert(+test(2,3));   // 6
alert(+test(4,5,6)); // 16

function running(total) {
    var summation = function () {
        var sum = total;
        var length = arguments.length;
        for (var i = 0; i < length; i++)
            sum += arguments[i];
        return running(sum);
    }

    summation.valueOf = function () {
        return total;
    };

    return summation;
}

A running total is the intermediate result of a summation. The running function returns another function which can be treated as a number (e.g. you can do 2 * running(21)). However, because it's also a function you can apply it (e.g. you can do running(21)(21)). It works because JavaScript uses the valueOf method to automatically coerce objects into primitives.

Furthermore, the function produced by running is recursively curried allowing you to apply it as many times to as many arguments as you wish.

var resultA = running(0);
var resultB = resultA(1,2);
var resultC = resultB(3,4,5);
var resultD = resultC(6,7,8,9);

alert(resultD + resultD(10)); // 100

function running(total) {
    var summation = function () {
        var sum = total;
        var length = arguments.length;
        for (var i = 0; i < length; i++)
            sum += arguments[i];
        return running(sum);
    }

    summation.valueOf = function () {
        return total;
    };

    return summation;
}

The only thing you need to be aware of is that sometimes you need to manually coerce the result of running into a number by either applying the unary plus operator to it or calling its valueOf method directly.


Part of the reason your add function is not very "functional" is because it is attempting to do more than just add up numbers passed to it. It would be confusing for other developers to look at your code, see an add function, and when they call it, get a function returned to them instead of the sum.

For example:

//Using your add function, I'm expecting 6
add(1,2,3) //Returns another function = confusing!

The functional approach

The functional approach would be to create a function that allows you to curry any other functions, and simplify your add function:

function curry(fn) {
    var args = Array.prototype.slice.call(arguments, 1);

    return function () {
        return fn.apply(this, args.concat(
                Array.prototype.slice.call(arguments, 0)
        ));
    }
}

function add() {
    var args = Array.prototype.slice.call(arguments);

    return args.reduce(function (previousValue, currentValue) {
        return previousValue + currentValue;
    });
}

Now, if you want to curry this function, you would just do:

var curry1 = curry(add, 1);
console.log(
        curry1(2), // Logs 3
        curry1(2, 3), // Logs 6
        curry1(4, 5, 6) // Logs 16
);

//You can do this with as many arguments as you want
var curry15 = curry(add, 1,2,3,4,5);
console.log(curry15(6,7,8,9)); // Logs 45

If I still want to add 1, 2, 3 up I can just do:

add(1,2,3) //Returns 6, AWESOME!

Continuing the functional approach

This code is now becoming reusable from everywhere.

You can use that curry function to make other curried function references without any additional hassle.

Sticking with the math theme, lets say we had a multiply function that multiplied all numbers passed to it:

function multiply() {
    var args = Array.prototype.slice.call(arguments);

    return args.reduce(function (previousValue, currentValue) {
        return previousValue * currentValue;
    });
}

multiply(2,4,8) // Returns 64

var curryMultiply2 = curry(multiply, 2);
curryMultiply2(4,8) // Returns 64

This functional currying approach allows you take that approach to any function, not just mathematical ones. Although the supplied curry function does not support all edge cases, it offers a functional, simple solution to your problem that can easily be built upon.