简体   繁体   中英

Create a function with an undetermined number of successive calls

As part of a programming challenge, we are tasked with creating a function with an undetermined number of successive calls. As an example, let's say the function returns simply the sum of the provided arguments, it should work as follows :

sum(4)() // 4
sum(4)(5)() // 9
sum(4)(5)(9)() // 18
sum(4)(5)(9)(1)() // 19
// etc...

The problem is simplified by the allowed empty function call at the end as an indication of end of calls.

I have worked on a solution that does the job but using global variables inside the function itself :

var sum = function (a) {
    if (!sum.init) {
        sum.total = 0;
        sum.init = true;
    }
    if (!arguments.length) {
        sum.init = false;
        return sum.total;
    }
    sum.total += a;
    return sum;
};

This solution works but uses state, global variables and function object trickery which is not ideal. My question here is whether there is a way to solve the problem in a purely recursive way.

As a side note, I do not believe the problem can be solved if that last empty call () is not provided, but if I'm wrong please let me know.

Update

This issue has been answered in CodeReview : https://codereview.stackexchange.com/a/153999/129579

A neet solution that does not rely on global scope and is purely functional.

You can make use of closures to acheive what you want like this:

 function sum(value){ // the closure variable that will be accessible for all the _sum calls (initialised to 0 for every sum call). var result = 0; // the function that will be returned (sum will only get called once to initialize the result to 0. It's _sum which will be returned as much as possible) function _sum(a){ // if we passed a parameter, then add it to result and return a new _sum if(typeof a != "undefined"){ result += a; return _sum; } // if we didn't return the result else return result; } // of course after initializing result we need to call _sum that handle the actual summing and return whatever it returns (if value is defined, it will return another `_sum` if not it will return the value of result which will be 0 at first) from now on sum will have nothing to do with the rest of the calls (()()()... ) return _sum(value); } console.log("sum() = " + sum()); console.log("sum(7)() = " + sum(7)()); console.log("sum(5)(6)(7)() = " + sum(5)(6)(7)()); // will return 0 because we call sum again console.log("sum() = " + sum()); 

NOTE: That sum(1)(7)(3)()); will call, in this order:

  1. sum with the parameter 1 which will initialize result to 0 and call
  2. _sum with the same parameter 1 which will add it to result and return a new inctance of _sum which will be called so the following
  3. _sum get called with the parameter 7 , add it and return a new _sum so the new
  4. _sum get called with the parameter 3 , ... spawn another
  5. _sum that will have no parameter, therefore if(typeof a != "undefined") will fail and this _sum will return result instead.

The actual sum is only called once at the begining to do the initialization. It's, as I said, _sum that get chained after that all the way to the end.

Basically you could use an outer function sum for the initial call and a closure over the starting value a and an inner function fn , which is repeatingly returned and only exited if arguments.length is equal to zero.

If a value b is supplied, the variable a gets updated and the inner function fn gets returned.

 function sum(a) { return function fn(b) { if (!arguments.length) { return a; } a += b; return fn; }; } console.log(sum(1)()); console.log(sum(1)(2)()); console.log(sum(1)(2)(3)()); 

Edit for calling sum with no argument

 function sum(a) { return arguments.length ? function fn(b) { if (!arguments.length) { return a; } a += b; return fn; } : 0; } console.log(sum()); console.log(sum(1)()); console.log(sum(1)(2)()); console.log(sum(1)(2)(3)()); 

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