DEV Community

Abdullah Al Numan
Abdullah Al Numan

Posted on • Updated on

Currying Existing Functions with JavaScript

This post is about transforming an already defined polyadic function into a curried function.

This is the third post in a series on curried functions titled Curry Functions in JavaScript. This follows the previous post named Basic Curried Functions in JavaScript.

Basic vs Advanced Currying

Basic curried functions are different from more advanced ones because basic currying doesn't involve taking a function as an argument, whereas more advanced ones do. Basic curried functions are defined from scratch, whereas advanced currying involves using an already existing multary function.

From a higher level, currying is more of an approach of transforming an otherwise uncurried function to return a series of unary functions - regardless of whether it is hardcoded by the author or transformed at runtime.

We will consider several advanced cases differing in their complexity levels: first one involving a wrapper function defined manually from ground up, but basing it on the passed, to-be-curried function.

In the upcoming posts, we will also cover auto-currying, variadic currying, infinite currying and currying to a fixed arity.

This article covers currying existing functions manually.

Currying Existing Functions Manually

In this example, we'll use the createMessage() function we wrote in the previous post named Basic Curried Functions in JavaScript.

Let's say, we have the function that returns the message string in hand:

function createMessage(greeting, name, message) {
  return `${greeting}, ${name}! ${message}`;
};
Enter fullscreen mode Exit fullscreen mode

Instead of writing a curried function from scratch for the above function, like this:

function createMessage(greeting) {
  return function(name) {
    return function(message) {
      return `${greeting}, ${name}! ${message}`;
    };
  };
};
Enter fullscreen mode Exit fullscreen mode

we can use the existing multary function by passing it to a wrapper function and then build the wrapper function on top of it:

function curryATernaryFunction(f) {
  return function(greeting) {
    return function(name) {
      return function(message) {
        return f(greeting, name, message);
      };
    };
  };
};
Enter fullscreen mode Exit fullscreen mode

Then calling the wrapper function with createMessage will give us the curried function. We can use it for our purposes afterwards:

const curriedCreateMessage = curryATernaryFunction(createMessage);
console.log(curriedCreateMessage('Hi')('Haskell')('Whadup?'));
// Hi, Haskell! Whadup?

Enter fullscreen mode Exit fullscreen mode

I named the above function curryATernaryFunction because I wanted to play with it a bit. We can actually curry other ternary functions (those that take three arguments) with it:

function addThreeThings(one, two, three) {
  return one + two + three;
};

console.log(curryATernaryFunction(addThreeThings)('Hi')('Haskell')('Whadup?'));
// HiHaskellWhadup?
console.log(curryATernaryFunction(addThreeThings)(1)(2)(3)); // 6

Enter fullscreen mode Exit fullscreen mode

How it works:
The wrapper function is called an accumulator. Its purpose is to store all the passed in arguments and make them available to the multary function. It uses nested closures (the returned functions at each level of nesting along with their lexical environments) to accumulate all the arguments for the final returned function.

The way it works is, every time a returned function is invoked and it takes its given argument, the argument is held at its immediately nested function's lexical scope - which makes it available to deeper ones via their scope chain. So, our core function's execution context is able to access all the arguments.

Top comments (2)

Collapse
 
jonrandy profile image
Jon Randy 🎖️

Why not write the manually curried function in a much simpler way?

const createMessage = greeting => name => message =>
  `${greeting}, ${name}! ${message}`
Enter fullscreen mode Exit fullscreen mode
Collapse
 
anewman15 profile image
Abdullah Al Numan

There's no staircase here, it looks like a rope. Doesn't help with visualization :)