简体   繁体   中英

How to implement infinite currying sum values with a callback function with result in javascript?

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:

  • when it is a function it will execute it and pass the first argument into it.
  • when it is a number, it will add the two arguments together and pass that as the first argument of the helper. Next time, the first argument will contain the new total.

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:

  • assumes that only number or function will be passed in.
  • The definition of 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM