Currying
TL;DR
Currying is a functional programming technique where a function that takes multiple arguments (f(a, b, c)) is transformed into a sequence of functions that each take exactly one argument (f(a)(b)(c)). It relies heavily on Closures to remember the previous arguments.
Mental Model
How It Works
Instead of requesting all parameters upfront, a curried function takes the first parameter and returns a new function. That new function takes the second parameter and returns another function, and so on. The final function in the chain has access to all the previously passed arguments via Closures, so it performs the actual computation.
Why use it?
It allows for Partial Application. You can pre-configure a function with some arguments and reuse it later.
Example
// --- Standard Function ---
function standardAdd(a, b, c) {
return a + b + c;
}
// --- Curried Version ---
function curriedAdd(a) {
return function(b) {
return function(c) {
return a + b + c; // Uses closures to access a and b
};
};
}
console.log(curriedAdd(1)(2)(3)); // 6
// --- The Power of Currying: Partial Application ---
function calculateDiscount(discount) {
return function(price) {
return price - (price * discount);
};
}
// We "pre-configure" a function specifically for 10% discounts
const tenPercentOff = calculateDiscount(0.10);
// Later in the app, we can use it simply:
console.log(tenPercentOff(500)); // 450
console.log(tenPercentOff(100)); // 90
Common Output Question
const multiply = a => b => c => a * b * c;
console.log(multiply(2)(3)(4));
Q: Explain what is happening here.
A: This is identical to the curriedAdd example, but written using modern ES6 Arrow Function syntax.
multiply(2)returns an arrow functionb => c => 2 * b * c.(3)passes 3 intob, returningc => 2 * 3 * c.(4)passes 4 intoc, executing the final math2 * 3 * 4, returning24.
Senior Interview Question
Q: Write a utility function curry(fn) that converts any standard function into a curried function.
A: This is a classic FAANG interview question. You must use recursion and check the length property of the function (which tells you how many arguments it originally expected).
function curry(fn) {
return function curried(...args) {
// If we have collected enough arguments, run the original function
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
// Otherwise, return a new function that collects more arguments
return function(...nextArgs) {
return curried.apply(this, args.concat(nextArgs));
};
}
};
}
// Usage:
const sum = (a, b, c) => a + b + c;
const curriedSum = curry(sum);
console.log(curriedSum(1)(2)(3)); // 6
console.log(curriedSum(1, 2)(3)); // 6