
Currying vs. Partial Application (2015) - tosh
http://www.datchley.name/currying-vs-partial-application/
======
phyller
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 conventions, anyone can start working
within seconds just by seeing the names of the functions and variables.

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.

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

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

------
tommikaikkonen
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've spent more hours than I'd like to admit
debugging these situations.

A type system would detect these cases, but TypeScript and Flow don't have
great support for curried functions. Typing them is very verbose.

~~~
skishore
The type of a curried function in Typescript is just something like:

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

~~~
tommikaikkonen
I agree, that doesn't look bad. However, this type definition forces you to
supply one argument per function call, which looks awful in JavaScript:

    
    
        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.

~~~
noppa
At least in Flow it's actually possible to properly type curried functions!

Here's a gist of the type definitions I'm using:
[https://gist.github.com/noppa/c600cc43fd44e33768efe6c6eec4a9...](https://gist.github.com/noppa/c600cc43fd44e33768efe6c6eec4a99a)

I think something similar might work in TS too.

Demo: [https://goo.gl/w3aPsw](https://goo.gl/w3aPsw)

------
tengbretson
I love how the new arrow syntax makes curried functions incredibly simple.

    
    
      const fn = a => b => c => {
        return a + b + c;
      };

~~~
jamesrom
appear incredibly simple*️

~~~
mikekchar
In what way is it not simple? It's hard to tell what you mean. The syntax is
actually a bit of a nightmare if you are writing a parser, but from the
perspective of a human reader, it shows you exactly what's going on under the
hood.

~~~
agumonkey
I think, as others above, parent meant to say "simple to write but not to
use".

~~~
mikekchar
Hmm... One way that I find easier to understand partial application is to
imagine that it's an object. All of the bound variables are like instance
variables in the object.

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

~~~
agumonkey
One major difference though, objects with multiple fields will require some
sophisticated logic to ensure correct order of initialization (depending on
the way constructors and setters are done). A partial function enforces some
order. You can accumulate safely information and get closer to a usable and
valid final piece of logic.

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.

------
TeMPOraL
Ok, it might be too early in the morning, but I still don't understand this. I
read that post, and the post by 'raganwald that the former linked to, and I
still don't see _any_ difference between currying and partial application. And
yet both posts seem to imply (without showing in any way) that the two
concepts are different. How come?

~~~
k__
Partial application is applied on call site, currying at definition.

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.

~~~
gmfawcett
That's not what currying is. You've just used partial application in two
different contexts.

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.

------
martyalain
{lambda talk} doesn't know closures but accepts de facto 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=curry](http://lambdaway.free.fr/workshop/?view=curry)

------
Johnny_Brahms
It surprises me to no end that programming languages that promote a functional
style with higher order functions do not support partial application as a part
of the standard library. It covers 95% of the uses of curried procedures and
gives you compiler warnings if you pass too few or too many arguments.

In scheme we have the cut macro that all self-respecting implementations
provide which guarantees you zero runtime overhead.

~~~
hellofunk
Here's an interesting post about the challenges of currying syntax in new
languages:

[https://github.com/apple/swift-
evolution/blob/master/proposa...](https://github.com/apple/swift-
evolution/blob/master/proposals/0002-remove-currying.md)

------
javajosh
I wrote my own curry using the pareto principle - this works for 80% of my use
cases (or more):

    
    
       const curry = (fn,b) => (a) => fn(a,b);

~~~
andreareina
Are you typically _not_ binding the first parameter? Why?

~~~
javajosh
It's a _right_ curry (which I can reapply for N args). It's just personal
preference, but I like to write "function templates" and then "particularize"
them with a curry, from right to left. The direction is unusual but it's a
personal choice and arbitrary.

~~~
gmfawcett
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](https://wiki.haskell.org/Section_of_an_infix_operator)

~~~
javajosh
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!

~~~
gmfawcett
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!)

------
agumonkey
I see the complaint over abusing currying, currying comes from a world where
things are reduced (npi) into binary and unary operations as much as possible.
I don't think FP/ML guys would like having wild arguments counts too.

------
amelius
Title should contain "in JavaScript".

