Currying and Partial Application in JavaScript

This article provides a concise overview of currying and partial function application in JavaScript, explaining their core mechanics and practical differences. You will learn how currying transforms a multi-argument function into a chain of unary functions and how this behavior serves as a powerful foundation for partial application to create modular, reusable code.

What is Currying?

Currying is a functional programming technique where a function with multiple arguments is transformed into a sequence of functions, each taking a single argument.

Instead of taking all arguments at once like f(a, b, c), a curried function is evaluated as f(a)(b)(c).

Standard Function vs. Curried Function

// Standard function
function add(a, b, c) {
  return a + b + c;
}
add(1, 2, 3); // 6

// Curried function
function curriedAdd(a) {
  return function(b) {
    return function(c) {
      return a + b + c;
    };
  };
}
curriedAdd(1)(2)(3); // 6

// Arrow syntax for currying
const arrowCurriedAdd = a => b => c => a + b + c;

What is Partial Function Application?

Partial function application (or partial application) is the process of fixing a certain number of arguments to a function, producing a new function of smaller arity (accepting fewer arguments).

For example, if you have a function that takes three arguments and you provide two, partial application returns a function that only expects the remaining one argument.

function multiply(a, b) {
  return a * b;
}

// Partial application using bind
const double = multiply.bind(null, 2);
console.log(double(5)); // 10

How Currying Facilitates Partial Application

Currying natively enables partial application without the need for methods like bind(). Because a curried function returns a new function at every step of argument evaluation, you can stop the chain at any point to create a specialized function.

Practical Example: Discount Calculator

Consider a function that calculates the final price of an item given a discount rate and the item’s price:

// Curried discount calculator
const applyDiscount = discount => price => price - price * discount;

// Partially apply the discount to create specialized functions
const tenPercentDiscount = applyDiscount(0.10);
const twentyPercentDiscount = applyDiscount(0.20);

// Use the partially applied functions
console.log(tenPercentDiscount(100)); // 90
console.log(tenPercentDiscount(50));  // 45
console.log(twentyPercentDiscount(100)); // 80

In this example, applyDiscount is a curried function. Calling applyDiscount(0.10) performs partial application by fixing the discount parameter and returning a reusable function tailored for 10% discounts.

Creating a Generic Curry Utility

In standard JavaScript libraries like Lodash or Ramda, curry functions are flexible enough to accept arguments either individually or in batches until the expected number of parameters (arity) is satisfied.

function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    } else {
      return function(...nextArgs) {
        return curried.apply(this, args.concat(nextArgs));
      };
    }
  };
}

// Example usage:
function sendRequest(protocol, domain, path) {
  return `${protocol}://${domain}/${path}`;
}

const curriedRequest = curry(sendRequest);

// Partial application by supplying arguments in different steps
const httpsRequest = curriedRequest('https');
const localHttpsRequest = httpsRequest('localhost:3000');

console.log(localHttpsRequest('api/users')); // "https://localhost:3000/api/users"
console.log(curriedRequest('http')('example.com')('home')); // "http://example.com/home"

Summary of Differences