Introduction
In the previous part of this series, we have discussed closures. We have seen that they allow us to have functions return other functions that remember variables from their outer scope.
We have alluded to the fact that this will become useful as soon as we learn about partial application and currying. It is now time to delve into that.
Functional programming is all about composing functions and using generic functionality to create a more specialized one. This allows for less duplication and better readability (expressiveness) of code.
Partial application and currying are mechanisms that we can use for precisely that — to build specialized versions of functions on top of more generic variations.
Let’s see what they are, what they can be used for, and what’s the difference between these two concepts.
What are we talking about?
Remember higher-order functions? If not, you might want to go back and brush up on this topic. The techniques we will now discuss are just like higher-order functions but taken one step further.
Both partial application and currying are related to the ways we invoke functions — specifically, functions that have more than one parameter. They allow us to call those functions providing just some of the arguments, leaving the rest “for later”.
If this is confusing, or sounds like a “right that’s great but is this actually useful” kind of thing — hang on! We will get into that, but first, let’s take a look at examples to understand what it is that we’re talking about.
Partial application
Take a look at the getApiURL
function and the way we use it in a couple of places:
As you can see, there’s a quite obvious duplication of code going on here. getUserURL
, getOrderURL
, and getProductURL
all look somewhat similar, yet it's not quite obvious how to go about fixing that. Let's try:
That’s better. What we’ve done here is we extracted the common part of getUserURL
, getOrderURL
, and getProductURL
to the getResourceURL
function. If we think about it, the common part is about calling getApiURL
and passing http://localhost:3000
to it as the first argument.
This way, we have used a more generic getApiURL
function to create a more specialized getResourceURL
that is a wrapper. Its job is to provide getApiURL
with the first argument. Subsequent calls to getResourceURL
won't need to worry about the http://localhost:3000
part anymore – it's taken care of.
What we’ve done here is we’ve partially applied the getApiURL
function and created a "wrapper" getResourceURL
function around it.
To make it easier to use this pattern, we can use a higher-order utility function — partial
.
Take a moment to understand how partial
works.
See how we make use of closures and have argsToApply
still available by the time we call fn(...argsToApply, ...restArgs)
?
Taking it one step further, we could partially apply getResourceURL
to create getUserURL
and the other variations:
It’s starting to look nice!
Interestingly, there is a method that can be used just like partial
, and it's built into the language itself! You may have even used it. It's called bind
. It binds the function to not only its this
context (a more popular use case), but also to its first arguments. Let's take a look:
We can also partially apply a function providing it with more than one argument. In this example, it could mean introducing back the duplication we were trying to avoid in the first place — but for the sake of completeness, let’s see what this would look like:
Currying
Currying is a technique somewhat similar to partial application. It also allows us to “fix” some of the function’s parameters and return a function that “accepts” the rest.
The difference is that with currying, we provide arguments to a function one at a time.
Let’s see an example:
We can see here that getApiURLCurried
is a function that accepts just one argument. It then returns a function that accepts one more argument and does the same thing again.
To use the curried version of getApiURL
, we need to provide arguments one at a time: first apiHostname
, then resourceName
to the function it returns, and then finally resourceId
to a yet another inner function.
We can write curried functions more succinctly:
What’s interesting is that this form is not much more verbose than the original version.
There is a curry
utility provided in various libraries, that transforms a regular function into its curried equivalent. This utility function is a bit more complex than the partial
utility above, so we will not be covering its implementation details. Feel free to read the following sources to get a grasp on this:
- “Functional-Light JavaScript” by Kyle Simpson
- https://gist.github.com/spoike/697b34a14896df4f4b8bdd9d4a89bbb1
Here’s how you can use the curry
utility (here, from the ramda
library):
What’s the difference, again?
Both currying and partial application are patterns that allow us to call functions with some of their parameters, and provide the rest later.
The difference is that:
- Partial application is more or less a pattern of calling a function. You can partially apply any function.
Currying is more about a form of the function. To be able to use currying, you have to explicitly create a new function that is a curried version of the original one. - Let’s say a function
foo
acceptsN = 5
arguments. The partial application allows us to call it withK
arguments, and get back a function that acceptsN - K
arguments. For example, if we callfoo
withK = 2
arguments, we will get a function that accepts3
arguments. Currying, on the other hand, transformsfoo
into a nested chain of functions that accept1
argument each. Calling the curried version offoo
with the first argument will return a function that accepts the second argument, and returns a function that accepts the third argument, and so on... - As a consequence of the above, currying differs from partial application in what happens if you want to actually apply arguments one by one. With curried functions, you get that option out of the box — there’s no need to use
curry
utility on a given function more than once. If you want to apply one more argument (but not all of them) to a partially applied function, you need to partially apply it (usingpartial
) again.
But… why?
There are a couple of benefits of using partial application and currying in your application code.
They both help us create specialized versions of generic functions, thus removing duplication and making the code easier to read and compose.
What does it mean, though? Let’s look at some more specific examples illustrating the benefits.
Separation of concerns
One of them is that when using these techniques, you don’t necessarily have to know all of the arguments of a given function in one place of your codebase. In the getApiURL
example above, one example of that would be "slicing" the functionality across different layers of code, like so:
This example might be a bit contrived. The point I’m trying to make, however, is that it’s sometimes better to have different “layers” of your code be responsible for contributing specific parameters (that fit their abstraction level best) to a more complex piece of business logic.
Readability
Another benefit of using partial application and currying is that they can help us create more readable code. Compare the following versions of the same functionality — adding 5
to all elements of a collection:
To me, usage of the curried version of add
is by far the most elegant. What do you think?
Composability
Yet another benefit of all this functional mumbo-jumbo is easier function composition. This is especially true for currying — functions that accept just 1 argument are simply easier to compose than others.
We will be getting back to function composition in future parts of this series, but for now, let’s consider a simple example illustrating this specific aspect.
Composing functions is about passing a function’s result directly as an argument to another function, like so:
This example is pretty easy to follow, but that’s mainly because both increment
and double
are unary functions (i.e. they accept just 1 argument). We could use the same kind of composition with any curried function – because they are all unary as well.
Function composition is not that elegant with functions that accept more than 1 argument. That’s why curried functions are easier to reason about when composed with other functions.
Don’t worry if you don’t yet see how this all fits together. We will get back to this in the next parts.
Gotchas!
Ok, so if partial application and (especially) currying are so awesome, why don’t we use them all the time?
Well, we just might… :) In Haskell, for example, automatic currying is built into the fabric of the language itself (the Haskell reference is not a surprise here, is it?).
Obviously, there are some trade-offs to consider before going on a currying spree — other than your colleagues hating you for writing code they don’t understand.
They look kind of weird
If you’re not used to this style of programming, these techniques make either the definition or the call site of the function — or both, a bit awkward (“why would you need 5 pairs of parentheses here?!”).
Let’s compare the same piece of functionality written using different styles:
Arguably, the traditional version of the function looks more familiar. This is definitely a part of the learning curve, and all I can do is assure you: it gets better with time, and after some time you could be totally comfortable with the curried version of this functionality.
Ordering of arguments
This is not exactly a gotcha or a drawback, but definitely a limitation of both currying and partial application. They’re not a huge help if you want to call a function providing a portion of arguments — just not the first ones. In cases like this, you are still better off creating a custom wrapper function. Let’s see an example to make this clear:
If apiHostname
was the last parameter of the original getApiURL
function, we could have easily partially applied both resourceName
and resourceId
and get a function that would accept apiHostname
as its ("last") parameter. Because our intent doesn't closely fit the function signature, it's easier to just create a wrapper firstAPIUser
function.
Optional arguments
The other thing that’s not very intuitive to model with partial application and currying is optional parameters. Let’s consider the following example for currying, utilizing ES6’s default parameters syntax:
This is not a deal breaker because, as you can see, we can omit optional argument. It’s just not that elegant — even if we don’t need to pass some arguments, we still need to call a function. Just something to keep in mind.
Misleading error messages
Using currying might sometimes cause our programs to produce puzzling error messages in case something goes wrong. For example, let’s consider what happens if we forget to pass one of the arguments to a function.
As we can see, none of these scenarios is particularly better. The curried version blows up in our face with a not-so-descriptive error. The traditional version, however, continues to work — but maybe we’d actually prefer it to fail.
Again, something to keep in mind — using curried versions of functions might make them more “volatile”, but it may sometimes be a good thing.
Summary
In this article, we have learned what currying and partial application are — ways to increase code reusability and improve readability. We’ve also learned what the differences between the two are, and discovered their pros and cons.
With that, we add a couple more tools to your functional toolbox. Use them wisely to improve the readability of your code, but don’t forget about their limitations and drawbacks.
For a deeper dive into this subject, I recommend checking out the following:
- ”Hey Underscore, You’re Doing It Wrong!” by Brian Lonsdorf
- ”Functional-Light JavaScript” by Kyle Simpson
- This StackOverflow thread
See you in the next part!