A Beginner’s Guide to Currying in Functional JavaScript

M. David Green
Share

Currying, or partial application, is one of the functional techniques that can sound confusing to people familiar with more traditional ways of writing JavaScript. But when applied properly, it can actually make your functional JavaScript more readable.

More Readable And More Flexible

One of the advantages touted for functional JavaScript is shorter, tighter code that gets right to the point in the fewest lines possible, and with less repetition. Sometimes this can come at the expense of readability; until you’re familiar with the way the functional programming works, code written in this way can be harder to read and understand.

If you’ve come across the term currying before, but never knew what it meant, you can be forgiven for thinking of it as some exotic, spicy technique that you didn’t need to bother about. But currying is actually a very simple concept, and it addresses some familiar problems when dealing with function arguments, while opening up a range of flexible options for the developer.

What Is Currying?

Briefly, currying is a way of constructing functions that allows partial application of a function’s arguments. What this means is that you can pass all of the arguments a function is expecting and get the result, or pass a subset of those arguments and get a function back that’s waiting for the rest of the arguments. It really is that simple.

Currying is elemental in languages such as Haskell and Scala, which are built around functional concepts. JavaScript has functional capabilities, but currying isn’t built in by default (at least not in current versions of the language). But we already know some functional tricks, and we can make currying work for us in JavaScript, too.

To give you a sense of how this could work, let’s create our first curried function in JavaScript, using familiar syntax to build up the currying functionality that we want. As an example, let’s imagine a function that greets somebody by name. We all know how to create a simple greet function that takes a name and a greeting, and logs the greeting with the name to the console:

var greet = function(greeting, name) {
  console.log(greeting + ", " + name);
};
greet("Hello", "Heidi"); //"Hello, Heidi"

This function requires both the name and the greeting to be passed as arguments in order to work properly. But we could rewrite this function using simple nested currying, so that the basic function only requires a greeting, and it returns another function that takes the name of the person we want to greet.

Our First Curry

var greetCurried = function(greeting) {
  return function(name) {
    console.log(greeting + ", " + name);
  };
};

This tiny adjustment to the way we wrote the function lets us create a new function for any type of greeting, and pass that new function the name of the person that we want to greet:

var greetHello = greetCurried("Hello");
greetHello("Heidi"); //"Hello, Heidi"
greetHello("Eddie"); //"Hello, Eddie"

We can also call the original curried function directly, just by passing each of the parameters in a separate set of parentheses, one right after the other:

greetCurried("Hi there")("Howard"); //"Hi there, Howard"

Why not try this out in your browser?

JS Bin on jsbin.com

Curry All the Things!

The cool thing is, now that we have learned how to modify our traditional function to use this approach for dealing with arguments, we can do this with as many arguments as we want:

var greetDeeplyCurried = function(greeting) {
  return function(separator) {
    return function(emphasis) {
      return function(name) {
        console.log(greeting + separator + name + emphasis);
      };
    };
  };
};

We have the same flexibility with four arguments as we have with two. No matter how far the nesting goes, we can create new custom functions to greet as many people as we choose in as many ways as suits our purposes:

var greetAwkwardly = greetDeeplyCurried("Hello")("...")("?");
greetAwkwardly("Heidi"); //"Hello...Heidi?"
greetAwkwardly("Eddie"); //"Hello...Eddie?"

What’s more, we can pass as many parameters as we like when creating custom variations on our original curried function, creating new functions that are able to take the appropriate number of additional parameters, each passed separately in its own set of parentheses:

var sayHello = greetDeeplyCurried("Hello")(", ");
sayHello(".")("Heidi"); //"Hello, Heidi."
sayHello(".")("Eddie"); //"Hello, Eddie."

And we can define subordinate variations just as easily:

var askHello = sayHello("?");
askHello("Heidi"); //"Hello, Heidi?"
askHello("Eddie"); //"Hello, Eddie?"

JS Bin on jsbin.com

Currying Traditional Functions

You can see how powerful this approach is, especially if you need to create a lot of very detailed custom functions. The only problem is the syntax. As you build these curried functions up, you need to keep nesting returned functions, and call them with new functions that require multiple sets of parentheses, each containing its own isolated argument. It can get messy.

To address that problem, one approach is to create a quick and dirty currying function that will take the name of an existing function that was written without all the nested returns. A currying function would need to pull out the list of arguments for that function, and use those to return a curried version of the original function:

var curryIt = function(uncurried) {
  var parameters = Array.prototype.slice.call(arguments, 1);
  return function() {
    return uncurried.apply(this, parameters.concat(
      Array.prototype.slice.call(arguments, 0)
    ));
  };
};

To use this, we pass it the name of a function that takes any number of arguments, along with as many of the arguments as we want to pre-populate. What we get back is a function that’s waiting for the remaining arguments:

var greeter = function(greeting, separator, emphasis, name) {
  console.log(greeting + separator + name + emphasis);
};
var greetHello = curryIt(greeter, "Hello", ", ", ".");
greetHello("Heidi"); //"Hello, Heidi."
greetHello("Eddie"); //"Hello, Eddie."

And just as before, we’re not limited in terms of the number of arguments we want to use when building derivative functions from our curried original function:

var greetGoodbye = curryIt(greeter, "Goodbye", ", ");
greetGoodbye(".", "Joe"); //"Goodbye, Joe."

JS Bin on jsbin.com

Getting Serious about Currying

Our little currying function may not handle all of the edge cases, such as missing or optional parameters, but it does a reasonable job as long as we stay strict about the syntax for passing arguments.

Some functional JavaScript libraries such as Ramda have more flexible currying functions that can break out the parameters required for a function, and allow you to pass them individually or in groups to create custom curried variations. If you want to use currying extensively, this is probably the way to go.

Regardless of how you choose to add currying to your programming, whether you just want to use nested parentheses or you prefer to include a more robust carrying function, coming up with a consistent naming convention for your curried functions will help make your code more readable. Each derived variation of a function should have a name that makes it clear how it behaves, and what arguments it’s expecting.

Argument Order

One thing that’s important to keep in mind when currying is the order of the arguments. Using the approach we’ve described, you obviously want the argument that you’re most likely to replace from one variation to the next to be the last argument passed to the original function.

Thinking ahead about argument order will make it easier to plan for currying, and apply it to your work. And considering the order of your arguments in terms of least to most likely to change is not a bad habit to get into anyway when designing functions.

Conclusion

Currying is an incredibly useful technique from functional JavaScript. It allows you to generate a library of small, easily configured functions that behave consistently, are quick to use, and that can be understood when reading your code. Adding currying to your coding practice will encourage the use of partially applied functions throughout your code, avoiding a lot of potential repetition, and may help get you into better habits about naming and dealing with function arguments.

If you enjoyed, this post, you might also like some of the others from the series: