Curried javascript sum function.

半腔热情 提交于 2021-02-04 16:28:11

问题


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!


回答1:


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.




回答2:


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.



来源:https://stackoverflow.com/questions/51958704/curried-javascript-sum-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!