JS Curry function with Recursion
Here's a generalized solution that works by repeatedly calling bind
until enough parameters have been passed.
function curry(func, arity = func.length) { return function (...args) { if (args.length >= arity) { return func(...args); } else { return curry(func.bind(this, ...args), arity - args.length); } };}const multiply = curry((a, b, c) => a * b * c);console.log(multiply(2, 3)(4));console.log(multiply(2)(3, 4));console.log(multiply(2)(3)(4));console.log(multiply(2, 3, 4));
Your code
var multiply = function(...args) { if (args.length === 3) { return args[0] * args[1] * args[2]; } else { return function() { // *** args.push([].slice.call(arguments).pop()); // *** return multiply.apply(this, args); }; }}
*** these two lines needed changing, you were almost there, so tantalisingly close in fact
var multiply = function(...args) { if (args.length === 3) { return args[0] * args[1] * args[2]; } else { return function(...args2) { // *** args.push(...args2); // *** return multiply.apply(this, args); }; }}console.log(multiply(2, 3)(4))console.log(multiply(2)(3, 4))console.log(multiply(2)(3)(4))console.log(multiply(2, 3, 4))
ES6 makes it even cleaner
const multiply = (...args) => (args.length === 3) ? args[0] * args[1] * args[2] : (...args2) => multiply(...args.concat(args2));console.log(multiply(2, 3)(4))console.log(multiply(2)(3, 4))console.log(multiply(2)(3)(4))console.log(multiply(2, 3, 4))
Here's an answer similar to 4castle's that uses an additional rest parameter instead of Function.prototype.bind
const curry = (f, ...xs) => (...ys) => f.length > xs.length + ys.length ? curry (f, ...xs, ...ys) : f (...xs, ...ys) const multiply = curry ((a, b, c) => a * b * c)console.log (multiply (2, 3) (4)) // 24console.log (multiply (2) (3, 4)) // 24console.log (multiply (2) (3) (4)) // 24console.log (multiply (2, 3, 4)) // 24console.log (multiply () () () (2, 3, 4)) // 24
But relying upon the length
property is a function can be a problem when variadic functions come into play – Here, partial
is easier to understand, explicitly communicates when a function's arguments will not be supplied in entirety, and it works with variadic functions.
const multiply = (x, ...xs) => x === undefined ? 1 : x * multiply (...xs)const partial = (f, ...xs) => (...ys) => f (...xs, ...ys)console.log (partial (multiply) (2, 3, 4)) // 24console.log (partial (multiply, 2) (3, 4)) // 24console.log (partial (multiply, 2, 3) (4)) // 24console.log (partial (multiply, 2, 3, 4) ()) // 24console.log (multiply (2, 3, 4, 5, 6, 7)) // 5040console.log (partial (multiply, 2, 3, 4) (5, 6, 7)) // 5040console.log (partial (partial (multiply, 2, 3), 4, 5) (6, 7)) // 5040
Partial application is related to currying, but not exactly the same thing. I write about some of the differences in this answer and this one