CodePark/ questions / Functional patterns
START PRACTICINGPRACTICE
Frontend question · JavaScript › Functional patterns

What is currying? Write a generic curry function.

function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) return fn.apply(this, args);
    return (...more) => curried.apply(this, [...args, ...more]);
  };
}
const add = curry((a, b, c) => a + b + c);
add(1)(2)(3); // 6
add(1, 2)(3); // 6

Currying turns a function that takes several arguments into a chain of functions that each take one argument. For example, add(a, b, c) becomes add(a)(b)(c).

In practice, JavaScript curry helpers are more flexible. They accept any number of arguments per call. They run the original function once enough arguments have been collected. So add(1, 2)(3) also works.

Why it is useful:

  • You can build specific functions from general ones. Example: const logError = log('error').
  • You can combine small functions in point-free style. This means writing functions without naming their arguments, like items.map(double) instead of items.map(x => double(x)).

Currying is close to partial application, which fixes some arguments at once. bind does partial application.

How the code works: it compares the number of collected arguments with fn.length, the number of declared parameters. When there are enough, it calls fn. Otherwise it returns a function that collects more.

Limitation: this does not work with rest parameters or default values, because length does not count them.

  • Currying turns f(a, b, c) into f(a)(b)(c).
  • It is built on closures that collect arguments.
  • It uses fn.length to know when to call the original function.
  • It is related to partial application, which bind does.
  • It lets you build reusable, specific functions from general ones.