Frage

I have function that look like this:

function curry(fn) {
    var args = [].slice.call(arguments, 1);
    return function() {
        return fn.call(this, args.concat([].slice.call(arguments)));
    };
}

I always thought that's how the function should look like and should work as:

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


curry(add, 1, 2)(3, 4);

but Wikipedia Article says that

it can be called as a chain of functions, each with a single argument

so the curry should look like this:

function curry(fn) {
    var args = [];
    return function curring() {
        args = args.concat([].slice.call(arguments));
        if (args.length >= fn.length) {
            return fn.apply(this, args);
        } else {
            return curring;
        }
    };
}

and be used as this:

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

curry(add)(1)(2)(3)(4);

Am I right?

War es hilfreich?

Lösung

Strictly speaking, currying converts a function with many arguments into a series of functions each with one single argument, as in your second curry function:

  • If you call all of them (in chain), you get the full application of the function, which produces the same result as the original function:
    curry(add)(1)(2)(3)(4) returns the same as add(1, 2, 3, 4), i.e.10

  • If you call only a subset, you get a partially applied function:

    1. addOne = curry(add)(1);
    2. addOneAndTwo = addOne(2);
    3. addOneAndTwo(3)(4) returns 10

In Javascript, currying is usually used as a synonym for partial application, as in your first curry function. Paraphrasing Prototype documentation:

curry curries (burns in) arguments to a function, returning a new function that when called with call the original passing in the curried arguments (along with any new ones).

For more detailed explanations, see What is the difference between currying and partial application.

Here is a working implementation of a true curry function in javascript by Evan Borden.

A few caveats:

  • In your first function, fn.call is wrong. You must use fn.apply, as the array that you pass as the second argument must be used as a list of arguments and call treats it as only one argument.

  • Your second function generates a curried function that can be called only 1 time, as each called curring instance modify the captured args array, which was initialized when curry was called.

    For example:

    1. addOne = curry(add)(1); defines addOne with its own args initialized to [1]

    2. addOne(2)(3)(4) returns 10 and modify args to [1, 2, 3, 4]

    3. addOne(2)(3)(4) (a second time) fails with addOne(...) is not a function,
      as addOne(2) tries to call add(1, 2, 3, 4, 2)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top