JavaScript nested number adder function with an unknown number of chained function calls

208 Views Asked by At

I have a nested function that should be able to handle chained function calls, but the number of calls is unknown. The function has to add up numbers until we call it without parameters, in which case it should return the result of all the numbers that were passed as arguments in the chain call.

Description:

Write the makeAdder function, which will return the adder function. The adder function should work on the following pattern: adder(2)(3)(4)(1)(2)(3)(4)() === 19. It will sum all the numbers passed in the parameters until it encounters a call without parameters. When calling without parameters, it will return the result and clear the amount.

Example:

const adder = makeAdder();
adder() === 0
adder(4)(5)() === 9
adder() === 0
adder(5)(5)(5)
adder(4)
adder() === 19
adder() === 0

How can I write this function without knowing how many nested functions I am going to need beforehand?

function makeInfinityAdder() {

  return function adder(a = 0) {
    return (b) => {
      if (b) {
        adder(a + b)
      } else {
        return a + b;
      }
    };
  }
}

I tried this but I get 'adder(...)(...) is not a function'.

3

There are 3 best solutions below

6
KooiInc On BEST ANSWER

A factory function: the return value returns a new Function instance (of itself) or the current value based on the availability of a (valid numeric) argument.

See also

const addAll = (a = 0) => b => +b >= 0 ? addAll(a + b) : a;

let add = addAll();
console.log(`add(8)(9)(10)(15)() => ${add(8)(9)(10)(15)()}`);
console.log(`add(0)(8)(9)(10)(15)('stop') => ${add(0)(8)(9)(10)(15)('stop')}`);

// reassign if you want to continue later (see comments):
add = add(5)(5)(5);
add = add(4);
console.log(`reassignment (add = add(...)) => ${add()}`);

// if you don't want to reassign
const addAll2 = (a = 0) => {
  const fn = b => +b >= 0 ? (a += b, fn) : a;
  return fn;
};

let add2 = addAll2();
add2(5)(5)(5);
add2(4);
console.log(`add2 (multiple add2(...)) => ${add2()}`);

0
001 On

Here's what I came up with.

const makeAdder = () => {
    // Store the results across calls
    let result = 0;
    // The adder function
    const adder = (a = null) => {
        if (a == null) {
            const retval = result;
            result = 0;
            return retval;
        }
        else {
            result += a;
            return adder;
        }
    };
    return adder;
};

const adder = makeAdder();
console.log(adder());
console.log(adder(4)(5)());
console.log(adder());
adder(5)(5)(5);
adder(4);
console.log(adder());
console.log(adder());

0
Scott Sauyet On

While you can do it like this:

const makeAdder = () => ((t = 0, tmp = t, fn = (n) => (
  (t += n || 0),
  (n == undefined) ? ((tmp = t), (t = 0), tmp) : fn
)) => fn) ()

const adder = makeAdder();
console .log (adder ())           //=> 0
console .log (adder (4) (5) ())   //=> 9 
console .log (adder ())           //=> 0
console .log (adder (5) (5) (5))  //=> <function>
console .log (adder (4))          //=> <function>
console .log (adder ())           //=> 19
.as-console-wrapper {max-height: 100% !important; top: 0}

the inherent statefulness of such a function bothers me, especially when we're presumably trying to treat it like a factory function.

I would rather make an adder function that always yields back stateless functions which have the current sum baked in. That gives us a cleaner interface:

const adder = (n, t = 0) => 
  n == undefined ? t : (x) => adder (x, t + n)

console .log (adder ())           //=> 0
console .log (adder (4) (5) ())   //=> 9 
console .log (adder ())           //=> 0
const foo = adder (5) (5) (5)     //=> <function> (15)
const bar = foo (4)               //=> <function> (19)
console .log (bar ())             //=> 19

console .log (bar (1) ())         //=> 20
console .log (foo (20) ())        //=> 35
console .log (foo (12) ())        //=> 27
.as-console-wrapper {max-height: 100% !important; top: 0}

I find this much cleaner. But notice that there is a difference in how we use adder. First, it is not a factory function. It is a plain function that returns either a number or another function. Second, the functions it generates as you keep calling it are new functions, and they are stateless. The separate calls to foo with different values don't accumulate a sum between them.