Live data from Hacker News

Currying vs. Partial Application (2015)

datchley.name

41–50 of 54 posts

Re: Currying vs. Partial Application (2015)

#41
post #22

This is interesting, but just because you can do something doesn't mean you should, particularly in JavaScript. As soon as I started working on a large project with a team of devs my coding style began to change dramatically. Simplicity and readability become paramount. Minimize how much a dev needs to understand about the code before they can work on it, and how long it takes them to read it. With the right coding c…

> 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 partial…

My 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.

Re: Currying vs. Partial Application (2015)

#42

Currying in JavaScript is really nice if you can remember the arities of each curried function you're using. If you forget to call up to the last argument, you'll be passing a curried function instead of the expected value, and it can throw an error really far away from the bug. And instead of normal data to inspect at the error site to point you to the bad call, you'll only have a generic function name to look at. I…

Not only do you need to remember the arity, but the order as well, which is IMO worse (at least a type system can protect you from arity mistakes). If your function is not commutative for adjacent arguments of the same type, you're skipping through a minefield if you rely on currying.

Re: Currying vs. Partial Application (2015)

#43
post #42

Currying in JavaScript is really nice if you can remember the arities of each curried function you're using. If you forget to call up to the last argument, you'll be passing a curried function instead of the expected value, and it can throw an error really far away from the bug. And instead of normal data to inspect at the error site to point you to the bad call, you'll only have a generic function name to look at. I…

Not only do you need to remember the arity, but the order as well, which is IMO worse (at least a type system can protect you from arity mistakes). If your function is not commutative for adjacent arguments of the same type, you're skipping through a minefield if you rely on currying.

How is that any different from having to remember the argument order in normal function application?

Re: Currying vs. Partial Application (2015)

#44
post #42

Earlier quoted context omitted.

Not only do you need to remember the arity, but the order as well, which is IMO worse (at least a type system can protect you from arity mistakes). If your function is not commutative for adjacent arguments of the same type, you're skipping through a minefield if you rely on currying.

How is that any different from having to remember the argument order in normal function application?

Conceptually it's not that different. Practically, it's pretty different because you're effectively fragmenting a single function application across your codebase, making it harder to reason about and more likely to make ordering mistakes.

Re: Currying vs. Partial Application (2015)

#45
post #41

Earlier quoted context omitted.

> 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 partial…

My 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…

But 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.

Re: Currying vs. Partial Application (2015)

#46
post #28

Earlier quoted context omitted.

That'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 re…

> 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.

Well 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.

Re: Currying vs. Partial Application (2015)

#47
post #45
post #41

Earlier quoted context omitted.

My 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…

But 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.

Yes 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.

Re: Currying vs. Partial Application (2015)

#48
post #22

This is interesting, but just because you can do something doesn't mean you should, particularly in JavaScript. As soon as I started working on a large project with a team of devs my coding style began to change dramatically. Simplicity and readability become paramount. Minimize how much a dev needs to understand about the code before they can work on it, and how long it takes them to read it. With the right coding c…

With all due respect, I don't think you understand the purpose of currying and partial application. In your defense, the article merely explains what currying is, but does not explain why you need it. For instance while writing functional Javascript code, I never curry my methods, instead I use helper methods from functional libraries such as lodash or Ramda to curry. Where currying is useful is in cases like this: `…

Ok +1 for the super cynical article about how to stop functional programming :D

But obviously that's a cheap shot for an example, no one would have a problem with the function he starts out with, he doesn't need to have a side effect. The problem is when you are in an OOP app, with an OOP language, doing things that really lend themselves to OOP, and trying to shoehorn everything into FP because it's How Smart People Program. And the result is not less complicated, but way more complicated.

I've got these opinions because I've already been that guy saying please stop writing this complicated stuff that I don't understand. I'm not an idiot, we've just got a huge amount of work to do, and the time it takes for me to piece all this together and find the bugs is not worth it, especially because it is going to be just as opaque to you when you have to come back to it in a few months.

I'm not saying FP isn't the best thing ever and someday I'm sure it's going to take over the world, and given all the time in the world and a clean sheet I might choose it myself right now. But I care about working as a team more than the finer points of coding philosophy, and making simple, effective, and on time code. I'll choose practical over principle if I have to, though I'd prefer to have both. And if that means FP, then let's do it, but so far my experience has been the opposite.

For context, we are talking about JavaScript apps, and my comments are limited to front end apps using OOP frameworks and fetching data in the form of objects from a REST API.

Re: Currying vs. Partial Application (2015)

#49

Earlier quoted context omitted.

That's a right section [1] (i.e., a partial application in the second argument). There's no such thing as a right curry. [1] https://wiki.haskell.org/Section_of_an_infix_operator

Haskell "sections" seem to be very specific to infix operators, so they don't apply. >There's no such thing as a right curry. Haha, well there is now!

It's not Haskell-specific terminology, I've seen it used in other functional language contexts (some Scheme libraries, etc.). But I admit I couldn't find another reference to link to the term, at least not with a quick Web search. :)

(It's still not currying, though! If you're providing partial arguments to an existing function, that's partial application; if you're transforming a multi-arg function into a single-arg, function-returning function, then it's currying!)

Re: Currying vs. Partial Application (2015)

#50
post #48

Earlier quoted context omitted.

With all due respect, I don't think you understand the purpose of currying and partial application. In your defense, the article merely explains what currying is, but does not explain why you need it. For instance while writing functional Javascript code, I never curry my methods, instead I use helper methods from functional libraries such as lodash or Ramda to curry. Where currying is useful is in cases like this: `…

Ok +1 for the super cynical article about how to stop functional programming :D But obviously that's a cheap shot for an example, no one would have a problem with the function he starts out with, he doesn't need to have a side effect. The problem is when you are in an OOP app, with an OOP language, doing things that really lend themselves to OOP, and trying to shoehorn everything into FP because it's How Smart People…

I used to be the guy who would say that people need to stop writing code which others can't understand, but then I migrated to, "why am I working at a company where I need to lower the bar so much that making changes in a code you understand well takes ages".

I joined that school when I used FP for my own project (I use Elm, and RamdaJS+JS) and found how amazingly handling bugs and complicated logic became. This clearly came with a higher barrier to entry for other people to understand my code (but this cost only needs to be paid once, I look at other people's functional code and I got no problem understanding it btw).

I understand large companies where logic needs to be written so simply so that anyone can understand it (Python philosophy "Code is read a lot more times than it is written"), but they don't end up with fewer bugs, it's just a LOT LOT BIGGER codebase, with 5 million for loops, doing 1500 things in one for loop.

In fact, before I fully went to FP side, I started writing my JS code without using for loops or forEach. Even this simple change of writing code using map/reduce/filter/drop/reject/take etc made code lot simpler to maintain, reason with, and eliminate bugs.

Post reply on HN