6

I'm learning JavaScript, and I recently came across a practice problem that asked me to construct a function that could create outputs as follows:

var threeSum= sum(3);
threeSum //3
threeSum(4) //7
threeSum(4)(3) //10
threeSum(4)(3)(7) //17
threeSum(4)(3)(7)()(2) //19
threeSum - 2 //1
threeSum + 2 //5

I assume currying is involved, and I think I have a basic grasp of how currying works in the simple form of something like

a=>b=>c=> a+b+c

but I have no notion of how I would create a curried function able to handle an indeterminate number of inputs, nor how to make it such that it could result in a variable that can act as both a value and a function.

Any insight is appreciated! I just need a push in the right direction -- at this point I don't even know what I'm looking for anymore.

6
  • 1
    A function can't return a value which can act as a number and as a function simultaneously. But you can return a function which will be coerced to the desired number. Commented May 29, 2016 at 20:50
  • @Oriol: What's the difference between acting as a number and being coercible to a number? Commented May 29, 2016 at 21:55
  • Apologies for the duplicate post. To be fair, though, the original post's "JavaScript sum function" title is incredibly generic, and has little to do with the actual operation of the code in question, just its intended function. Commented May 29, 2016 at 22:21
  • @Eric I mean var obj = {valueOf:()=>42} will become 42 when coerced to a number, but obj !== 42, typeof obj !== 'number', etc. It won't be 42 itself. Commented May 29, 2016 at 22:51
  • 1
    @Eric codewars.com/kata/539a0e4d85e3425cb0000a88/train/javascript I'll put it in the question, as well. Commented Jun 3, 2016 at 19:00

2 Answers 2

6

The trick here is that you need to define valueOf, which allows javascript to interpret an object (like a function) as a value:

var valueAndCallable = function(x) {
    var res = function(a) { return a + x };
    res.valueOf = function() { return x; };
    return res;
};

var v = valueAndCallable(1)
console.log(v);      // function ... -
console.log(+v);     // 1 - calls .valueOf()
console.log(1 + v);  // 2 - calls .valueOf()
console.log(v(3));   // 4

For currying, you just want to make res() also return a valueAndCallable.

Sign up to request clarification or add additional context in comments.

7 Comments

this is just a dirty hack!
@Iven: But the question is asking for a dirty hack!
OK, now @Brad knows that this solution is kind of a hack and should be used with caution.
Brad asks for how to "hold a function and a [numeric] value in a variable". valueOf is the only way to achieve this. No unhacky solution can exist
For currying, you just want to make res() also return a valueAndCallable. that interesting part, can you impliment that?
|
1

As stated in the comments you can't define a variable that acts like a number and a function simultaneously.

To curry variadic functions you have to pass the arity explicitly:

const curryN = n => f => {
  let next = (m, acc) => x => m > 1 ? next(m - 1, acc.concat([x])) : f(...acc, x);
  return next(n, []);
};

const sum = (...args) => args.reduce((acc, x) => acc + x, 0);

sum(1, 2, 3, 4, 5); // 15
curryN(5)(sum)(1)(2)(3)(4)(5); // 15

let sum3 = curryN(3)(sum);
sum3(1)(2)(3); // 6

let sum5plusX = curryN(2)(sum)(5);
sum5plusX(6); // 11

I would recommend not to use variadic functions at all. Use Array.reduce instead. Here's an interesting tutorial about currying. It's an in-depth topic.

1 Comment

This is not true - you can do it without passing the arity

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.