3 ms·
> The mental gymnastics required to read these functions and understand how they work is not negligible, it adds up. While I agree with avoiding unnecessary co
by catnaroek 9y ago
> The mental gymnastics required to read these functions and understand how they work is not negligible, it adds up.
While I agree with avoiding unnecessary complication, partial application is no more complicated than object construction, something you've presumably been doing all your life. Every time you create an object whose only initialization logic is to set some internal variables, you are effectively partially applying a function whose arguments are (0) the constructor's arguments, and (1) a method selector. No mental gymnastics are required to understand this. (And this doesn't take into account open recursion, which makes object construction more complicated in ways that mere partial application isn't.)
- phyller 9y agoThat's a fair point, currying is the main offender here, partial application is just making a new function. With the right name it's not harder to understand. It does add complexity because you have layers of dependencies instead of everything being in the same place. The example is always some simple math, but usually functions are doing more, and when they get changed it isn't always obvious that the things that rely on partial applications of those functions are also affected. But that is true of anything that uses any dependencies, and a fundamental part of how we usually code. I prefer to reasonably minimize the number of dependencies, and then of course good tests protect you against this problem.
- deleted 9y ago[deleted]
- catnaroek 9y agoJust to be clear, I don't advocate currying everywhere. To me, the distinction between uncurried and curried functions lies primarily in the kinds of usage they suggest: (0) Uncurried functions are easier to pass as arguments to higher-order functions, because the author of the latter doesn't have to anticipate the arity of the former. (1) Curried functions are easier to partially apply. This is particularly useful for collection-traversing higher-order functions (map, filter, reduce, etc.). Furthermore, functions of three or more arguments can be “partially curried” in various ways, and the optimal choice ultimately depends on how you intend to use them. That being said, when in doubt, I tend to go for uncurried.
- marcosdumay 9y ago> The example is always some simple math, but usually functions are doing more On a language like Haskell, 90% of the time you see partial application it is something like `(+1)`, or `inClass isSpace`. That insistence on functions doing more is a very OOP thing. Functions that do too much do not compose well.
- emerongi 9y agoWell in Haskell it all makes sense, since you have other powerful tools (function composition and application, very large standard library of small functions, etc) that all compose into readable and nice code. If you just use currying randomly, it's going to create more headaches than solve. Ultimately you'd need to adopt something like Ramda in your project if you want to do this in your JS codebase, but even then I think Ramda-dependent code is way less readable than Haskell.
- cle 9y agoMy main objection with currying, and partial application as it's presented, is the implicit argument ordering that's imposed. I can't tell you the number of bugs I've seen that were caused by out-of-order arguments, even without currying/PA. I would never use currying like this in any non-trivial codebase, because it's very easy to make ordering mistakes, even in statically typed languages (if multiple arguments are the same type, your compiler may not protect you). I could accept using partial application if the arguments were required to be explicitly named and/or they all had distinct types. And at that point, the OOP line blurs even more.
- pera 9y agoBut isn't that true for functions in general? types may help you mitigating some of those bugs, but the real way to solve the issue is with good documentation: docstrings and well-named parameters is the way to go.
- cle 9y agoYes it is also true for functions in general, which is why you shouldn't have functions with lots of arguments (and especially lots of arguments with the same type). Currying exacerbates the problem because the function application doesn't occur in one place--not only do you have to get the ordering right, but the order in which the function is applied is scattered across your code and depends on the control flow. It's a neat trick, but most of the time it significantly reduces the clarity and maintainability of a program.