Functional JavaScript — Currying

John Au-Yeung - Jan 25 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

JavaScript is partly a functional language.

To learn JavaScript, we got to learn the functional parts of JavaScript.

In this article, we’ll look at how to use currying with JavaScript.

Unary Function

A unary function is a function that takes a single argument.

For example, a unary function is:

const identity = (x) => x;
Enter fullscreen mode Exit fullscreen mode

Binary Function

A binary function is a function that takes 2 arguments.

An example of one is:

const add = (x, y) => x + y;
Enter fullscreen mode Exit fullscreen mode

Variadic Function

A variadic function is a function that takes a variable number of arguments.

We can define a variadic function in JavaScript by using the rest operator:

function variadic(...args) {
  console.log(args)
}
Enter fullscreen mode Exit fullscreen mode

args has an array of all the arguments we pass in.

Currying

Curry is converting a function with multiple arguments into nested unary functions.

This is useful because it lets us create functions with some of the arguments applied.

For example, we can convert a binary function:

const add = (x, y) => x + y;
Enter fullscreen mode Exit fullscreen mode

into a function unary function that returns another unary function by writing:

const addCurried = x => y => x + y;
Enter fullscreen mode Exit fullscreen mode

The addCurried function takes a parameter x and returns a function that takes a parameter y which returns the sum of x and y together.

Then we can use it by writing:

const add1 = addCurried(1);
const sum = add1(2);
Enter fullscreen mode Exit fullscreen mode

We called addCurried with 1 to return a function with x set to 1 and assign that to the add variable.

Then we call add1 with 2 to return the final sum.

We can generalize this by creating a function that returns a function that takes one argument, which is the binary function.

Inside that function, we return a function that takes the 2nd argument.

And inside that, we return the result of the binary function called with the parameters of the outer functions.

For example, we can write:

const curry = (binaryFn) => {
  return (firstArg) => {
    return (secondArg) => {
      return binaryFn(firstArg, secondArg);
    };
  };
};

const add = (x, y) => x + y
const sum = curry(add)(1)(2);
Enter fullscreen mode Exit fullscreen mode

to create the curry function to do what we described.

Then we can pass in any binary function like our add function.

And then it’ll be curried automatically.

We can generalize this further with a curry function that recursively returns functions with one argument, until there’s only one argument left.

For instance, we can write:

let curry = (fn) => {
  if (typeof fn !== 'function') {
    throw Error('No function provided');
  }

  return function curriedFn(...args) {
    if (args.length < fn.length) {
      return function(...moreArgs) {
        return curriedFn(...[...args, ...moreArgs]);
      };
    }
    return fn(...args);
  };
};
Enter fullscreen mode Exit fullscreen mode

We check if fn is a function.

If it is, then we return a function that returns a function that calls the same function that’s returned if fn has more parameters than args .

If there are more arguments in fn than args , that means that we can curry it more.

If the number of parameters of the curried function is the same as the number of parameters in fn , then we can’t curry more.

So we just call the function.

Then we can call it by writing:

const add = (x, y, z) => x + y + z;
const sum = curry(add)(1)(2)(3);
Enter fullscreen mode Exit fullscreen mode

We curried the function, so we call the curried function with their individual arguments.

And sum is 6 since we add all the numbers together.

Conclusion

We can curry functions so that we can create functions with some arguments applied and reuse that function for something else.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .