DailyJS
Published in

DailyJS

Functional JS #5: Partial Application, Currying

This is a fifth part of the “Functional JS” series. Go to the previous part here, or the beginning of the series here.

Photo by Isis França on Unsplash

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:

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:

  1. 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.
  2. Let’s say a function foo accepts N = 5 arguments. The partial application allows us to call it with K arguments, and get back a function that accepts N - K arguments. For example, if we call foo with K = 2 arguments, we will get a function that accepts 3 arguments. Currying, on the other hand, transforms foo into a nested chain of functions that accept 1 argument each. Calling the curried version of foo 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...
  3. 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 (using partial) 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:

See you in the next part!

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store