HiveBrain v1.2.0
Get Started
← Back to all entries
snippetjavascriptTip

Understanding JavaScript currying

Submitted by: @import:30-seconds-of-code··
0
Viewed 0 times
javascriptcurryingunderstanding

Problem

Functional programming often makes use of currying, which is a process that transforms a function that takes multiple arguments into a series of functions that each take a single argument. This makes code more flexible and reusable.
Creating a curry() function can be tricky in some cases. For the sake of simplicity, let's start with a function whose number of arguments is fixed. In that case, we will use Function.prototype.length to determine the number of arguments the function accepts.
Knowing the number of arguments needed to call the function, we will then use recursion to create a curried function that will call the original function once the number of arguments provided is sufficient. If not, it will return a new function that will accept the remaining arguments.
Variadic functions are functions that accept a variable number of arguments. For example, Math.min() is a variadic function that returns the smallest of zero or more numbers.
> [!NOTE]

Solution

const curry = (fn) => {
  const curried = (...args) => (
    args.length >= fn.length
      ? fn(...args)
      : (...rest) => curried(...args, ...rest)
  );
  return curried;
};

const add = (x, y) => x + y;
const curriedAdd = curry(add);
curriedAdd(1)(2); // 3


Knowing the number of arguments needed to call the function, we will then use recursion to create a curried function that will call the original function once the number of arguments provided is sufficient. If not, it will return a new function that will accept the remaining arguments.
Variadic functions are functions that accept a variable number of arguments. For example, Math.min() is a variadic function that returns the smallest of zero or more numbers.
> [!NOTE]
>
> Math.min.length is 2, which weakly signals that it's designed to handle at least two parameters. This, however, isn't in line with user-defined variadic function.
Our previous implementation will simply not work. Indeed, Function.prototype.length will return 0 for variadic functions. In order to circumvent this issue, we should be able to define the arity of the function we want to curry. This way, the curried function will know when to stop expecting further arguments and call the original function.

Code Snippets

const curry = (fn) => {
  const curried = (...args) => (
    args.length >= fn.length
      ? fn(...args)
      : (...rest) => curried(...args, ...rest)
  );
  return curried;
};

const add = (x, y) => x + y;
const curriedAdd = curry(add);
curriedAdd(1)(2); // 3
const curry = (fn, arity = fn.length, ...args) =>
  arity <= args.length ? fn(...args) : curry.bind(null, fn, arity, ...args);

curry(Math.pow)(2)(10); // 1024
curry(Math.min, 3)(10)(50)(2); // 2
const uncurry = (fn, arity = 1) => (...args) => {
  const next = acc => args => args.reduce((x, y) => x(y), acc);
  if (arity> args.length) throw new RangeError('Arguments too few!');
  return next(fn)(args.slice(0, arity));
};

const add = x => y => z => x + y + z;
const uncurriedAdd = uncurry(add, 3);
uncurriedAdd(1, 2, 3); // 6

Context

From 30-seconds-of-code: currying

Revisions (0)

No revisions yet.