How do you curry any javascript function of arbitrary arity?

前端 未结 5 1935
天命终不由人
天命终不由人 2020-12-19 04:19

Let\'s say I have some function:

function g(a,b,c){ return a + b + c }

And I\'d like to turn it into its \"curried\" form (in quotations si

相关标签:
5条回答
  • 2020-12-19 04:41

    I believe that you could simply use Function.prototype.bind. That gives you all the flexibility you need, wheter you want the result of the function right away or simply push another value into the arguments until you decide to execute.

    function sum() {
        return [].reduce.call(arguments, function (c, n) {
            return c + n;
        });
    }
    
    sum(1, 2); //3
    
    var sum2 = sum.bind(null, 1, 2);
    
    sum2(); //3
    
    var sum3 = sum2.bind(null, 3);
    
    sum3(); //6
    

    You could also use a helper function like:

    function curry(fn) {
        var c = curry.bind(this, fn = fn.bind.apply(fn, [this].concat([].slice.call(arguments, 1))));
    
        c.exec = fn;
    
        return c;
    }
    
    curry(sum, 1, 2)(3)(4, 5)(6, 7, 8).exec(); //36
    

    Also this is very flexible as you do not have to chain, you can re-use the same curried function.

    var sumOnePlus = curry(sum, 1);
    
    sumOnePlus.exec(2); //3;
    sumOnePlus.exec(3); //4;
    
    0 讨论(0)
  • 2020-12-19 04:45

    How about something like this:

    function makeLazy(fn) {
        var len = fn.length;
        var args = [];
        return function lazy() {
            args.push.apply(args, arguments);
            if (args.length < len) {
                return lazy;
            } else {
                return fn.apply(this, args);
            }
        }
    }
    
    function f(a,b,c) { return a + b + c; }
    
    var lazyF = makeLazy(f);
    lazyF(1)(2)(3); // 6
    
    var lazyF = makeLazy(f);
    lazyF(1,2)(3); // 6
    

    If you wanted a reusable function (I guess I can't tell exactly what you want), then this would work:

    function makeCurry(fn) {
        return function curry() {
            var args = [].slice.call(arguments);
            return function() {
                return fn.apply(this, args.concat.apply(args, arguments));
            };
        }
    }
    
    
    function f(a,b,c) { return a + b + c; }
    
    var curryF = makeCurry(f);
    var addOneTwoAnd = curryF(1,2);
    
    addOneTwoAnd(3); // 6
    addOneTwoAnd(6); // 9
    
    0 讨论(0)
  • 2020-12-19 04:45

    Please check the curry library.

    It can turn any function into curry no matter how many arguments are there.

    Example:

    > var curry = require('curry');
    undefined
    > var add = curry(function(a, b, c, d, e) { return a + b + c + d + e; });
    undefined
    > add(1)
    [Function]
    > add(1,2,3,4,5)
    15
    > add(1,2)(3,4)(5)
    15
    >
    
    0 讨论(0)
  • 2020-12-19 04:49

    Here's my attempt:

    function curry(fn, len) {
        if (typeof len != "number")
            len = fn.length; // getting arity from function
        return function curried() {
            var rlen = len - arguments.length;
            if (rlen <= 0) // then execute now
                return fn.apply(this, arguments);
            // else create curried, partially bound function:
            var bargs = [this]; // arguments for `bind`
            bargs.push.apply(bargs, arguments);
            return curry(fn.bind.apply(fn, bargs), rlen);
        };
    }
    

    This does not partial application (which is easy in JS with the bind method), but true functional currying. It works with any functions of arbitrary, but fixed arity. For variadic functions you would need a different execution trigger, maybe when no arguments are passed any more or an exec method like in @plalx' answer.

    0 讨论(0)
  • 2020-12-19 04:50

    The bind() method on function lets you bind the this inside the function as well as bind extra parameters. So, if you pass null for the this parameter, you can use bind() to curry the parameters into the function.

    function g(a,b,c){ return a + b + c }
    
    var g_1 = g.bind(null, 1);
    console.log(g_1(2, 3)); // Prints 6
    
    var g_1_2 = g.bind(null, 1, 2);
    console.log(g_1_2(3)); // Prints 6
    

    Check Javascript Function bind() for details and interactive examples of using bind() to bind parameters.

    0 讨论(0)
提交回复
热议问题