Composition: one function's output feeding the next

LLM-authored, human-reviewed

Foundations

You compose functions whenever you chain steps. “Double it, then add one” uses two functions: the first function’s output becomes the second function’s input. The compose_fn exercises in the functions exercises make that chain explicit. Track which function runs first. Everything else is substitution.

Composition is output feeding input

Composition plugs one function into another. If f(x) = x + 1 and g(x) = 2 * x, then f(g(x)) means “run g, then give its output to f.” Ronald Kneusel defines it as a mapping between sets: given f : S → T and g : T → U, the composition is

(g ∘ f)(s) = g(f(s))

Read this as “g of f of s.” The order matters. In g(f(s)), f runs first, and g receives f‘s result. The notation g ∘ f reads right-to-left. The rightmost function receives the original input.

The worked example contains the whole skill. With f(x) = x + 1 and g(x) = 2 * x, compute f(g(3)) by running the inner function g on 3 first:

g(3) = 2 * 3 = 6      then      f(6) = 6 + 1 = 7

So f(g(3)) = 7. Every compose exercise follows these two steps: resolve the inner function, then apply the outer function to that result. No new arithmetic. Substitute twice, in the right order.

Order matters: f(g(x)) is not g(f(x))

Composition is not commutative. Swap the order and you get a different function. With the same f and g:

f(g(x)) = f(2x) = 2x + 1        ("double, then add one")
g(f(x)) = g(x + 1) = 2(x + 1)   ("add one, then double")

These agree only by accident: at x = 1, both give 2. They are different functions. “Double then add one” and “add one then double” describe different machines. The compose exercises make you identify the function named in the prompt. The inner function runs first, so f(g(x)) always means g first.

Kneusel’s example shows the same point from the other direction. With f(x) = x - 3 and g(x) = x², the composition g(f(x)) is (x - 3)², which expands to x² - 6x + 9. But f(g(x)) is x² - 3. The same two functions produce two compositions and two results.

Composition in code: the pipe

Elixir’s pipe operator makes composition read left-to-right, in the order the data flows:

x |> g() |> f()

This is the same as f(g(x)). The data enters g first, then f, from left to right. That matches how you would say the steps aloud. JavaScript has no pipe, so nest the calls and read from the inner call outward:

const f = x => x + 1;
const g = x => 2 * x;
f(g(3));   // 7 - read g(3) first, then f(...)

Carry two more facts with you. Composition is associative: (h ∘ g) ∘ f and h ∘ (g ∘ f) are the same function. You can group a three-step chain either way without changing the answer (the code version: f(g(h(x))) and (f ∘ g)(h(x)) agree). There is also an identity function id(x) = x that changes nothing, so f ∘ id = f and id ∘ f = f. It is the “do nothing” step, and you can insert it anywhere without changing the result.

Why this matters here

The compose_fn skill connects “a function is a mapping” to “a function can be built from other functions.” That leads to higher-order functions and then to lambda calculus, where composition is the only way anything gets done: there are no numbers or built-ins, only functions wired to functions. When a lambda exercise asks you to reduce (λf. λg. λx. f (g x)) A B c, it asks you to evaluate a composition written as abstractions instead of named f and g.

Where to go next

← Back to articles