1
\$\begingroup\$

I wanted to write an add function that implemented currying in JavaScript. I welcome criticism and suggestions for improvement.

function add(...args1) {
  if(!args1.length) {
    return sum(args1);
  }

  return (...args2) => {
    if(!args2.length) {
      return sum(args1.concat(args2));
    }

    return add.apply(null, args1.concat(args2));        
  };
}

function sum(arr) {
  return arr.reduce((p,c) => p+c,0);
}

console.assert(add(1,2)(3)(4)() === 10, '1+2+3+4 should be 10');
\$\endgroup\$
2

1 Answer 1

1
\$\begingroup\$

I'm unsure about this part:

if(!args1.length) {
  return sum(args1);
}

If the array's empty, you could just return zero - no need to call sum.

Secondly, you're doubling possible return types for add. You either get a new curried function, or you get a number.

This goes for the curried function as well, really, as it too will return either a sum or another function.

So either way, it's kinda tricky. Partial application/currying is kinda difficult if you have something like this, that you can "keep currying" forever.

Anyway, sticking to your current structure, it can be simplified somewhat. Notably, you don't have to create a new closure for each invocation. And you can get rid of the double !argsN.length checks and calls to sum:

function add(...initial) {
  let list = [];

  function adder(...values) {
    if(!values.length) {
      return list.reduce((sum, n) => sum + n, 0);
    }

    list.push(...values);
    return adder;
  }

  return adder(...initial);
}

Here, I've named the nested function, so it can return itself. After the initial call to add, the nested adder function is created, closes over the list array, and is invoked. It then either returns the sum or it returns itself. I.e. only one closure is created, and subsequent calls simply update the closed over list - or sums it.

adder also handles all the input checking etc.. The outer add function only exists to create and invoke it.

Also note that I renamed the argument arrays, as args1 and args2 really aren't too descriptive. And that the ...-splat works for both definition and invocation. And, lastly, since it only need to do a sum in 1 place, there's no need for a separate sum function.

\$\endgroup\$
2
  • \$\begingroup\$ Is it a common pattern to move control back and forth between two functions per the code in the question, or is this generally seen as an over-complication? \$\endgroup\$
    – 52d6c6af
    Commented Nov 17, 2015 at 14:38
  • \$\begingroup\$ @Ben I don't know if it's common enough to be called a "pattern", really. It's a function factory - just a (possibly) recursive one. In and of itself that's probably fine. I mostly changed the structure because it seemed simpler (and removed some repetition) in this particular case. In other cases, the original structure might make more sense \$\endgroup\$
    – Flambino
    Commented Nov 17, 2015 at 18:11

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.