Too much curry

One can easily apply too much or wrong type of curry.

Partial application and currying are great tools for programing in JavaScript. Recently several articles 1, 2 nicely explaining their use to remove complex code, leaving only concise and elegant code.

Using curry in programming is similar to using curry to flavor cooking. Not enough spice or too much can ruin the dish. Let us look at the ways things go wrong.

Not enough curry

Let us take parseInt as an example. If you forget its signature, you might get a nasty surprise

1
2
3
var _ = require('lodash');
var parseInteger = _.curry(parseInt);
parseInteger('7'); // [Function: bound]

The result is not number 7 as we might expect, but a cryptic function. If we try to inspect the function to get a sense what else is needed, we get no meaningful information

1
2
3
4
// how many arguments does curried function expect?
var parseInteger = _.curry(parseInt);
parseInteger.length; // 0
parseInteger('7').length; // 0

We do know that a curried function returns a function that expects either a single argument, or varied number of arguments. But it is weird that we get a function that expects zero arguments.

I am using lodash/curry in this instance. Let us try Ramda/curry.

1
2
3
4
var parseInteger = R.curry(parseInt);
parseInteger.length; // 2
parseInteger('7').length; // 1
parseInteger('7')(10); // 7

As you can see, Ramda library creates a new function with correct number of expected arguments.

Too much curry

What happens if we apply too many arguments? A typical javascript function just ignores extra arguments

1
parseInt('7', 10, 'foo', 'bar'); // 7

Let us apply too much curry to parseInt

1
2
3
var parseInteger = _.curry(parseInt);
parseInteger('7')(10)('foo')('bar');
// TypeError: number is not a function

The problem happens when we try to apply 'foo' to the number 7 returned by the second function. These errors can get very cryptic because the curried function returned by Lodash DOES NOT apply when invoked without arguments

1
console.log(parseInteger()()('7')(10));

Flavorless curry

Lodash curry function cannot work properly with functions that do not explicitly define its arguments, of course. The problem is that the curry fails silently, and the exception happens when one tries to call the function the second time

1
2
3
4
5
6
7
8
9
// sum two numbers
function sum() {
return arguments[0] + arguments[1];
};
console.log(sum(6, 10)); // 16
var sum2 = _.curry(sum);
// sum2(6)(10);
// ^
// TypeError: number is not a function

Missing curry

Just like I described before, when you design function's signature, please place the arguments less likely to change first (on the left), while leaving the arguments most likely to change last (on the right). This will make creating new functions easier. In case of parseInt, we might want to bind the radix argument, and then apply the new function to various strings without worrying about the weird results

1
2
3
var parseInteger = _.partialRight(parseInt, 10);
parseInteger('7'); // 7
parseInteger('-20'); // -20

Unfortunately, while Lodash includes partial and partialRight, it only includes left to right curry. We must create an adaptor function to reverse the arguments ourselves before currying it, or use a separate library lodash-contrib

Conclusion

Effective use of the curry function requires knowing the precise signatures of the functions to be curried.