thor
thor

Reputation: 22530

Ramda curry/uncurry issue with ES6 default parameter syntax

In the following example, I couldn't get Ramda.js uncurry functions to work with ES6 arrow functions when a default parameter is present:

const tt = (x) => y => x + y;
const tt1 = (x = 5) => y => x + y;
const uncurry = R.uncurryN(2);

console.log( uncurry(tt)(1,2)  );
console.log( uncurry(tt1)(1,2) );

The two functions tt and tt1 should be the same except for a default parameter. But The output is different (babel-node 6.24.1):

3
6

It seems that the default syntax is taken as an assignment with the uncurrying.

Am I missing something here? Is this intended or a bug?


Just to clarify:

Without the curry/uncurry, both functions (with or without the default value), behaves the same way when parameters are fully supplied. Both tt(1)(2) andtt1(1)(2) evaluates to 3. Why should the behavior be different after changing calling convention?

By the way, I was following some react/redux examples (es6 how to use default parameters that go before non-default parameters?) and test if it's possible to convert some of the react function calls to Ramda style. The issue discussed here is apparently an obstacle.

Upvotes: 3

Views: 1156

Answers (1)

Scott Sauyet
Scott Sauyet

Reputation: 50807

While this isn't precisely intended, it's hard to see a really useful solution to this.

The fault is in this line in the implementation:

      endIdx = currentDepth === depth ? arguments.length : idx + value.length;

If it were replaced with

      endIdx = currentDepth === depth ? arguments.length : idx + 1;

your two functions would work the same. That would then break this sort of usage:

const tt2 = (x, y) => (z) => x + y + z;
uncurry(tt2)(1, 2, 3); //=> NaN

(With the current implementation, this properly returns 6.)

That might not be all that important. It seems a strange thing to try to use uncurryN for a function that is not fully curried.

But overall, I don't know that this helps. Default parameters can be difficult to work with. A parameter with a default does not contribute to the function's length:

length is a property of a function object, and indicates how many arguments the function expects, i.e. the number of formal parameters. This number excludes the rest parameter and only includes parameters before the first one with a default value. -- MDN

The default values are not available for use by decorator functions, so something like uncurryN would lose the default values. And it makes it awkward to work with any parameters after one with a default value.

You could still do this, of course:

((x, y) => tt1(x)(y))(1, 2); //=> 3
((x, y) => tt1(x)(y))(undefined, 2); //=> 7

And an undefined passed to uncurry(tt1) would work as well. But passing an explicit undefined feels a bit odd.

Feel free to raise an issue for Ramda to discuss this.

You can play with these ideas on the Ramda REPL.

Upvotes: 1

Related Questions