Currying vs. Partial Application (2015)
datchley.name
datchley.name
The mental gymnastics required to read these functions and understand how they work is not negligible, it adds up. Especially when the function definition might be in another file from the one you are working on.
If any of my co-workers started actually using these techniques in our code, I would flag it. Usually, if you find yourself in a situation where it is beneficial to use techniques like this, it's a sign that you might be able to refactor your entire approach to make the design simpler.
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.)
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.
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.
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.
(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.
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.
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.
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:
```javascript
//Definitions
const filterUsers = (fieldName, value, users) => //Implementation
const sortUsersBy = (fieldName, users) => //Implementation
const takeUsers = (count, users) => //Implementation
//Without currying
UserService
.getUsers()
.then(users => filterUsers('active', true, users))
.then(users => sortUsersBy('age', users))
.then(users => takeUsers(3, users));
//If these methods were curried
UserService
.getUsers()
.then(filterUsers('active', true))
.then(sortUsersBy('age'))
.then(takeUsers(3));
```
Here is a video which explains proper uses of currying (and does it very well) [1]. Here is another article if your coworker start using functional programming and you want to stop them [2].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.
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.
+1 for including take/drop alongside map/reduse/filter
For instance, if you want to write something on the log, then loop and collect everything into a single array (using map) and then perform the side effect with a single command (which is a lot more performant in most cases).
For asynchronous side effects, create an array of promises using a map, and then run a Promise.all() on that array if you need to resolve all of them.
But again, if your experience is different or in your requirements, it is not possible to create a map/reduce/filter transoformation for side effects, then I'd love to hear about it.
A type system would detect these cases, but TypeScript and Flow don't have great support for curried functions. Typing them is very verbose.
In JS is even worse because of the weak typing, if by mistake you get a curried function instead of a value, JS will happily operate on it giving you things like "hellofunction () {}". When you realize that there is a problem, it would be hard to find the actual cause of the error.
I think this is the reason why dynamic functional languages such as Clojure don't use auto-currying. I a static typed world, like Haskell's this is not a problem at all.
Partial application on the other hand is very useful and practical in JS and other dynamic languages.
(a: number) => (b: number) => (c: number) => number
Sure, the parameter names and parentheses are a bit annoying, but I wouldn't call that "very verbose". Comparable concepts in C++ or Java would be a nightmare to type out. fn(1)(2)(3)
That's a big drawback for me. Libraries like Ramda allow one or more arguments per function call: fn(1, 2, 3) === fn(1, 2)(3) === fn(1)(2, 3)
That's what makes the verbosity unbearable, as each type of call needs its own type.Here's a gist of the type definitions I'm using: https://gist.github.com/noppa/c600cc43fd44e33768efe6c6eec4a9...
I think something similar might work in TS too.
Demo: https://goo.gl/w3aPsw
Function<Number, Function<Number, Function<Number, Number>>>
The same in Kotlin is actually okayish: (Number) -> (Number) -> (Number) -> NumberMaybe just a matter of perception but it looks verbose to me.
One reason for that is that my curried functions and their derivatives are usually named in a way that says exactly what they do.
const fn = a => b => c => {
return a + b + c;
};Imagine that you have a collection of items that you want to map over. Unfortunately the function you want to run takes 2 parameters instead of one. What if that function was really an object with one instance variable and a method that took 1 variable. So something like this (if it formats correctly):
class Person {
constructor(name) { this.name = name; }
is(adj) { console.log(this.name + ' is ' + adj); }
};
const mike = new Person('Mike');
['smart', 'handsome'].forEach((adj) => mike.is(adj));
I think most people from an object oriented background will find this easy to understand. Instead of making an object, though, we can just make a function that binds the value in conceptually the same way: const is = name => adj => {
console.log(name + " is " + adj);
}
const mikeIs = is('Mike');
['smart', 'handsome'].forEach(mikeIs);
Note: I don't have to make a lambda in the second case because I don't have to trip over `this` pointers, but I could if I wanted: ['smart', 'handsome'].forEach((adj) => mikeIs(adj));
Now, imagine that you have a bunch of curried functions, whose first argument is "name". Let's say "is", "jumps", "eats". You could write a function like this: const Person = (name) => {
return { is: is(name), jumps: jumps(name), eats: eats(name) };
};
This is literally a class (minus the crazy `this` pointers).This is one of the reasons, I really like Javascript. :-)
It's less easy when you need choice although one can use subfunctions .
In OOP you may have fluent interfaces, builder things but it's.. once again a lot for not much more.
Currying:
const f = x => y => x + y;
const g = f(1);
const sum = g(2);
Partial application: const f = (x, y) => x + y;
const g = _ => f(1, _);
const sum = g(2);
Most FP languages have nicer syntax for this.Currying takes a multi-argument function:
const f = (x, y, z) => x + y * z;
...and converts it to a function that takes a single argument, and returns a function taking the next argument, recursively: const f_curried = x => y => z => x + y * z;
const result = f_curried(1)(2)(3)
edit: maybe you were trying to convey that, in your first example, f is already a curried function? As a whole, the first example just looks like a partial-application demonstration.https://hughfdjackson.com/javascript/why-curry-helps/
Basically a curried function could be described nested series of partially applied functions(one argument per step).
On a side note to me this article is a bit on the heavy side when it comes to conveying the message. For one thing partial application should be explained first.
fun foo (x, y) = ...
And fun foo x y = ...
The language won't make the choice for them. f = function (x, y, z) { return [x, y, z]; };
g = partiallyApply(f, 1, 2);
With these definitions (and some suitable definition of `partialApply`): g(3) == f(1, 2, 3) == [1, 2, 3]
Note that `g` is a closure: a function with (references to) some values: the function `f`, and the data `x = 1` and `y = 2`. This closure will accept some argument (`z`) and return `f(x, y, z)`.Whilst currying is similar, it's like partially-applying everything, and doing so implicitly. For example, given `h = curry(f)` we get a new function: a closure with a reference to `f`.
If we say `i = h(1)`, we get a new closure which references `f` and `x = 1`. We can say `j = i(2)` to get another new closure which references `f`, `x = 1` and `y = 2`. All of the following hold:
j(3) == i(2, 3) == h(1, 2, 3) == f(1, 2, 3) == [1, 2, 3]
The important thing to notice is that in the case of partial-application, we only got one extra closure, and that happened when we explicitly called the `partialApply` function.In the case of currying, we only called the `curry` function once, to get `h`. Yet we subsequently get more and more closures, without any extra calls to the `curry` function: `h` can return new closures, and those closures can return new closures (like `i` and `j`) and so on.
In a language with strict (call by value) semantics like Javascript, this makes it hard to know when the "real" function (in our case `f`) will actually get called. This is important if `f` has side-effects, or involves some heavy computation. It also makes it harder to know when values will be garbage collected, due to the references inside these closures.
In the case of `partialApply`, only one closure is created, we know exactly where (at the point where `partialApply` is called), we know exactly what references will be captured (the arguments to `partialApply`) and we know exactly when the "real" function will get called (it will be called whenever the resulting closure is called).
To add to all of the other references in this thread, I also wrote my own a few years ago :)
Here's a basic implementation of currying in Javascript:
http://chriswarbo.net/blog/2012-02-20-currying_in_javascript...
Here's an "improvement" which also 'extends' the currying to return values:
http://chriswarbo.net/blog/2012-10-01-better_currying_in_jav...
For example, if we have the following:
a = curry(function(w, x) {
return function(y) {
return function(z) {
return w + x + y + z;
};
};
});
The "basic" version of `curry`, which is what I've seen most tutorials use, handles situations with "too few" arguments, by returning a closure: a(1)(2)(3)(4) == a(1, 2)(3)(4) == 1 + 2 + 3 + 4
In the "improved" version we also handle situations with "too many" arguments, by passing them as arguments to the return value (of course, this assumes we're returning functions, like above); which makes all of the following equivalent: a(1)(2)(3)(4) == a(1, 2)(3)(4)
== a(1)(2, 3)(4)
== a(1)(2)(3, 4)
== a(1, 2, 3)(4)
== a(1)(2, 3, 4)
== a(1, 2, 3, 4)
== 1 + 2 + 3 + 4
I've also written an equivalent for PHP, which goes more into the difference between partial application and currying:http://chriswarbo.net/blog/2014-02-21-partial_application___...
1) just define function as usual:
{def add
{lambda {:a :b :c}
{+ :a :b :c}
}} - > add
2) and use it: {add 1 2 3} -> 6
{{add 1} 2 3} -> 6
{{add 1 2} 3} -> 6
{{{add 1} 2} 3} -> 6
More to see in http://lambdaway.free.fr/workshop/?view=curryIn scheme we have the cut macro that all self-respecting implementations provide which guarantees you zero runtime overhead.
https://github.com/apple/swift-evolution/blob/master/proposa...
const curry = (fn,b) => (a) => fn(a,b);>There's no such thing as a right curry.
Haha, well there is now!
(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!)