A Practical Guide to Understanding Currying in JavaScript

Currying can be confusing. Let’s break it down

John Isom
John Isom
Feb 16 · 8 min read
A plate of food containing rice and curry
A plate of food containing rice and curry
I heard we’re talking about curry! 😋 — Photo by Dragne Marius on Unsplash

You’re a programmer who’s heard the term “curry” thrown around. Perhaps you’ve used partial application, and assumed they are the same thing. They’re not.

After reading this guide of understanding and enlightenment, you too will join the elite crowd of programmers that know the difference.


Accurate Currying Resource

All jokes and fun aside, I created this informational article as a reaction to all the terrible resources about currying in JavaScript. When I searched Google for “JavaScript curry,” I was appalled to see so much misinformation at the top of the results, namely from this article and this article.

Thankfully, there is some good information from javascript.info, Eric Elliot, and Adam Bene, yet even these good resources, except for javascript.info, are lacking in providing a reliable, general-purpose curry function.

It was with this horrible realization that I felt it was my duty to spread knowledge and awareness of this plight on programmers, and to provide a sane, accurate, and useful article.


Terms

With that said, before we jump into how to use currying, it’s crucial that we understand a few terms:

A language is said to support first-class functions if functions can be stored in variables and treated like regular objects, such as being passed into and returned by other functions.

A function that operates on other functions, either by accepting a function as input, returning a function as output, or both.

If a language does not have support for first-class functions, higher-order functions cannot exist in that language.

“A technique for implementing lexically scoped name binding in a language with first-class functions” — Wikipedia

This means that a function retains access to variables that were in scope when it was defined, even if the function is invoked in a scope without those variables.

“The process of fixing a number of arguments to a function, producing another function of smaller arity.” — Wikipedia

“Translating the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single argument.” — Wikipedia

The number of arguments a function takes.


Partial Application

Partial function application is a way of predefining some arguments to be applied first, before any subsequent arguments.

As a kind author in this Wikipedia article states:

“If you fix the first arguments of the function, you get a function of the remaining arguments.”

In JavaScript, an example of a function that partially applies arguments to a different function would look like this:

Note that this example doesn’t fully comply with the definition of partial application — It technically returns a variadic function, not a function of smaller arity.

In this code sample, the function partiallyApply takes a function func and some predefined arguments (argsToApply) as input, and returns a new function that wraps around func.

It’s in this wrapper function that the magic happens. When we create the anonymous wrapper function, a closure is created that retains access to the argsToApply variable.

This means that even when the wrapper function is returned and argsToApply is no longer in scope, the wrapper function retains access to argsToApply.

Here are some partially applied functions in action:

As we can see, in the case of concat5, we were able to predefine three of the five arguments and then later call the function with the remaining two, even though those predefined arguments are no longer in scope.

This is somewhat related to currying, which we will now explore.


Currying

Currying, though related to partial application, is not the same. To curry a function is to take a function and transform it into a sequence of functions, each taking one argument.

Here’s an example to illustrate:

There are a few interesting things going on here:

  1. The curry function takes a function as an argument and returns a new function.
  2. The returned function returns a function, and so on (this is the sequence of functions). If you were to inspect the return values for each of the curried function calls, you would see that they are all functions except for the very last return value, which brings us to this:
  3. The sequence of functions knows exactly when the last argument has been provided, and instead of returning a new function, it returns the final result.

As we can see, what sets currying apart from partial application is that currying returns a sequence of functions, compared to partial application’s single function, that knows when to finish and return the final result. This is because currying cares about the arity of a function.

If we remember the definition from the terms at the top of this article, arity is the number of arguments that a function takes. The curry function is able to detect when the required number of arguments have been passed in and act accordingly.

In JavaScript, we can get arity with the Function.prototype.length method, as seen below:

Even though the default parameters and rest parameter accept additional arguments, they don’t count towards the length of the function.

Notice that default parameters and the rest parameter don’t count towards the length of a function. In the context of currying, this makes sense. If the arguments are optional, how should we know when to return the final value instead of another function?

It’s also important to understand that argsAfterDefault has a length of 0, even though there are two “regular” parameters after the default parameters. When JavaScript calculates the length of a function, it only cares about the parameters before any default or rest parameters.

With that information, we now know a little bit more about how we want our curry function to behave. It should only return the final value after length arguments have been passed in — one at a time.

But what if we wanted to be able to pass in multiple at a time? Or not pass in any?

Consider this example:

Which implementation of the two curry functions do we want?

currySingleArgs strictly adheres to the definition of currying, but curryMultipleArgs is much more flexible. It really comes down to what you need for your specific situation, so let’s go ahead and dig into both.


Currying With Multiple Arguments

Let’s analyze the implementation of these two curry functions, starting with curryMultipleArgs:

This may look a little bit complex, but once we break it down, it becomes simpler. Let’s take a look at the function that is returned:

This is the curried version of our passed-in function.

What’s important to note here is that like partial application, this inner (or “wrapper”) function creates a closure that can still access the original passed-in function to get its length and eventually invoke it, even after the function is out of scope.

This function has two main parts:

  1. If the proper number of arguments has been passed in, invoke the original function with those arguments.
  2. Otherwise, return an anonymous function that will accept more arguments.

The first part is easier to understand. If we curry our function and then immediately invoke the curried function (curry) with the correct number of arguments, the original function (func) will be executed with those arguments.

The second part is where it gets interesting. Let’s analyze the anonymous function returned:

This function expression is wrapped in parentheses to be syntactically legal.

It’s a function that takes an arbitrary number of arguments, similar to the curried function, that when invoked with those arguments, calls the curried function.

Again, as with the partial application example and with curried, what’s important to note is that this anonymous function creates a closure that retains access to important references, namely the arguments passed into curried (args1) and curried itself.

Now, this is still a little bit unclear, but it will make a lot more sense when we step through how the program is executed step-by-step.

For this purpose, I’ve created a modified version of curryMultipleArgs that logs the value of args1 and args2 each time a function in the sequence of functions is executed:

When the anonymous function is executed, it immediately invokes “curried” as well.

This solution works by recursively calling curried in a roundabout way, with an anonymous function that accepts more arguments.

If this doesn’t make 100% sense, don’t worry. It’s OK and to be expected. Currying is a challenging topic and there’s a lot to wrap your head around.


Currying With a Single Argument

Let’s analyze the implementation for currySingleArgs:

This is slightly more complex than the other implementation because an outside array needs to be mutated to enforce only single arguments.

This implementation keeps track of all the arguments not by passing in arrays and concatenating with each function invocation, but by first initializing an array to hold all the arguments and then pushing a new argument to the array each time intermediate is called.

There are two main steps to this algorithm:

  1. On the first function call in the sequence of functions (when curried is called), initialize the arguments array and immediately invoke intermediate with the passed-in argument.
  2. Invoke func if the correct number of arguments has been eventually passed in. If the correct number of arguments have yet to be passed in, return intermediate to accept another argument.

Let’s take an inside-out approach to dissect this function, starting with the second step:

Being the meat of the logic, this is surprisingly simple.

There’s not much going on in this snapshot. This function accepts one argument, arg, and immediately pushes it to the args array.

After that, if the length of args is equal to the length of func, which is true only when the very last argument has been passed in, we invoke func with the arguments and return the result.

Otherwise, we return intermediate, allowing the program to keep chaining the function calls.

There’s not too much going on in the second step, so let’s take a close look at the first step. It can be a little bit confusing, but once we break it down, we can start to understand what exactly is happening:

It is very important to note that the array of arguments is initialized when we call the first function in the sequence of functions, not when we curry the function.

Take, for example, this naive currying solution that initializes the arguments array when the function is curried:

This is highly undesirable behavior.

To avoid this sort of behavior, we need to initialize args after we start calling the curried function.

One way to do that would be to wrap the whole thing in a function, which we name curried, and then invoke intermediate immediately after initializing args.

That way, any subsequent calls of intermediate will still be able to access the args array but any new calls of the curried function will have their own copy of args.

The only way to get an intermediate function to add another argument to args is for curried or another intermediate to return it, which forces us to chain our function calls and not rely on state:

Exactly the behavior we want.

As you can see, that’s all it takes to get the function to behave appropriately.

There are a lot of things going on here, but when we break down and analyze the solution in little pieces, it starts to make sense. Out of the many things happening, these are the most important to understand:

  1. By only accepting a single argument in the function signatures, we only deal with one argument at a time.
  2. That single argument, whether it is present or not, is pushed into our args array. This is the array that will be applied to func when it has the correct number of arguments.
  3. args is only initialized after we start invoking the curried function, not before. This gives us easy, predictable behavior. We accomplish this with an IIFE and somewhat heavy use of closures.

TL;DR

There are two implementations for a general curry function in JavaScript — one that can only take one argument at a time and one that can take any number of arguments at a time:

The two implementations of a general curry function.

This was a one-off article/guide. I hope you enjoyed it and found it helpful and interesting.

Better Programming

Advice for programmers.

Thanks to adamisom

John Isom

Written by

John Isom

John is a student at Launch School, busy mastering programming fundamentals and drinking coffee. Plain black and espresso, to be precise.

Better Programming

Advice for programmers.

More From Medium

More from Better Programming

More from Better Programming

More from Better Programming

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade