Using ES5, how do you curry a function that takes infinite arguments.
function add(a, b, c) { return a + b + c; }
The function above takes only three arguments but we want our curried version to be able to take infinite arguments.
Hence, of all the following test cases should pass:
var test = add(1); test(2); //should return 3 test(2,3); //should return 6 test(4,5,6); //should return 16
Here is the solution that I came up with:
function add(a, b, c) { var args = Array.prototype.slice.call(arguments); return function () { var secondArgs = Array.prototype.slice.call(arguments); var totalArguments = secondArgs.concat(args); var sum = 0; for (i = 0; i < totalArguments.length; i++) { sum += totalArguments[0]; } return sum; } }
However, I have been told that it’s not very “functional” in style.
Advertisement
Answer
Part of the reason your add
function is not very “functional” is because it is attempting to do more than just add up numbers passed to it. It would be confusing for other developers to look at your code, see an add
function, and when they call it, get a function returned to them instead of the sum.
For example:
//Using your add function, I'm expecting 6 add(1,2,3) //Returns another function = confusing!
The functional approach
The functional approach would be to create a function that allows you to curry any other functions, and simplify your add function
:
function curry(fn) { var args = Array.prototype.slice.call(arguments, 1); return function () { return fn.apply(this, args.concat( Array.prototype.slice.call(arguments, 0) )); } } function add() { var args = Array.prototype.slice.call(arguments); return args.reduce(function (previousValue, currentValue) { return previousValue + currentValue; }); }
Now, if you want to curry this function, you would just do:
var curry1 = curry(add, 1); console.log( curry1(2), // Logs 3 curry1(2, 3), // Logs 6 curry1(4, 5, 6) // Logs 16 ); //You can do this with as many arguments as you want var curry15 = curry(add, 1,2,3,4,5); console.log(curry15(6,7,8,9)); // Logs 45
If I still want to add 1, 2, 3
up I can just do:
add(1,2,3) //Returns 6, AWESOME!
Continuing the functional approach
This code is now becoming reusable from everywhere.
You can use that curry function to make other curried function references without any additional hassle.
Sticking with the math theme, lets say we had a multiply function that multiplied all numbers passed to it:
function multiply() { var args = Array.prototype.slice.call(arguments); return args.reduce(function (previousValue, currentValue) { return previousValue * currentValue; }); } multiply(2,4,8) // Returns 64 var curryMultiply2 = curry(multiply, 2); curryMultiply2(4,8) // Returns 64
This functional currying approach allows you take that approach to any function, not just mathematical ones. Although the supplied curry
function does not support all edge cases, it offers a functional, simple solution to your problem that can easily be built upon.