Lodash flowRight: Mathematical Function Composition

Lodash's _.flowRight method provides a direct implementation of mathematical function composition for JavaScript applications. By accepting a series of functions and invoking them from right to left, _.flowRight replicates the standard algebraic notation where the output of one operation automatically feeds into the next. This article breaks down the mechanics of mathematical composition, illustrates how _.flowRight mirrors this behavior, and explores how it simplifies nested operations in functional programming.

The Principle of Mathematical Composition

In mathematics, function composition combines two or more functions to produce a new function. Given two functions, \(f\) and \(g\), their composition is formally written as:

\[(f \circ g)(x) = f(g(x))\]

In this notation, evaluation occurs from the inside out, or right to left. The inner function \(g(x)\) executes first using the original input \(x\). The resulting value is then passed directly as the argument to the outer function \(f\).

If extended to three functions—\((f \circ g \circ h)(x)\)—the execution order remains strictly right-to-left: \(h(x)\) executes first, \(g\) receives the result of \(h\), and finally \(f\) receives the result of \(g\).

How Lodash _.flowRight Works

The Lodash library provides two composition utilities: _.flow and _.flowRight. While _.flow executes functions from left to right (similar to a Unix pipe), _.flowRight mirrors traditional mathematical composition by executing functions from right to left.

When invoking _.flowRight(f, g, h), Lodash returns a new composed function. When this composed function receives an argument, Lodash runs h, passes its return value to g, and finally passes that return value to f.

const _ = require('lodash');

const addTwo = (n) => n + 2;
const multiplyByThree = (n) => n * 3;
const square = (n) => n * n;

// Traditional nested execution: square(multiplyByThree(addTwo(4)))
// Mathematical representation: (square ∘ multiplyByThree ∘ addTwo)(4)

const compute = _.flowRight(square, multiplyByThree, addTwo);

const result = compute(4); 
// Execution steps:
// 1. addTwo(4)          => 6
// 2. multiplyByThree(6) => 18
// 3. square(18)         => 324

console.log(result); // Output: 324

Argument Arity and Execution Rules

To accurately represent functional composition while maintaining JavaScript compatibility, _.flowRight follows specific rules regarding arguments:

  1. Initial Invocation Arity: The rightmost (first executed) function can accept multiple arguments (an arity of greater than or equal to 1). This allows the composed pipeline to begin with complex operations such as summing two numbers or merging objects.
  2. Subsequent Invocations: Every preceding function in the chain receives only a single argument—the return value of the function executed immediately before it.
const formatCurrency = (amount) => `$${amount.toFixed(2)}`;
const applyDiscount = (total) => total * 0.9;
const calculateSubtotal = (price, quantity) => price * quantity;

// calculateSubtotal is the rightmost function and accepts two arguments
const getFinalPrice = _.flowRight(
  formatCurrency,
  applyDiscount,
  calculateSubtotal
);

console.log(getFinalPrice(100, 2)); // Output: "$180.00"

Advantages Over Deep Nesting

In standard JavaScript, replicating \((f \circ g \circ h)(x)\) without a composition utility requires manual nesting:

const result = f(g(h(x)));

As the number of operations increases, deeply nested calls become difficult to read, maintain, and debug. They introduce visual noise via excessive parentheses and force developers to track data flow inside-out across a single line of code.

Using _.flowRight flattens this structure into a declarative definition. It creates reusable, point-free functions that describe what transformations occur rather than imperatively managing intermediate variables or nested syntax.