I have a test where I need to implement a high order function called sum in this case that fulfills the following requirements:
sum(result => {console.log("-> ", result)});// -> prints: -> 0
sum(1)(result => {console.log("-> ", result)});// -> prints: -> 1
sum(1)(2)(result => {console.log("-> ", result)});// -> prints: -> 3
sum(1)(2)(4)(result => {console.log("-> ", result)});// -> prints: -> 7
I did a function in order to get the infinite currying with recursion but I'm a little bit lost with the callback func.
let sum = a => !a ? 0 : b => b ? sum(a+b) : a
console.log(sum()) -> 0
console.log(sum(1)()) -> 1
console.log(sum(1)(2)()) -> 3
console.log(sum(1)(2)(4)()) -> 7
Use a closure to accumulate the sum. An inner function will call the callback with the sum when it detects the argument is a function. Otherwise it will return itself after adapting the sum:
function sum(arg) {
let total = 0;
function inner(arg) {
if (typeof arg === "function") {
arg(total);
} else {
total += arg;
return inner;
}
}
return inner(arg);
}
sum(result => {console.log("-> ", result)});// -> prints: -> 0
sum(1)(result => {console.log("-> ", result)});// -> prints: -> 1
sum(1)(2)(result => {console.log("-> ", result)});// -> prints: -> 3
sum(1)(2)(4)(result => {console.log("-> ", result)});// -> prints: -> 7
If it is not intended that the function maintains state, then you can use the this argument to pass on the total:
"use strict";
function sum(arg) {
function inner(arg) {
if (typeof arg === "function") {
arg(+this);
} else {
return inner.bind(this + arg);
}
}
return inner.call(0, arg);
}
sum(result => {console.log("-> ", result)});// -> prints: -> 0
sum(1)(result => {console.log("-> ", result)});// -> prints: -> 1
sum(1)(2)(result => {console.log("-> ", result)});// -> prints: -> 3
sum(1)(2)(4)(result => {console.log("-> ", result)});// -> prints: -> 7
const foo = sum(0);
foo(100)(console.log); // 100
foo(1)(console.log); // 1
Strict mode is advised here, but it will work in sloppy mode as well. In that case the this argument is boxed and unboxed again.
For simplicity, you can have a helper function that accepts two arguments. The first argument is a number. The second argument would be a number or function and based on the type it would do different things:
This way you can set up an continual chain of curried execution that gets terminated when a function is passed as an argument.
The actual sum() function can use the helper and initialise the start of the chain by setting the first argument to 0 - the neutral element for the addition operation:
const helper = total => arg => {
if (typeof arg === "function")
arg(total);
else if (typeof arg === "number")
return helper(total + arg);
else
throw new Error("invalid argument");
}
const sum = x =>
helper(0)(x);
sum(result => {console.log("-> ", result)});// -> prints: -> 0
sum(1)(result => {console.log("-> ", result)});// -> prints: -> 1
sum(1)(2)(result => {console.log("-> ", result)});// -> prints: -> 3
sum(1)(2)(4)(result => {console.log("-> ", result)});// -> prints: -> 7
For simplicity, the helper() function is curried.
Here is a more concise version:
sum() has been eta-reduced.const helper = total => arg =>
(typeof arg === "function")
? arg(total)
: helper(total + arg);
const sum = helper(0);
sum(result => {console.log("-> ", result)});// -> prints: -> 0
sum(1)(result => {console.log("-> ", result)});// -> prints: -> 1
sum(1)(2)(result => {console.log("-> ", result)});// -> prints: -> 3
sum(1)(2)(4)(result => {console.log("-> ", result)});// -> prints: -> 7