Kindly read before you mark it as duplicate.
Im not asking for single curry call.
This functions multiplies, multiplication(4,4,4) //64
function multiplication(...args) {
return args.reduce((accum, val) => accum * val, 1)
}
But Im trying to achieve something else...
This same function should multiply its curry function parenthesis as well. e.g.
/*
which return the multiplication of three numbers.
The function can be called in any of the following forms:
multiply(2, 3)(4) => 24
multiply(2)(3, 4) => 24
multiply(2)(3)(4) => 24
multiply(2, 3, 4) => 24
*/
Kindly help.
After fiddling through a lot of code and reading some stack answers.
Finally I came up with. But it still doesnt satisfy this multiply(2)(3, 4) => 24
But works fine for rest of the cases
multiply(2,3,4)
multiply(2,3)(4)
multiply(2)(3)(4)
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);
};
}
}
while multiply(2)(3, 4) => 24 fail
Here's a generalized solution that works by repeatedly calling
bind
until enough parameters have been passed.Here's an answer similar to 4castle's that uses an additional rest parameter instead of
Function.prototype.bind
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.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
A very basical
curry
function can simply be implemented in JavaScript by using recursion as follows;However the above
curry
function is valid for functions which take definite number of arguments as we check thef.length
property which is defined and set at the function's definition. This is a normal functional behaviour since pure functions have a solid type bound with what it takes and what it gives. However JS is loosely typed, and not a pure functional language. It has the freedom of taking indefinitely many arguments.For indefinitely many arguments designated by the
rest
operator like(...a)
, thefunction.length
property is0
, enforcing us to use thearguments.length
to decide where to stop. In this case the curried function will give you a new function every single time for you to be able to enter new arguments up until you invoke it with no arguments finally to get the result.Your code
*** these two lines needed changing, you were almost there, so tantalisingly close in fact
ES6 makes it even cleaner
Here is a minimal curry function
High Level Explanation:
We want to construct a function, similar in spirit to Thrush (
f => a => f(a)
) but with variadic inputs. We want to partially apply input to this function, passing in the curried functionf
for the first parameter and the rest of the parameters needed until the appropriate arity for our function, given byf.length
is met or exceeded.Details:
Suppose we have some add function,
and we curry it
Here is what happens:
curry( add, 10 )
)args.length >= fn.length
isfalse
because we provided noargs
and the function has a length of 3Cool so we basically just get the same function back only now its bound to
curry
Next we call it thus
Now the following happens
We invoke the curried function.
curriedAdd
isadd
bound to it as the first parameter (afterthis
is set tonull
). It looks like thisconst inc = curry.bind(null,add)(0,1)
Here when we invoke curry,
add
is again the first parameter of the function.args
is now a list of two[0,1]
.args.length >= fn.length
is therefore false becauseadd.length
is 3 andargs.length
is two.curry
and bind that toadd
with two parameters[0,1]
spread into bind.inc
is notcurry.bind(null, add, 0, 1)
Cool, so now we call this
But
inc
is justcurry.bind(null,add,0,1)
Thus we called
curry
as before. This timeargs.length >= fn.length
istrue
and invokeadd
with all three parametersAn important part of this currying function is that the predicate be
args.length >= fn.length
and notargs.length === fn.length
because otherwise this would failThis may seem not important, however, in Javascript you might often do something like this
The
reduce
function passes in a few parameters... a number greater than our expected two (see footnotes). If our curry predicate didn't account for the greater than scenario, this code would break.Hope this was informative and educational. Enjoy!
Footnotes:
[1] - four to be exact, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce