DEV Community

Linas Spukas
Linas Spukas

Posted on

 

Curring In Javascript

Currying is a technique of transforming function with multiple arguments into a sequence of functions, each with a single argument.
Let's compare regular and curried function:

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

add(2, 3, 5) // 10

// curried function
function curriedAdd(a) {
  return function(b) {
    return function(c) {
      return a + b + c;
    }
  }
}

curriedAdd(2)(3)(5) // 10

In the example above, the regular function add takes multiple arguments at once and returns the evaluated result. The second function, curried curriedAdd, that takes the first argument, returns a function, that takes the second arguments, which returns the third function with the last argument. The last function evaluates and returns the result. Because the curried function returns two more functions in a sequence, it supposed to be called three times curriedAdd(2)(3)(5), while the regular function is called one time with all the arguments at once add(2, 3, 5);

Where It Is Useful

Currying is an advanced functional concept and is not very common, and usually used for specific cases. Still, knowing it can help you solve the following problems.

Avoid Passing Same Arguments

When you find yourself continuously passing the same arguments all over again, you can avoid it by restructuring into currying function. For example, function add is being called with the same argument of 2:

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

// repeating calls with the same argument
sum(2, 3) // 5
sum(2, 7) // 9

// curried function
function add(a) {
  return function(b) {
    return a + b;
  }
}

const addTwo = add(2);

// which is equal to
const addTwo = function add(2, b) {
  return function(b) {
    return 2 + b;
  }
}

addTwo(3) // 5
addTwo(7) // 9

Make Function Compositions

Currying is great for function compositions. If you have multiple functions, that relies upon the result of the previous one, you can create a pipeline of functions:

function addTwo(a) {
  return 2 + a;
}

function substractOne(a) {
  return a - 1;
}

// instead of calling functions separately
// we can compose into a curried function
// that will take any amount of functions into a pipeline

function compose(...fns) {
  return function(a) {
    return fns.reduce((result, fn) => fn(result), a) 
  }
};

const pipe = compose(addTwo, substractOne);

pipe(3) // 4

The function compose takes any amount of functions, returns the function that takes an argument which will be run against all the functions that were passed in to compose function. The reduce method will accumulate the result from each of the functions and will pass to the next one.

Hold The State

As functions are objects too, with the help of currying we can assign the property to the function, that will be used in the following curried function calls. The following example will help you understand the first sentence better. Let's say we want to write infinite currying function, that takes any amount of arguments and any amount of curried functions. As we will not know how many arguments nor functions we will have, we need to store the state inside the function:

function add(...a) {
  function curried(...b) {
    return add(...a, ...b)
  }

  // assign `sum` field to function `curried`
  // to hold the sum value for the following function calls
  curried.sum = a.reduce((result, value) => result + value);

  return curried;
}

// the state of the sum of all arguments
// will be kept in the functions `value` field that we created
add(2, 3, 5)(5, 5)(2)(1).sum; // 23

Sum Up

Now we know, that a curried function produces nested functions, where the arguments are taken one by one until they are resolved and the result is returned. With the help of currying, the functional composition is made easy and you can avoid passing the same arguments continuously.
Currying is a very powerful concept, not easy to wrap your head around it. The readability of the code where the currying is used probably is the main reason why it is used not that often.

Top comments (0)

Need a better mental model for async/await?

Check out this classic DEV post on the subject.

⭐️🎀 JavaScript Visualized: Promises & Async/Await

async await