Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The implementation in the submission is awfully inelegant, dated, and slow. I quickly wrote up a fast elegant ES2021 solution and tested it thoroughly. Below is the code, feel free to use it:

  const curry = fn => {
    return (...args) => {
      const curried = (...a) => {
        args = [...args]
        return args.push(...a) >= fn.length ? fn(...args) : curried
      }
      return curried()
    }
  }


I get the dated claim, but how is yours faster? It's nearly the same logic written with syntax sugar, no? The differences I see are that by using rest params instead of a deferred Array.prototype.concat, you've lifted the Array instance creation into all branches, where the original saves itself the trouble in the invariant case. And yours defines a variable whereas the original didn't. Is there some under the hood reason why this version would be more performant?

As for the inelegant claim, beauty is in the eye of the beholder. If performance is not a concern (as it won't be in most currying use-cases) I think the original version is much easier to read without years of js experience. It can be hard for newer or cross-discipline devs to understand mixed usage of rest params and spread operator since they look the same. In a scenario like this I think maintainability is a key ingredient of elegance.


The article's implementation grows the stack unnecessarily through recursively nested closures. A commenter pointed out a flaw in my code. This new implementation is even faster and more concise by doing away with the closures (other than the single inner closure):

  const curry = fn => {
    const curried = (...a) => a.length >= fn.length ? fn(...a) : curried.bind(undefined, ...a)
    return curried
  }
It uses bind which is an extremely powerful operator (a function that maps functions to functions)


Your implementation is broken for any function that has more than two arguments.

   const sum3 = curry(( a, b, c ) => a + b + c )
   const sum3_10 = sum3( 10 ) // ...
   const sum3_10_20 = sum3_10( 20 ) // ...
   sum3_10_20( 30 ) // 60
   sum3_10_20( 5 ) // 60

One of the points of currying is to be able to fork the partial application of the function at any point.


Very good catch, thank you. Here is my take on a better version that fixes the issue:

  const curry = fn => {
    const curried = (...a) => a.length >= fn.length ? fn(...a) : curried.bind(undefined, ...a)
    return curried
  }


The topic is not the implementation, but rather the concept. To make the topic accessible to as wide an audience as possible, including old C stogies, the traditional anonymous function is much easier to understand.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: