Why Lodash/fp Functions Are Auto-Curried by Default

Lodash's functional programming variant, lodash/fp, automatically curries its functions to promote clean functional composition, enable effortless partial application, and reduce boilerplate in data transformation pipelines. By transforming multi-argument utilities into sequences of single-argument functions, lodash/fp allows developers to configure transformations upfront and apply them to data later, aligning standard JavaScript with modern functional programming paradigms.

Understanding Auto-Currying

Currying is the process of converting a function that takes multiple arguments into a chain of functions that each take a single argument. In standard Lodash, calling _.map(collection, iteratee) requires both the data and the operation to be supplied together. In lodash/fp, calling fp.map(iteratee) without the second argument does not throw an error or return undefined; instead, it returns a new function waiting to receive the collection.

The Synergy Between Currying and "Data-Last" Arguments

Standard Lodash is "data-first" (_.filter(array, predicate)), which is optimal for method chaining via object wrappers. However, lodash/fp flips this convention to "iteratee-first, data-last" (fp.filter(predicate, array)).

Auto-currying is designed to leverage this rearranged argument order. Because the data argument is always placed last, omitting it automatically generates a reusable transformer function that awaits the data:

// Pre-configured, reusable utility
const getActiveUsers = fp.filter(user => user.isActive);

// Applied later to various datasets
const activeAdmins = getActiveUsers(adminList);
const activeMembers = getActiveUsers(memberList);

Facilitating Function Composition and Pipelines

Modern functional code relies heavily on composition mechanisms like fp.flow or fp.compose (left-to-right or right-to-left execution). These utilities pass the return value of one function directly into the next as an argument.

Without auto-currying, combining Lodash methods requires verbose arrow function wrappers:

// Without auto-currying:
const getAdultNames = data => 
  fp.flow(
    d => fp.filter(user => user.age >= 18, d),
    d => fp.map(user => user.name, d)
  )(data);

With auto-curried functions, the explicit argument references disappear:

// With auto-currying:
const getAdultNames = fp.flow(
  fp.filter(user => user.age >= 18),
  fp.map('name')
);

Enabling "Point-Free" Style

Auto-currying enables point-free (tacit) programming, a paradigm where function definitions do not explicitly identify the arguments (or "points") they process. By removing the need to name intermediary variables that merely pass data from one step to the next, codebase noise decreases, cognitive load is reduced, and individual operations become easier to test, isolate, and reuse across an application.