F2.06 · part 1 of 3
Capturing the environment
A closure captures the value of each variable as it stood when the function was defined — not a live link to the variable. Because Elixir bindings are immutable, that captured value never shifts underneath the function. The environment it carries is a fixed snapshot.
In languages with mutable variables, a closure capturing a loop variable is a classic trap: every closure ends up seeing the final value. Elixir sidesteps this. Rebinding a name creates a new binding; the closure still holds the value it captured. So a closure’s behaviour is settled the moment it is created.
Captured at definition
When a closure is created, it copies the values it needs. Rebind one of those names afterwards and the closure is unaffected — it kept the earlier value. Set the value at capture and the value it is rebound to, and the closure ignores the rebind.
Set both values.
- capture by value
- the closure stores the value at definition time, not a reference.
- lexical scope
- a function can see the variables in the block where it was written.
- immutability
- rebinding a name makes a new binding; the old value still exists.
- snapshot
- the captured environment is fixed once the closure is created.
rebinding x does not change the closure
F1.04 · immutability
Because values never mutate, a captured value stays exactly as it was.
Elixir
Rebinding x shadows the old binding; closures over it are untouched.
A closure freezes the values it captures. Later rebindings make new bindings and leave the closure’s snapshot intact.
Several variables at once
A closure can capture more than one variable. make_line captures a slope and an
intercept, returning a function of x that computes the line. Both captured values
ride along; the returned function needs only x.
Set the captured slope and intercept, then the input.
make_line captures slope and intercept
Idea
The environment is a snapshot of every captured variable, not only one.
F2.06.3 · currying
Capturing arguments one at a time is how currying is built.
One closure can hold several values. make_line bakes in slope and
intercept, leaving a clean function of x.
Worked examples
Function factories: each captures a value and returns a specialised function.