Introduction
While talking about functional programming, we might have heard the term "currying". But what is it? What does it mean? How does it work? Let's find out.
What is currying?
Currying is a technique of evaluating a function with multiple arguments, into a sequence of functions with a single argument. It is also known as partial function application. It is not only used in functional programming, but also in object-oriented programming. It is used to make functions more flexible and reusable.
Let's take a look at an example to understand how currying works.
// curry(f) does the currying transform
function curry(fn) {
return function(a) {
return function(b) {
return fn(a, b);
};
};
}
// let curry = fn => (a => (b => fn(a,b)));
function add(a, b) {
return a + b;
}
add(2,3); // 5
add(2,6); // 8
let curryAdd = curry(add);
curryAdd(1)(2); // 3
const add2 = curryAdd(2);
add2(3); // 5
add2(6); // 8
const add5 = curryAdd(5);
add5(7); // 12
In the above example, the function add
is a regular function that takes 2 arguments and returns the sum. If we were to use that in multiple places with multiple combinations we'd have to define both arguments for every single function call which would be tedious. But what happens if we curry the function?
With currying, we can create an intermediate function, add2
or add5
that can be used to get our outputs in difference cases.
With currying, we are able to save the intermediate function as a specialized function that can be used again later.
The function f(a,b)
was simplified to f(a)(b)
.
Why do we need currying?
Currying helps us to make functions more reusable and flexible. Something every developer should follow while writing code.
When we curry a function we are able to save the intermediate functions that can be used later. If a function that takes many arguments is curried, then every time we pass an argument to an intermediate function we get a more specialized function.
Let's say we want to build a translator:
function translate(fromLanguage, toLanguage, message) {
...
}
translate = _.curry(translate);
After that translate
works normally:
translate("English", "Japanese", "Hello"); // Konichiwa
But also works in the curried for, so we can save the intermediate functions which can be reused
let translateEnglish = translate("English");
translateEnglish("Japanese", "Hello"); // Kinochiwa
translateEnglish("French", "Hello"); // Bonjour
let englishToJapanese = translateEnglish("Japanese");
englishToJapanese("Goodbye"); // Sayonara
So:
- We still preserve the original function
- We are able to generate partial functions easily that can be reused
Currying can also be used in composing functions.
Advanced implementation of curry
This implementation can be used for multi-argument functions
const curry = (fn) => {
return helper = (...args) => {
if (args.length >= fn.length) {
return fn(...args);
} else {
return (...args2) => {
return helper(...args, ...args2);
};
}
};
};
Example implementation
function add(num1, num2, num3) {
return num1 + num2 + num3;
}
let curryAdd = curry(add);
console.log(curryAdd(1, 2, 3)); // 6
console.log(curryAdd(1)(2, 3)); // 6
console.log(curryAdd(1)(2)(3)); // 6
Conclusion
While currying may not be commonly used and can feel complicated, it is an important concept to understand when it comes to functional programming.
Thanks for reading this article, and please feel free to leave any comments you have. I’m open to learning from you. Cheers!