Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Currying a function that takes infinite arguments

Using ES5, how do you curry a function that takes infinite arguments.

function add(a, b, c) {
    return a + b + c;
}

The function above takes only three arguments but we want our curried version to be able to take infinite arguments.

Hence, of all the following test cases should pass:

var test = add(1);

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

Here is the solution that I came up with:

function add(a, b, c) {
    var args = Array.prototype.slice.call(arguments);

    return function () {
        var secondArgs = Array.prototype.slice.call(arguments);
        var totalArguments = secondArgs.concat(args);

        var sum = 0;

        for (i = 0; i < totalArguments.length; i++) {
            sum += totalArguments[0];
        }

        return sum;
    }
}

However, I have been told that it's not very “functional” in style.

like image 546
runtimeZero Avatar asked Jan 27 '16 13:01

runtimeZero


People also ask

What is infinite currying in JavaScript?

Now I'll introduce the concept of infinite currying. In Javascript, every object can implement this method valueOf that when the object is evaluated, the result would be the result of the method call. Also in Javascript, everything is an object (besides primitives) — including functions!

When would you use a currying function?

Currying is helpful when you have to frequently call a function with a fixed argument. Considering, for example, the following function: If we want to define the function error , warn , and info , for every type, we have two options. Currying provides a shorter, concise, and more readable solution.

What is currying function technique?

Currying is a function that takes one argument at a time and returns a new function expecting the next argument. It is a transformation of functions that translates a function from callable as f(a, b, c) into callable as f(a)(b)(c).

What is a currying function explain with an example?

Currying is when you break down a function that takes multiple arguments into a series of functions that each take only one argument. Here's an example in JavaScript: function add (a, b) { return a + b; } add(3, 4); // returns 7. This is a function that takes two arguments, a and b, and returns their sum.


1 Answers

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.

like image 112
Aadit M Shah Avatar answered Sep 18 '22 00:09

Aadit M Shah