Currying & Partial Application
Transforming a multi-argument function into a chain of single-argument functions.
Overview
Currying transforms a function that takes multiple arguments into a chain of functions each taking a single argument. Partial application is the related concept of fixing some arguments of a function to produce a new function with fewer parameters. Together they enable function reuse, composition, and the creation of specialised functions from general ones.
Origin
Named after Haskell Curry (though the technique was first identified by Moses Schönfinkel in 1924). Currying is foundational to Haskell, where all functions are curried by default. It was popularised in JavaScript through libraries like Ramda and lodash/fp.
Examples
Currying and partial application in JavaScript
// Generic curry utility
const curry = fn => {
const arity = fn.length
return function curried(...args) {
if (args.length >= arity) return fn(...args)
return (...more) => curried(...args, ...more)
}
}
const multiply = curry((a, b) => a * b)
const double = multiply(2) // partial application
const triple = multiply(3)
double(5) // => 10
triple(5) // => 15
// Composing curried functions into a pipeline
const add = curry((a, b) => a + b)
const gt = curry((threshold, n) => n > threshold)
const tax = curry((rate, amount) => amount * (1 + rate))
const applyGST = tax(0.15)
const overHundred = gt(100)
[90, 110, 200]
.filter(overHundred)
.map(applyGST) // => [126.5, 230]Partial application in Ruby
logger = ->(level, message) { puts "[#{level.upcase}] #{message}" }
info = logger.curry.call('info')
error = logger.curry.call('error')
info.('Server started') # [INFO] Server started
error.('Disk full') # [ERROR] Disk full
# Method#curry on any method
add = method(:+).to_proc.curry
add_five = add.(5)
[1, 2, 3].map(&add_five) # => [6, 7, 8]Use Cases
- 01Creating specialised functions from general ones (applyTax, sendWelcomeEmail, validateEmail)
- 02Functional pipelines that compose point-free style: array.map(double).filter(isPositive)
- 03Event handlers configured with context at setup time, invoked later with event data
- 04React component factories that pre-configure common props
- 05Middleware pipelines where each step receives partial context from the one before
When Not to Use
- //When the curried form is harder to read than a plain multi-argument call
- //When functions are not reused with different partial applications, the pattern adds complexity for no gain
- //In performance-critical code: each curried call creates a new closure
Technical Notes
- Currying and partial application are not the same: currying always produces unary functions; partial application fixes any number of arguments
- Haskell functions are curried by default, add 3 returns a function awaiting the second argument
- JavaScript's Function.prototype.bind is partial application: fn.bind(context, arg1) fixes the first argument
- Point-free style (not mentioning the data argument explicitly) becomes natural when functions are curried, it can improve readability or obscure it depending on context
More in Programming Techniques