Lambda Calculus · v1.1.0
2026-09-25 23:01:09
Everything built in this module comes from those two mechanisms alone.
Abstraction: replace a concrete part with a name, supplied later.
A cost for one price becomes a function of price.
The λ calculus keeps the operation and throws away the wrapping.
\[\langle expression \rangle ::= \langle name \rangle \mid \langle function \rangle \mid \langle application \rangle\]
\[\langle function \rangle ::= \lambda\langle name \rangle.\langle body \rangle\]
\[\lambda x.x \qquad \lambda first.\lambda second.first \qquad \lambda f.\lambda a.(f\ a)\]
\[ \begin{align} \langle application \rangle &::= (\langle function\ expr \rangle\ \langle argument\ expr \rangle) \end{align} \]
\[ \begin{align} &(\lambda x.x\ \lambda a.\lambda b.b) \end{align} \]
Occurrences of the bound variable in the body are replaced by:
Applicative order
the value of the argument
like Pascal’s call by value
Normal order
the unevaluated argument
like ALGOL 60’s call by name
All applications in this unit are evaluated in normal order.
\[\lambda x.x\]
Returns whatever argument it is applied to.
\[(\lambda x.x\ \lambda x.x) \Rightarrow \lambda x.x\]
The body is \(x\), so the argument comes back unchanged.
\[\lambda s.(s\ s)\]
Applies its argument to its argument.
\[(\lambda s.(s\ s)\ \lambda s.(s\ s)) \Rightarrow (\lambda s.(s\ s)\ \lambda s.(s\ s))\]
It reduces to itself, forever.
The unsolvability of halting, appearing here in a few characters.
\[\lambda func.\lambda arg.(func\ arg)\]
Returns a function that applies its first argument to its second.
\[ \begin{align} &((\lambda func.\lambda arg.(func\ arg)\ \lambda x.x)\ \lambda s.(s\ s)) \\ \Rightarrow\ &(\lambda x.x\ \lambda s.(s\ s)) \\ \Rightarrow\ &\lambda s.(s\ s) \end{align} \]
As a value, application can be passed and abstracted over.
Any sugared form compiles back to λ calculus before evaluation.
\[\text{def}\ \langle name \rangle = \langle function \rangle\]
A definition naming itself expands forever: no recursion this way.
\[(identity2\ identity) \Rightarrow \ldots \Rightarrow identity\]
Any argument reduces back to itself — the effect of identity.
Write every step; when a derivation stalls, check the bracketing first.
\[ \begin{align} &((select\_first\ identity)\ apply) \\ \Rightarrow\ &(\lambda second.identity\ apply) \\ \Rightarrow\ &identity \end{align} \]
The second argument is discarded; the body never mentions second.
\[ \begin{align} &((select\_second\ identity)\ apply) \\ \Rightarrow\ &(\lambda second.second\ apply) \\ \Rightarrow\ &apply \end{align} \]
first never appears in the body, so the first argument is lost.
select_first and the first argument comes backselect_second and the second does\[(make\_pair\ identity\ apply\ select\_first) \Rightarrow identity\] \[(make\_pair\ identity\ apply\ select\_second) \Rightarrow apply\]
Next unit’s true is exactly “select the first argument”.
In \(\lambda x.x\), \(x\) is bound. In \((f\ \lambda x.x)\), \(f\) is free.
In the body of \(\lambda f.(f\ \lambda f.f)\), which is \((f\ \lambda f.f)\):
The distinction is per occurrence, not per name.
\[ \begin{align} &((apply\ arg)\ boing) \\ \Rightarrow\ &(\lambda arg.(arg\ arg)\ boing) \\ \Rightarrow\ &(boing\ boing) \end{align} \]
arg is used as both a bound and a free variable name.
Rename the bound variable consistently:
\[ \begin{align} &((\lambda func.\lambda arg1.(func\ arg1)\ arg)\ boing) \\ \Rightarrow\ &(\lambda arg1.(arg\ arg1)\ boing) \\ \Rightarrow\ &(arg\ boing) \end{align} \]
A name clash: β reduction puts a free variable in the scope of a bound variable of the same name. α conversion renames to remove it.
A captured variable still reduces — to the wrong thing, silently.
\[\lambda\langle name \rangle.(\langle expression \rangle\ \langle name \rangle) \quad \equiv \quad \langle expression \rangle\]
\[ \begin{align} &(\lambda\langle name \rangle.(\langle expression \rangle\ \langle name \rangle)\ \langle argument \rangle) \\ \Rightarrow\ &(\langle expression \rangle\ \langle argument \rangle) \end{align} \]
The wrapper adds nothing: both give the same result.
β
substitutes an argument for a bound variable
the only one that computes
α
renames to prevent capture
changes no meaning
η
removes a redundant wrapper
changes no meaning
Everything is eventually a β reduction.
Nothing more is added to the language. Everything is built inside it.
Conditions, Booleans and Integers — the next unit in this module.
true and falseNOT, AND, OR, then the natural numbers, built inductively out of pairs