Currying is a functional programming technique that transforms a function with multiple arguments into a sequence of functions, each taking their own argument(s), allowing for more flexible and reusable code.

For instance, rather than invoking a function in the usual manner:
calculateArea(length, width);

A curried version would be structured as:
calculateArea(length)(width);

The Advantages

Ok but why is it beneficial? Let’s create a function to multiply two numbers.

function multiply(a, b) {
    return a * b;
}

console.log(multiply(2, 5)); // Output: 10

Now lets refactor with currying:

const multiply = (a) => (b) => a * b;

const double = multiply(2); // Partially apply the first argument
console.log(double(5));     // Output: 10
console.log(double(8));     // Output: 16

What’s Improved?

  • Reusability: The double function is created by partially applying the argument 2. Now, you can reuse it anywhere to double a number without repeating logic.

  • Modularity: By splitting the function into smaller steps, it’s easier to manage and debug.

Another example? Say we have this logger function.

function logger(fileName, logLevel, message) {
    console.log(`[${fileName}] [${logLevel}] ${message}`);
}

logger("app.js", "INFO", "Application started");
logger("app.js", "ERROR", "Unhandled exception");

With currying:

const logger = (fileName) => (logLevel) => (message) =>
    console.log(`[${fileName}] [${logLevel}] ${message}`);

// Create specialised loggers
const appLogger = logger("app.js");
const infoLogger = appLogger("INFO");
const errorLogger = appLogger("ERROR");

// Use them
infoLogger("Application started");    // Output: [app.js] [INFO] Application started
errorLogger("Unhandled exception");   // Output: [app.js] [ERROR] Unhandled exception

What’s Improved?

  • Consistency: The fileName is fixed at the beginning, ensuring all logs from the same file follow a uniform format.

  • Avoid Repetition: By partially applying arguments (appLogger and infoLogger), you don’t need to repeatedly pass the same fileName and logLevel.

  • Flexibility: You can create multiple specialised loggers for different contexts and reuse them, simplifying the codebase.

You’re not limited to using this technique in Javascript either. Here’s a PHP example:

function multiply($a, $b) {
    return $a * $b;
}

echo multiply(2, 5); // Output: 10

With currying:

function multiply($a) {
    return function ($b) use ($a) {
        return $a * $b;
    };
}

$double = multiply(2); // Partially apply the first argument
echo $double(5);       // Output: 10
echo $double(8);       // Output: 16

By leveraging closures, we can create a powerful chain of functions where each function remembers the context in which it was created.

This approach allows us to break a function into smaller, reusable pieces and defer execution until all arguments are provided.

The Grumpy Dev is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.