0

I trying to make next with closure:

function func(number) {
    var result = number;

    var res = function(num) {
        return result + num;
    };
    return res;
}

var result = func(2)(3)(4)(5)(3);
console.log(result); // 17

I need to receive 2 + 3 + 4 + 5 + 3 = 17 But I got an error: Uncaught TypeError: number is not a function

6
  • 9
    This hurts my brain.. You can either return a function or a number, not both.. Commented Aug 5, 2013 at 19:40
  • @MikeChristensen: Actually, you could return both by checking arguments.length. Commented Aug 5, 2013 at 19:43
  • 4
    @SLaks - Oh and put a () at the end of the chain? Yea, that'd be a clever way to annoy your co-workers. Commented Aug 5, 2013 at 19:44
  • 2
    Is there any reason why you can't use func(2, 3, 4, 5, 3) and rework your function to accommodate that setup? Although you have a simple example, it kinda makes more sense to head this way instead of continually invoking a function?... Commented Aug 5, 2013 at 19:48
  • 1
    possible duplicate of Javascript sum function Commented Aug 5, 2013 at 20:17

7 Answers 7

9

You somehow have to signalize the end of the chain, where you are going to return the result number instead of another function. You have the choice:

  • make it return a function for a fixed number of times - this is the only way to use the syntax like you have it, but it's boring. Look at @PaulS' answer for that. You might make the first invocation (func(n)) provide the number for how many arguments sum is curried.
  • return the result under certain circumstances, like when the function is called with no arguments (@PaulS' second implementation) or with a special value (null in @AmoghTalpallikar's answer).
  • create a method on the function object that returns the value. valueOf() is suited well because it will be invoked when the function is casted to a primitive value. See it in action:

    function func(x) {
        function ret(y) {
            return func(x+y);
        }
        ret.valueOf = function() {
            return x;
        };
        return ret;
    }
    
    func(2) // Function
    func(2).valueOf() // 2
    func(2)(3) // Function
    func(2)(3).valueOf() // 5
    func(2)(3)(4)(5)(3) // Function
    func(2)(3)(4)(5)(3)+0 // 17
    
Sign up to request clarification or add additional context in comments.

1 Comment

in my version though. if I call. f(4)(5) result becomes 9. nxt time f(1)(3)(null) will give 13 instead 4! :(
8

You're misusing your functions.

func(2) returns the res function.
Calling that function with (3) returns the number 5 (via return result + num).

5 is not a function, so (4) gives an error.

3 Comments

@user2056866 It's hard to see what practical use this would have so it's likely that this is homework. Are you trying to make a recursive function? You're a bit off if so.
Just for interesting, I trying to do this throught closure.
@user2056866: Try my answer. its not exactly how you want it but its almost the same.
3

Well, the (2)(3) part is correct. Calling func(2) is going to return you res, which is a function. But then, calling (3) is going to return you the result of res, which is a number. So the problem comes when you try to call (4).

For what you're trying to do, I don't see how Javascript would predict that you're at the end of the chain, and decide to return a number instead of a function. Maybe you could somehow return a function that has a "result" property using object properties, but mostly I'm just curious about why you're trying to do things this way. Obviously, for your specific example, the easiest way would just be adding the numbers together, but I'm guessing you're going a bit further with something.

2 Comments

Yes, it is just for interesting. But I still can`t understand how will be right.
Like I said, your entire method of calling it this way is weird. Would it be more acceptable to return an object with chain-callable functions? ie, func().addmore(3).addmore(5).addmore(7).getResult() ? This is normally what JQuery does.
0

If you want to keep invoking it, you need to keep returning a function until you want your answer. e.g. for 5 invocations

function func(number) {
    var result = number,
        iteration = 0,
        fn = function (num) {
            result += num;
            if (++iteration < 4) return fn;
            return result;
        };
    return fn;
}
func(2)(3)(4)(5)(3); // 17

You could also do something for more lengths that works like this

function func(number) {
    var result = number,
        fn = function () {
            var i;
            for (i = 0; i < arguments.length; ++i)
                result += arguments[i];
            if (i !== 0) return fn;
            return result;
        };
    return fn;
}
func(2)(3, 4, 5)(3)(); // 17

2 Comments

I havent downvoted your answer but it works only for exactly these many numbers of (). Its not dynamic.
@AmoghTalpallikar well I wrote it for OPs example, edited in one that works a little differently
0

I flagged this as a duplicate, but since this alternative is also missing from that question I'll add it here. If I understand correctly why you would think this is interesting (having an arbitrary function that is applied sequentially to a list of values, accumulating the result), you should also look into reduce:

function sum(a, b) {
    return a + b;
}

a = [2, 3, 4, 5, 3];

b = a.reduce(sum);

1 Comment

don't forget to initialize the reduce in case a is an empty array.
0

Another solution could be just calling the function without params in order to get the result but if you call it with params it adds to the sum.

function add() {
  var sum = 0;
  var closure = function() {
    sum = Array.prototype.slice.call(arguments).reduce(function(total, num) {
      return total + num;
    }, sum);
    return arguments.length ? closure : sum;
  };
  return closure.apply(null, arguments);
}

console.log(add(1, 2, 7)(5)(4)(2, 3)(3.14, 2.86)); //  function(){}
console.log(add(1, 2, 7)(5)(4)(2, 3)(3.14, 2.86)()); // 30;

Comments

0

We can make light work of it using a couple helper functions identity and sumk.

sumk uses a continuation to keep a stack of the pending add computations and unwinds the stack with 0 whenever the first () is called.

const identity = x => x

const sumk = (x,k) =>
  x === undefined ? k(0) : y => sumk(y, next => k(x + next))

const sum = x => sumk(x, identity)

console.log(sum())                // 0
console.log(sum(1)())             // 1
console.log(sum(1)(2)())          // 3
console.log(sum(1)(2)(3)())       // 6
console.log(sum(1)(2)(3)(4)())    // 10
console.log(sum(1)(2)(3)(4)(5)()) // 15

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.