If you’re confused about the difference, the following should clear it up for you, but first, let’s get some vocabulary out of the way:
Application: The process of applying a function to its arguments in order to produce a return value.
Partial Application: The process of applying a function to some of its arguments. The partially applied function gets returned for later use. In other words, a function that takes a function with multiple parameters and returns a function with fewer parameters. Partial application fixes (partially applies the function to) one or more arguments inside the returned function, and the returned function takes the remaining parameters as arguments in order to complete the function application.
Curry: A function that takes a function with multiple parameters as input and returns a function with exactly one parameter.
Why Does this Matter?
James Coglan gave a great talk that will help explain why you should care:
The features James talked about depend on function type uniformity. Functions have types. For instance, a function that takes a function and an array and returns an array (e.g. Function.prototype.map()):
(fn, array) -> array
- A partial application may or may not have a predictable return type.
- A curried function always returns another function with an arity of 1 until all of the arguments have been applied.
All the cool things James talks about rely on function type uniformity. For example he talks about how promises can help abstract your program logic’s dependence on time.
Promises do that because they lift whatever function you’re calling so that the return type is always uniform: All functions that return promises return the same type, which means that you can use them in standardized ways. James talks about lots of ways that promises help.
In this case, promises are containers which, like functors (a fancy word that basically means “something that can be mapped over”, e.g., an array. see also: applicative functors), can provide a standardized way to process the data inside the container regardless of the data’s type.
Warning: googling functional programming terms can be intimidating — it’s all a lot easier than academics make it sound.
By dealing with containers instead of the values inside of containers, you can create lots of generic functions that will work universally for anything that uses the container’s interface.
Like promises, curried functions return containers that all share the same interface. The returned functions are the containers in this case. You just keep calling the returned function until you’ve exhausted all the arguments and the final value gets returned.
In other words, a curried function is a function that can lift all of its arguments so that you can deal with those arguments in a standardized way.
The most common use-case for that kind of lifting is function composition, e.g.,
c(x) = f(g(x)). Function composition takes the return value of one function and feeds it in as an argument to another function. Since a function can only return one value, the function being applied to the return value must be unary.
Additionally, curried functions have a built-in iterator mechanism: A curried function will partially apply one argument at a time, never doing more work than it can do with a single argument. Calling the returned function has the effect of telling the function to apply the next step in the application.
For example, the curried function a(b)(c); doesn’t have to invoke the c application right away. It could be broken up like this:
const next = a(b);
doSomeStuff().then(() => next(c));
You should have a clearer understanding of the difference between partial application and curry, and why you’d want to curry your functions.
He spends most of his time in the San Francisco Bay Area with the most beautiful woman in the world.