currying
Currying in JavaScript
Transforming multi-argument functions into unary pipelines for ultimate reusability.
The Custom Sandwich Assembly Station
Currying transforms a function with multiple arguments $f(a, b, c)$ into a sequence of nesting unary functions f(a)(b)(c). It enables partial application, dependency injection, and cleaner function composition.
Function Arity
Arity is the number of arguments a function expects, accessible via `fn.length`. Currying breaks down an N-ary function into N unary functions.
Closure Retention of Arguments
Each intermediate function captures previous arguments in its closure until all required arguments are collected.
Partial Application vs Currying
Currying converts to unary (one-argument) functions in sequence. Partial application fixes a subset of arguments and returns a function that takes the rest all at once.
Generic Curry Implementation
A recursive helper compares the count of accumulated arguments against `fn.length`. If enough are received, it executes; otherwise, it returns a new function waiting for more.
Building a generic, production-ready curry function and real-world logger:
// Generic recursive curry implementation
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
}
return function(...nextArgs) {
return curried.apply(this, args.concat(nextArgs));
};
};
}
// Practical Example: Reusable Configurable Logger
const log = curry((date, level, message) => {
console.log(`[${date.toISOString().slice(11, 19)}] [${level.toUpperCase()}] ${message}`);
});
const logToday = log(new Date());
const logErrorToday = logToday("error");
const logInfoToday = logToday("info");
logErrorToday("Database connection timed out");
logInfoToday("Server listening on port 3000");
[15:00:00] [ERROR] Database connection timed out
[15:00:00] [INFO] Server listening on port 3000
Functions with Default Parameters Breaking fn.length
The Risk: In JavaScript, default parameters do not count towards `fn.length` (`((a, b = 1) => {}).length` is 1), causing naive curry utilities to execute prematurely.
The Fix: Ensure functions to be curried have explicit arity without default params, or specify arity explicitly to the curry helper.
-
✓
Currying transforms $f(a, b, c)$ into
f(a)(b)(c). - ✓ Arity = number of expected parameters (`fn.length`).
- ✓ Enables Partial Application and reusable function configuration.
- ✓ Relies heavily on closures to accumulate arguments across calls.
- ✓ Check `args.length >= fn.length` in generic curry utilities.