Currying a function that takes infinite arguments

后端 未结 4 1574
北恋
北恋 2020-11-30 12:01

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

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


        
4条回答
  •  南笙
    南笙 (楼主)
    2020-11-30 12:32

    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.

提交回复
热议问题