Language: EN

que-es-el-currying-en-javascript

What is Currying in JavaScript

The currying is a technique that transforms a function with multiple parameters into a sequence of functions, each with a single parameter.

In other words, instead of passing all arguments to the function at once, currying allows you to “decompose” the function into simpler steps.

Currying is a concept that comes from the mathematical field and has found an important place in functional programming. In JavaScript, it has become a very popular pattern.

This may seem complex at first. However, at times, this approach allows for improved modularity and code reuse.

Currying in JavaScript

To illustrate currying, let’s consider a simple example. Imagine we have a simple function that adds two numbers:

function add(a, b) {
    return a + b;
}

Nothing particularly striking, right? Let’s see the curried version of this function.

function curriedAdd(a) {
    return function(b) {
        return a + b;
    };
}

Now, instead of calling our function add(a, b), we have a function that accepts one parameter and returns another function that accepts another parameter.

We can use our curriedAdd version as follows:

const add5 = curriedAdd(5);

console.log(add5(3));  // Output: 8
console.log(add5(10)); // Output: 15

In this example,

  • curriedAdd takes an argument a and returns a new function that expects the second argument b.
  • This allows us to create specialized functions (like add5) that always add a fixed number.

That is, we now have a function that generates functions that add a specific number.

Currying with Lambdas

We can use lambda functions to create a more compact version of currying. The behavior remains the same, but using lambdas makes it more concise and more in line with modern JavaScript style.

const add = a => b => a + b;

const result = add(2)(3); // Result: 5

In this example,

  • The add function is now defined as a series of nested functions using arrow syntax.
  • Each function returns another function that accepts the next argument until the final calculation with a + b is reached.

Implementation of Currying

We have seen how to manually convert a function into a “curried” version, as in the previous example with the add function.

However, it is common to create some generic solution to convert any function. Let’s look at some of them.

Utility Function

Currying can be implemented with a simple utility function. For example:

function currying(fn) {
    return function(arg1) {
        return function(arg2) {
            return fn(arg1, arg2);
        };
    };
}

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

const curriedMultiply = currying(multiply);
const multiplyBy2 = curriedMultiply(2);
console.log(multiplyBy2(4)); // Output: 8

In this example, currying converts a function with two arguments into a sequence of unary functions.

Generic Utility Function

We can also create a utility function for more advanced currying, which allows for an arbitrary number of arguments.

function currying(fn) {
    return function curried(...args) {
        if (args.length >= fn.length) {
            return fn(...args);
        } else {
            return function(...args2) {
                return curried(...args, ...args2);
            };
        }
    };
}

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

const curriedMultiply = currying(multiply);
const multiplyBy2and3 = curriedMultiply(2)(3);
console.log(multiplyBy2and3(4)); // Output: 24

In this example, the currying function takes any function fn and returns a curried version of it. This allows arguments to be passed one at a time or in groups.

Using Libraries

Many JavaScript libraries and frameworks provide support for currying. For example, Lodash has a function _.curry that makes it easy to create curried functions.

const _ = require('lodash');

const curriedSum = _.curry(function(a, b, c) {
    return a + b + c;
});

console.log(curriedSum(1)(2)(3)); // 6

Function Composition

Currying and function composition are closely related. While currying decomposes functions into a series of unary functions, function composition allows you to combine them to build new, more complex functions.

const add = a => b => a + b;
const multiply = a => b => a * b;

// We combine the functions to create a new one
const multipliedSum = (a, b, c) => multiply(a)(add(b)(c));

console.log(multipliedSum(2, 3, 4)); // Output: 14

In this example,

  • add and multiply are curried functions that return a new function when receiving an argument.
  • multipliedSum uses composition. First, add(b)(c) calculates the sum of b and c, returning 7. Then, multiply(a)(7) multiplies the result by a, giving 14.

That is, we have composed two curried functions (add and multiply) to form a new, more complex function (multipliedSum).

In a sense, function composition is the inverse of currying: instead of splitting, we are combining.

Practical Examples