What is curry?
Currying is a technique in programming where a function that normally takes several arguments is transformed into a chain of functions, each taking just one argument. The result is a series of nested functions that remember the arguments they received until all required inputs are provided, at which point the original computation is performed.
Let's break it down
Imagine a normal function add(a, b) that returns a + b. After currying, it becomes addCurried(a)(b). First you call addCurried with the first argument (a); this returns a new function that expects the second argument (b). When you finally supply b, the inner function adds the two numbers and returns the result. In code:
function add(a, b) { return a + b;
}
const addCurried = a => b => a + b;
let addFive = addCurried(5); // returns a function waiting for the second number
let result = addFive(3); // result is 8
Why does it matter?
Currying makes it easy to create specialized versions of a generic function without rewriting code (partial application). It also encourages a functional style where small, single‑argument functions can be composed together, leading to clearer, more reusable code. In large codebases, this can reduce duplication and simplify testing.
Where is it used?
- Functional programming languages like Haskell and Elm use currying by default.
- JavaScript libraries (e.g., Ramda, Lodash/fp) provide curried utilities.
- In React, hooks such as useCallback often rely on partially applied functions.
- Python’s functools.partial mimics currying for specific use cases.
- Many functional‑style APIs in Scala, F#, and Clojure encourage curried functions.
Good things about it
- Enables partial application, letting you pre‑fill some arguments.
- Improves function composition and pipeline creation.
- Leads to more modular, testable code.
- Often results in cleaner, more expressive APIs.
- Works well with immutable data and pure functions, core ideas of functional programming.
Not-so-good things
- Can be harder for beginners to read, especially when functions are deeply nested.
- May introduce slight performance overhead due to extra function calls.
- Debugging stack traces can become more complex.
- Over‑use can lead to overly abstract code that’s difficult to maintain.