How to Curry Functions in JavaScript



This JavaScript language feature can help tidy up your code and will give you a new appreciation of how functions work.


Curried functions can help make your JavaScript code more readable and expressive. The currying technique is ideal when you want to break down complex logic into smaller, self-contained, more manageable pieces of code.


Learn all about curried functions in JavaScript, how to use the function currying technique to create partially applied functions, as well as real-life use cases for both curried functionWhat Is CurryCurrying is named after mathematician Haskell B. Curry, and the concept derives from Lambda calculus. Currying takes a function that receives more than one parameter and breaks it into a series of unary (one-parameter) functions. In other words, a curried function only takes one parameter at a time.

A Basic Example of Currying

Below is an example of a curried function:

 function buildSandwich(ingredient1) {
  return (ingredient2) => {
    return (ingredient3) => {
      return `${ingredient1},${ingredient2},${ingredient3}`
    }
  }
}

The buildSandwich() function returns another function — an anonymous function that receives the ingredient2 argument. Then, this anonymous function returns another anonymous function that receives ingredient3. Finally, this last function returns the template literal, a way of formatting strings in JavaScript.

What you've created is a nested function where each function calls the one underneath it until we reach the end. Now, when you call buildSandwich() and pass it a single parameter, it'll return the part of the function whose arguments you're yet to provide:

 console.log(buildSandwich("Bacon"))

You can see from the output that buildSandwich returns a function:

Web browser console output showing a function returning a function.

To complete the function call, you would need to supply all three arguments:

 buildSandwich("Bacon")("Lettuce")("Tomato")

This code passes "Bacon" to the first function, "Lettuce" to the second, and "Tomato" to the last function. In other words, the buildSandwich() function is really broken into three functions, with each function receiving only one parameter.

While it's perfectly valid to curry using the traditional functions, all the nesting can get pretty ugly the deeper you get. To get around this, you can use arrow functions and take advantage of their cleaner syntax:

 const buildMeal = ingred1 => ingred2 => ingred3 =>
`${ingred1}, ${ingred2}. ${ingred3}`;

This refactored version is more concise, an advantage of using arrow functions vs regular functions. You can call the function the same way you did with the previous one:

 buildMeal("Bacon")("Lettuce")("Tomato")

Partially Applied Curry Functions

Partially applied functions are a common use of currying. This technique entails supplying only the needed arguments at a time (rather than supplying all the arguments). Whenever you invoke a function by passing all the required parameters, you say that you have "applied" that function.

Let's look at an example:

 const multiply = (x, y) => x * y;

Below is the curried version of multiply:

 const curriedMultiply = x => y => x * y;

The curriedMultiply() function receives the x argument for the first function and y for the second function, then it multiplies both values.

To create the first partially applied function, call curriedMultiple() with the first parameter and assign the returned function to a variable:

 const timesTen = curriedMultiply(10)

At this point, the code has "partially applied" the curriedMultiply() function. So anytime you want to call timesTen(), you just need to pass it one number and the number will be automatically multiplied by 10 (which is stored inside the applied function):

 console.log(timesTen(8)) // 80

This lets you build on a single complex function by creating multiple custom functions from it, each with its own functionality locked in.

Take a look at an example that's closer to a real web development use case. Below you have a updateElemText() function that takes an element's id on the first call, the content on the second call, and then updates the element based on the id and content you supplied it:

 const updateElemText = id = content
   => document.querySelector(`#${id}`).textContent = content

// Lock the element's id into the function:
const updateHeaderText = updateElemText('header')

// Update the header text
updateHeaderText("Hello World!")


Function Composition With Curried Functions

Another common use of currying is function composition. This lets you call small functions, in a specific order, and combine them into a single, more complex function.

For example, in a hypothetical e-commerce website, here are three functions that you might want to run one after the other (in precise order):

 const addCustomer = fn => (...args) => {
  console.log("Saving customer info")
  return fn(...args)
}

const processOrder = fn => (...args) => {
  console.log(`processing order #${args[0]}`)
  return fn(...args);
}

let completeOrder = (...args) => {
  console.log(`Order #${[...args].toString()} completed.`);
}

Notice that this code uses the let keyword to define the completeOrder() function. This allows you to reassign a value to the variable and is part of how scoping works in JavaScript.

Next, you need to call the functions in reverse order (from inside to out) because you'd want to add the customers first:

 completeOrder = (processOrder(completeOrder));
completeOrder = (addCustomer(completeOrder));
completeOrder("1000")

This will give you the following output:

A screenshot showing the results of curried function composition.

If you were to write the above functions the regular way, the code will look something like this:

 function addCustomer(...args) {
  return function processOrder(...args) {
    return function completeOrder(...args) {
      // end
    }
  }
}

When you call the addCustomer() function and pass in the arguments, you're starting from the inside and working your way out to the top of the function.

Convert a Normal Function to a Curried Function With a Curry Function

If you plan to use curried functions a lot, you can streamline the process with a helper function.

This function will convert any normal function to a curried function. It uses recursion to handle any number of arguments.

 const curry = (fn) => {
  return curried = (...args) => {
    if (fn.length !== args.length) {
      return curried.bind(null, ...args)
    }

    return fn(...args);
  }
}

This function will accept any standard written function that receives more than one parameter, returning a curried version of that function. To see it in action, use this example function that takes three parameters and adds them together:

 const total = (x, y, z) => x + y + z

To convert this function, call the curry() function and pass total as an argument:

 const curriedTotal = curry(total)

Now to call the function, you just need to pass in all the arguments:

 console.log(curriedTotal(10)(20)(30)) // 60

More About Functions in JavaScript

JavaScript's functions are extremely flexible and currying functions is just a small part of that. There are many other types of functions like arrow functions, constructor functions, and anonymous functions. Familiarizing yourself with these functions and their components is key to mastering JavaScript.


Previous Post Next Post