Reputation: 621
desired functionality:
mult(3);
//(x) => 3 * mult(x)
mult(3)(4);
//(x) => 3 * (4 * mult(x))
mult(3)(4)();
//12
attempt:
function mult(x){
if(x === undefined){
return 1;
}else{
return (y => x * mult(y));
}
}
result:
mult(3)
//y => x * mult(y)
//looks pretty good
mult(3)()
//3
//exactly what I want so far.
mult(3)(4)()
//Uncaught TypeError: mult(...)(...) is not a function
sure enough,
mult(3)(4)
//NaN
Yet mult(3)
looks good and typeof mult(3) === "function"
.
What gives? Can I not be this fancy in JS? Any why not?
Upvotes: 3
Views: 88
Reputation: 135257
Here's another way that uses a secondary parameter with a default value
x
is undefined, return the accumulator acc
x
is not undefined – return a new lambda that asks for the next input y
and recur using y
and acc * x
const mult = (x, acc = 1) =>
x === undefined
? acc
: y => mult (y, acc * x)
console.log (mult ()) // 1
console.log (mult (2) ()) // 2
console.log (mult (2) (3) ()) // 6
console.log (mult (2) (3) (4) ()) // 24
Personally, I would use a known (explicit) empty value rather than relying upon the implicit undefined
const Empty =
Symbol ()
const mult = (x = Empty, acc = 1) =>
x === Empty
? acc
: y => mult (y, acc * x)
console.log (mult ()) // 1
console.log (mult (2) ()) // 2
console.log (mult (2) (3) ()) // 6
console.log (mult (2) (3) (4) ()) // 24
Really though, mult
as it is defined above is a toy. A more practical implementation would use variadic interface instead of the weirder currying with ()
used to signal a return value
// fixed arity
const mult = (x, y) =>
x * y
// variadic interface
const multiply = (x = 1, ...xs) =>
xs.reduce (mult, x)
console.log (multiply ()) // 1
console.log (multiply (2)) // 2
console.log (multiply (2, 3)) // 6
console.log (multiply (2, 3, 4)) // 24
Upvotes: 2
Reputation: 85777
In
mult(3)(4)
mult(3)
yields y => 3 * mult(y)
.
Thus
(y => 3 * mult(y))(4)
becomes
3 * mult(4)
mult(4)
yields y => 4 * mult(y)
.
3 * (y => 4 * mult(y))
is nonsense because you're trying to multiply 3
by a function. This is why you're getting NaN
here, and NaN
can't itself be further applied.
Possible solution:
function mkmult(acc) {
return x =>
x === undefined
? acc
: mkmult(acc * x);
}
const mult = mkmult(1);
console.log(mult(3)());
console.log(mult(3)(4)());
console.log(mult(3)(4)(5)());
Upvotes: 2
Reputation:
If you think about it, the mult
should never be passed undefined
since it represents the "current" or left side of the multiplication. The inner function receiving y
is the one that should handle providing the result.
function mult(x){
return y => {
if (y === undefined) return x;
else return mult(x * y);
};
}
console.log(mult(3))
console.log(mult(3)())
console.log(mult(3)(4)())
Upvotes: 2