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 | var _ = require('lodash'); |
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 | // how many arguments does curried function expect? |
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 | var parseInteger = R.curry(parseInt); |
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 | var parseInteger = _.curry(parseInt); |
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 | // sum two numbers |
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 | var parseInteger = _.partialRight(parseInt, 10); |
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.