1

In a recent interview, I was asked to write a function that adds numbers and accepts parameters like this:

add(1)(2)(3) // result is 6
add(1,2)(3,4)(5) // result is 15

The number of parameters is not fixed, and the arguments can be either passed in sets or individually.

How can I implement this add function?

6
  • 3
    So you want to implement currying a variadic function? I'd argue that's not possible, but there are many related questions on SO. E.g. stackoverflow.com/q/38638644/218196 Commented May 10, 2018 at 18:31
  • I'm sure you did some attempt in your presumed interview, why didn't you make any here? Also it's very close to this kata from codewars, you can look at solutions by opting out of the related kata. Also note that the description of your function is not proper - is the result returned after exactly three calls every time or what? Commented May 10, 2018 at 18:31
  • Possible duplicate of Variadic curried sum function (found via Google) Commented May 10, 2018 at 18:33
  • @ASDFGerte: I am not sure what you mean by 'opting out of the related kata'. I don't see any solution mentioned there, just the option of taking that challenge! Commented May 10, 2018 at 18:46
  • 4
    I know. What you want is simply not possible, if you really want to to curry a variadic function. Think about it: Currying means to return a function of lower arity if not all arguments are passed, eventually returning the result if all arguments have been passed. But since a variadic function accepts an unlimited number of arguments, you don't know when it is done. Hence the use of "hacks" in the other question. Commented May 10, 2018 at 18:53

5 Answers 5

3

Given your examples, the number of parameters is fixed in some ways.

As @ASDFGerte pointed out, your examples seem to return the result after three invocations. In this case a simple implementation without introducing terms like variadic and currying could be

function add(...args1){
  return function(...args2){
    return function(...args3){
      return args1.concat(args2).concat(args3).reduce((a,b)=>a+b)}}}
                
console.log(add(1)(2)(3))
console.log(add(1,2)(3,4)(5))

Every invocation accepts a variable number of parameters.

However it would be nice to generalize the construction of this nested functions structure and you can accomplish that with currying.

But if you want to allow an arbitrary number of invocations, when you should stop returning a new function and return the result? There is no way to know, and this is a simple, unaccurate and partial explanation to give you the idea of why they said you cannot accomplish what they asked you.

So the ultimate question is: is it possible that you misunderstood the question? Or maybe it was just a trick to test you

Edit

Another option would be to actually invoke the function when no arguments are passed in, change the call to add(1)(2)(3)()

Here an example recursive implementation

function sum (...args) {
  let s = args.reduce((a,b)=>a+b)

   return function (...x) {
     return x.length == 0 ? s : sum(s, ...x)
    };
}
console.log(sum(1,2)(2,3,4)(2)())

At every invocation computes the sum of current parameters and then return a new function that:

  • if is invoked without parameters just return the current sum
  • if other numbers are passed in, invokes recursively sum passing the actual sum and the new numbers
Sign up to request clarification or add additional context in comments.

3 Comments

We can check if the function argument is undefined and if it is, we stop returning a new function. So maybe a recursive function here which checks this condition should work?
it could but instead of add(1)(2)(3) you should do add(1)(2)(3)()
Ok. But I am not able to wrap my head around how this will work. Can you give a more detailed explanation?
1

I'm a bit late to the party, but something like this would work (a bit hacky though in my opinion):

const add = (a, ...restA) => {
  const fn = (b, ...restB) => {
    return add([a, ...restA].reduce((x, y) => x + y) + [b, ...restB].reduce((x, y) => x + y))
  };
  fn.valueOf = () => {
    return [a, ...restA].reduce((x, y) => x + y)
  };
  return fn;
}

This function returns a function with a value of the sum. The tests below are outputing the coerced values instead of the actual functions.

console.log(+add(1,2)(3,4)(5)); // 15
console.log(+add(1)) // 1
console.log(+add(1)(2)) // 3
console.log(+add(1)(2)(3)) // 6
console.log(+add(1)(2)(3)(4)) // 10

Since it's a currying function, it will always return another function so you can do something like this:

const addTwo = add(2);
console.log(+addTwo(5)); // 7

1 Comment

I think part of the exercise was to have to avoid manually casting the return value (+);
1

A function that multiply numbers and accepts multiple parameters but this code will only work for if have sequence of single arguments.

const curry = (n1) => {
    
  return function(n2){
    if(n2 === undefined) return n1;
    return curry(n1*n2);
  }
}

console.log(curry(2)(3)(4)());

/*
curry(2)
  func(3)
  
--- recursion --
    curry(2*3)
    
    curry(6)
      func(4)
      
------- recursion --
        curry(6*4)
        
        curry(24)
          func()
            return 24
*/

Comments

0

using reduce and spread it can be done as below

 function calc(...args1){
    
    return function (...args2){
    
    return function (...args3){
    
    let merge = [...args1, ...args2, ...args3]
    
    return merge.reduce((x ,y)=> x + y)  ;
    
    }
    }
    } 

let sum = calc(10)(1)(4);

console.log("sum",sum);

Comments

0

They probably wanted to know how comfortable you were with "javascript internals", such as how and when methods like Function#toString and Function#valueOf, Function#[Symbol.toPrimitive] are called under the hood.

const add = (...numbers) => {  
  const cadd = (...args) => add(...args, ...numbers);
  
  cadd[Symbol.toPrimitive] = () => numbers.reduce((a, b) => a + b);
  
  return cadd;
}

console.log(
  `add(1,2)(3,4)(5) =>`, add(1,2)(3,4)(5),
); // result is 15

console.log(
  `add(1,2) =>`, add(1,2),
); // result is 3

console.log(
  `add(1,2)(5)(1,2)(5)(1,2)(5)(1,2)(5) =>`, add(1,2)(5)(1,2)(5)(1,2)(5)(1,2)(5),
); // result is 32

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.