6

I'm currently working on a programming problem in my personal time that asks that I make a javascript function that can be called in this manner.

add(1) // 1
add(1)(2) // 3
add(1)(2)(3); // 6
add(1)(2)(3)(4); // 10
add(1)(2)(3)(4)(5); // 15

What I'm having trouble figuring out is how to make it return a value on the very last call.

For example, in order for add(1)(2) to work, then add(1) has to return a function, but according to the instructions add(1) when called by itself will return 1.

I'm assuming one way you can overcome this is to figure out how many times in succession the add function is being called, but I cannot think of a way to achieve that. Does anyone have any hints that can point me in the right direction?

I've read these two articles (1, 2) on function currying and I understand them, but I'm not sure how to do currying when dealing with a variable number of arguments.

m0meni
  • 16,006
  • 16
  • 82
  • 141
  • 2
    So what did you try? Plenty examples of currying on the net. you return the function... – epascarello Nov 24 '15 at 19:10
  • 1
    @epascarello sorry if I didn't make it clear. I've read through this http://www.crockford.com/javascript/www_svendtofte_com/code/curried_javascript/index.html and this http://blog.carbonfive.com/2015/01/14/gettin-freaky-functional-wcurried-javascript/. As for my attempts they've been so off that I don't see the value in posting them. Also I don't have a problem with currying itself. I have a problem with the function taking a variable number of calls before it finally resolves. I don't know how to accommodate that. – m0meni Nov 24 '15 at 19:14
  • Btw, instead of using variadic functions, you should solve corresponding problems either with reduce and binary operator functions, or with a "semi-variadic" function, where the variadic arguments are passed as an array. This fits much better to the functional style. Variadic functions create more problems than they solve and should be avoided. –  Feb 11 '16 at 19:31

2 Answers2

4

It is impossible to curry a variadic function with an unknown number of arguments.

Where add is a variadic function, you could do something like

var add5 = curryN(add, 5);
add5(1)(2)(3)(4)(5); //=> 15

var add3 = curryN(add, 3);
add3(1)(2)(3); //=> 6

There's simply no avoiding this tho because a curried function will continue to return a function until the last argument is received, at which point the computation is run.


The only other option is to create some way to "short-circuit" the arguments and notify the function that the arguments are done being sent. That would require something like

var xadd = curryUntilUndefined(add);
xadd(1)(2)(3)(4)(5)(undefined); //=> 15

Here, the undefined signals the end of the variadic arguments. I don't really recommend this tho because of the other problems it can create for you. Not to mention, it's not particularly nice to look at.

Mulan
  • 129,518
  • 31
  • 228
  • 259
  • I was thinking the same thing, but I wanted to remain hopeful that it was due to my own lack of knowledge. I'm going to wait and see if someone has the miraculous solution, but otherwise I'll just accept yours. – m0meni Nov 24 '15 at 19:22
  • 1
    @AR7 I've done [another answer about curried functions](http://stackoverflow.com/a/30249365/633183) you can read, if you're interested. – Mulan Nov 24 '15 at 19:36
  • Seems like you didn't factor in javascript weirdness into your answer. Epascarello got it. – m0meni Nov 24 '15 at 19:43
  • 3
    Lol, that's not "javascript weirdness", you could define any function you want to terminate the computation. You still need to chain the `.valueOf()` call which doesn't fit your original question. So yes, it's still impossible. – Mulan Nov 24 '15 at 19:48
  • You're right, but what I was referring to was that it's not apparent that `valueOf()` gets called implicitly by something like `==` or `+` and makes it appear as if you never needed to call another function. – m0meni Nov 24 '15 at 19:51
  • 3
    I'm still yet to find a polite way to tell people they're addicted to sugar and that it's slowly killing them. – Mulan Nov 24 '15 at 19:57
2

It is not impossible, use valueOf().

function add(initNum) {
    var sum = initNum;
    var callback = function (num) {
        sum += num;
        return callback;
    };
    callback.valueOf = function () {
        return sum;
    };
    return callback;
};
console.log(add(1)(2)==3);            //true
console.log(add(1)(1)+1);             //3
console.log(add(1)(2)(3).valueOf());  //6
epascarello
  • 204,599
  • 20
  • 195
  • 236
  • Ah so this is one case where `==` gives you the answer you want and `===` doesn't. – m0meni Nov 24 '15 at 19:37
  • 2
    Yes it is still impossible *without* adding some special external call to terminate the sending of arguments. Or to say it more clearly, the API in the original question is impossible. – Mulan Nov 24 '15 at 19:52
  • 1
    @naomik It is a lot better than having to terminate the method outright or state how many iterations the currying needs. With valueOf anything that calls it internally will get the value without you the developer having to manually stop the chain. – epascarello Nov 24 '15 at 19:59
  • 3
    As already pointed out `===` breaks because types don't match. A huge loss, imo. I'll take explicit over implicit, thanks. – Mulan Nov 24 '15 at 20:07