JavaScript Currying
Rahul Vijayvergiya
Posted on July 15, 2024
Currying is a powerful concept in functional programming that transforms a function with multiple arguments into a sequence of functions, each taking a single argument. This technique allows for more modular and reusable code. In JavaScript, currying can be implemented in various ways. This blog will explore currying, provide examples, and discuss different methods to achieve n argument currying.
What is Currying?
Currying is the process of converting a function that takes multiple arguments into a series of functions that each take a single argument. For example, a function f(a, b, c) can be transformed into f(a)(b)(c).
Why Use Currying?
- Partial Application: Currying allows you to fix some arguments of a function and create a new function.
- Higher-Order Functions: It facilitates the use of higher-order functions, which take other functions as arguments or return them.
- Code Reusability: Curried functions are more reusable and composable.
- Functional Composition: Currying enables better functional composition, where complex functions are built by combining simpler functions, leading to cleaner and more maintainable code.
Simple Currying Example
Let's start with a basic example to understand how currying works.
Uncurried Function
Here's a simple function that adds three numbers:
function add(a, b, c) {
return a + b + c;
}
console.log(add(1, 2, 3)); // Output: 6
Explanation: This function add takes three arguments a, b, and c, and returns their sum. When we call add(1, 2, 3), it returns 6.
Curried Function
Now, let's convert this function into a curried version:
function curryAdd(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}
console.log(curryAdd(1)(2)(3)); // Output: 6
Explanation: The curryAdd function takes an argument a and returns a function that takes an argument b, which in turn returns a function that takes an argument c. The final function returns the sum of a, b, and c. When we call curryAdd(1)(2)(3), it sequentially passes the arguments 1, 2, and 3 through the nested functions, resulting in 6.
Currying with Arrow Functions
JavaScript's arrow functions provide a concise way to create curried functions.
const curryAddArrow = a => b => c => a + b + c;
console.log(curryAddArrow(1)(2)(3)); // Output: 6
Explanation: The curryAddArrow function is an arrow function that takes an argument a and returns another arrow function that takes b, which returns yet another arrow function that takes c. The final arrow function returns the sum of a, b, and c. When we call curryAddArrow(1)(2)(3), it sequentially passes the arguments 1, 2, and 3 through the nested arrow functions, resulting in 6.
Use Case
1.Configuration Functions
A common use case for currying is configuration functions. For instance, imagine you are creating a logging utility where you want to configure the logging level and the message format separately.
function logger(level) {
return function (message) {
console.log(`[${level}] ${message}`);
};
}
const infoLogger = logger('INFO');
const errorLogger = logger('ERROR');
infoLogger('This is an info message');
errorLogger('This is an error message');
2. String Formatter
Let's consider a practical example where currying can be used to create a string formatter. This formatter will allow you to configure the prefix and suffix separately.
function formatter(prefix) {
return function (suffix) {
return function (str) {
return `${prefix}${str}${suffix}`;
};
};
}
const htmlFormatter = formatter('<b>')('</b>');
console.log(htmlFormatter('Hello')); // <b>Hello</b>
const parensFormatter = formatter('(')(')');
console.log(parensFormatter('123')); // (123)
Currying in Modern JavaScript Libraries
Currying is commonly used in modern JavaScript libraries like Lodash and Ramda. For example, in Lodash, you can use the _.curry method to create curried functions easily.
const _ = require('lodash');
function multiply(a, b, c) {
return a * b * c;
}
const curriedMultiply = _.curry(multiply);
console.log(curriedMultiply(2)(3)(4)); // 24
console.log(curriedMultiply(2, 3)(4)); // 24
Currying with N Arguments
Let go through below example of currying with a recursive function that adds n arguments. We'll use currying to create a function that can accept any number of arguments, one at a time, and add them together.
function curryAddition(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn(...args);
} else {
return function(...nextArgs) {
return curried(...args, ...nextArgs);
};
}
};
}
// This function sums an array of numbers
function add(...nums) {
return nums.reduce((acc, num) => acc + num, 0);
}
// Creating a curried version of the addition function
const curriedAdd = curryAddition(add);
// Function to handle n arguments
function curriedAddN(...initialArgs) {
function adder(...args) {
if (args.length === 0) {
return curriedAdd(...initialArgs);
}
initialArgs.push(...args);
return adder;
}
return adder;
}
// Examples
const addFiveNumbers = curriedAddN();
console.log(addFiveNumbers(1)(2)(3)(4)(5)()); // 15
const addThreeNumbers = curriedAddN(1)(2)(3);
console.log(addThreeNumbers()); // 6
const addNumbersInSteps = curriedAddN(1, 2)(3)(4, 5);
console.log(addNumbersInSteps()); // 15
Conclusion
Currying is a powerful technique in functional programming that enhances modularity and reusability of code. By transforming functions into chains of single-argument functions, currying allows for partial application and flexible function composition. Whether for configuration, string formatting, or complex computations, currying can make your code more expressive and adaptable.
Posted on July 15, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.