2

I came across this interesting problem. Write a javascript function that returns sum of all the arguments passed to it, through multiple calls to that same function.

Here are the ways function can be called -

sum(1, 2, 3, 4);
sum(1, 2)(3, 4);
sum(1, 2)(3)(4);
sum(1, 2, 3)(4);
sum(1)(2, 3, 4);

All the calls above should work and return 10.

Here's what I have written so far, but it only works for first two function calls sum(1, 2, 3, 4) and sum(1, 2)(3, 4) and shits the bed for rest of it.

const arr = [];

function sum(...args) {
  if (args.length === 4) {
    return args.reduce((acc, curr) => {
      return (acc = acc + curr);
    }, 0);
  } else {
    arr.push(...args);
    return function(...args) {
      arr.push(...args);
      return sum(...arr);
    };
  }
}

Someone please help me, this is driving me nuts.

Thanks!

2
  • 1
    Allowing an arbitrary number of calls will be problematic because to make the chaining work, you need to return a function. But at some point you need to return a number with the final result. Commented Aug 22, 2018 at 1:30
  • This can only work with a specific number of arguments (in this case, 4). Commented Aug 22, 2018 at 1:36

2 Answers 2

6

You're pretty close. This is a perfect opportunity to use the .bind method to return a function that captures the first arguments if you haven't yet been given at least four.

So something like:

function sum(...args) {
  if (args.length >= 4) {
    return args.reduce((acc, curr) => {
      return (acc = acc + curr);
    }, 0);
  } else {
    // Bind the arguments you have to this function, and return it:
    return sum.bind(null, ...args)
  }
}

console.log(sum(1, 2, 3, 4));
console.log(sum(1, 2)(3, 4));
console.log(sum(1, 2)(3)(4));
console.log(sum(1, 2, 3)(4));
console.log(sum(1)(2, 3, 4));

Finally, I'd change the condition to check for >= 4 so that passing more than that doesn't result in a case where you'll curry forever.

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

4 Comments

That's right, or more accurately, it needs at least four.
Awesome! Thanks a lot! Quick question - how does this code retain arguments from previous call? Meaning, in case of sum(1,2)(3,4), how is the second function call getting arguments from the first function call? Apologies if this is a dumb question.
Sort of 'at least four', for example this is en error: sum(1, 2)(3, 4)(5, 6)
@PowPowPow That's where the .bind method comes in. Using .bind returns a new function, that when called, automatically precedes any arguments given to the new function with those you've passed to bind. Here are the docs for bind which explain it a little better.
1

Currying has a specific and defined behavior that doesn't mix well with variadic functions due to the undefined arity. However in your particular problem you specify an arity (for example, 4) so its possible to know when to return a result

const curryN = (n, f, ...xs) =>
  (...ys) =>
    ys.length >= n
      ? f (...xs, ...ys)
      : curryN (n - ys.length, f, ...xs, ...ys)
      
const add = (...numbers) =>
  numbers.reduce ((a, b) => a + b, 0)
  
const curryAdd =
  curryN (4, add)
  
console.log
  ( curryAdd (1) (2) (3) (4) // 10
  , curryAdd (1, 2) (3, 4)   // 10
  , curryAdd (1, 2, 3) (4)   // 10
  , curryAdd (1) (2, 3, 4)   // 10
  , curryAdd (1, 2, 3, 4)    // 10
  )

This is a fragile way to design your program though, and it's not even true currying, which only accepts 1 argument per application. Partial application is better because it produces a program with a much more reliable behavior

const partial = (f, ...xs) =>
  (...ys) =>
    f (...xs, ...ys)
    
const add = (...numbers) =>
  numbers.reduce ((a, b) => a + b, 0)
  
console.log
  ( partial (add, 1) (2, 3, 4) // 10
  , partial (add, 1, 2) (3, 4) // 10
  , partial (add, 1, 2, 3) (4) // 10
  )

Please read this related answer for additional insight.

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.