Reduction strategies

The rule that picks the next redex among all the redexes of a term is called a reduction strategy. Let us see where the choice arises. A term has one of three forms:

  • a variable xx — nothing to reduce;
  • an abstraction λx.M\lambda x.M — no choice: we reduce the body MM;
  • an application M NM\,N — redexes may sit both in the left part and in the right one; choosing between them is exactly what a strategy does.

Let us unfold an application: its left part may itself be an application, the left part of that one too, and so on. Descending along the left branches to the first non-application — the head of the term — we get one of two shapes:

(…((x N1) N2)…Nk),\displaystyle (\dots((x\,N_1)\,N_2)\dots N_k),(…(((λx.M) N1) N2)…Nk).\displaystyle (\dots(((\lambda x.M)\,N_1)\,N_2)\dots N_k).

In the first shape the head is a variable xx: there is nothing to contract on the left, redexes can hide only in the arguments NiN_i. In the second the head is an abstraction, and (λx.M) N1(\lambda x.M)\,N_1 is a redex; here is the fork: contract it right away or evaluate the argument first. This choice is what distinguishes the two classic strategies.

The normal strategy contracts the leftmost outermost redex — in our notation (λx.M) N1(\lambda x.M)\,N_1: arguments are substituted into the body unevaluated. The applicative strategy does the opposite: it first brings the argument of the redex to normal form and only then contracts the redex itself.

A term is conveniently drawn as a tree. For example, for ((λx.M) N1) N2((\lambda x.M)\,N_1)\,N_2 it looks like this (fig. 1.4): the @@ nodes are applications, the λx\lambda x node is an abstraction. The leftmost outermost redex is found on the tree by descending from the root along the left edges: it is the first @@ whose left child is an abstraction.

Tree of the term ((λx.M) N₁) N₂: two application nodes @ and an abstraction node λx; the lower @ is the leftmost outermost redex
Fig. 1.4. The tree of the term ((λx.M) N1) N2((\lambda x.M)\,N_1)\,N_2: the @@ nodes are applications, the λx\lambda x node is an abstraction; the red @@ is the leftmost outermost redex (λx.M) N1(\lambda x.M)\,N_1.

The same descent lets us introduce an important notion — the head normal form. Let us explain it with two examples:

λx1…xn. y N1…Nk,\displaystyle \lambda x_1\dots x_n.\,y\,N_1\dots N_k,​n,k\displaystyle n,k​≥0,\displaystyle {} \ge 0,λx1…xn. (λz.M) N1…Nk,\displaystyle \lambda x_1\dots x_n.\,(\lambda z.M)\,N_1\dots N_k,​n\displaystyle n​≥0, k\displaystyle {} \ge 0,\ k​>0.\displaystyle {} >0.

The first term is a head normal form: the descent along the left branches ends at the variable yy, called the head variable. The head of such a term will never change; redexes can hide only in the arguments NiN_i. The second term is not a head normal form: its head is the redex (λz.M) N1(\lambda z.M)\,N_1, called the head redex.

Let us state both strategies precisely, as rules of an operational semantics. As if we had not enough notions already — we need three more, three syntactic categories. The first is the non-abstraction NA\mathit{NA}:

NA::=x∣M N.\mathit{NA} \mathrel{\text{::=}} x \mid M\,N.

Here everything seems clear: it is any term except an abstraction. MM and NN are arbitrary terms, so a non-abstraction may well be a redex — for example (λy.y) z(\lambda y.y)\,z. The other two categories describe finished results: normal forms NF\mathit{NF} and their subclass, non-abstraction normal forms NANF\mathit{NANF}:

NF::=λx.NF∣NANF,\displaystyle \mathit{NF} \mathrel{\text{::=}} \lambda x.\mathit{NF} \mid \mathit{NANF},NANF::=x∣NANF NF.\displaystyle \mathit{NANF} \mathrel{\text{::=}} x \mid \mathit{NANF}\ \mathit{NF}.

The split is necessary: without it we could form an application with an abstraction on the left — and such a term is not a normal form any more, it is a redex. Examples of NF\mathit{NF}: λx. x\lambda x.\,x, λf.λx. f x\lambda f.\lambda x.\,f\,x. Examples of NANF\mathit{NANF}: xx, f xf\,x, x (λy.y) zx\,(\lambda y.y)\,z — and each of them is at the same time an NF\mathit{NF}.

Now, at last, the strategies. At the heart of each lies its own redex-contraction rule. The normal strategy uses ordinary β\beta-reduction: the redex is contracted right away, the argument NN is an arbitrary term and is substituted into the body unevaluated:

(λx.M) N\displaystyle (\lambda x.M)\,N →M[x ⁣:= ⁣N]\displaystyle {} \to M[x\!:=\!N]
(1.33)

The applicative strategy contracts a redex differently — only once the argument has been evaluated, that is, brought to normal form — to the left of the arrow stands an NF\mathit{NF}, and until the argument is one, contraction is forbidden:

(λx.M) NF\displaystyle (\lambda x.M)\,\mathit{NF} →M[x ⁣:= ⁣NF]\displaystyle {} \to M[x\!:=\!\mathit{NF}]
(1.34)

Since we cannot contract a redex while the argument is not in normal form, the applicative strategy has a rule for the argument:

N→N′(λx.M) N→(λx.M) N′\dfrac{N \to N'}{(\lambda x.M)\,N \to (\lambda x.M)\,N'}
(1.35)

The remaining rules are shared by the normal strategy and the applicative one:

NA→NA′NA N→NA′ N,\displaystyle \dfrac{\mathit{NA} \to \mathit{NA}'}{\mathit{NA}\,N \to \mathit{NA}'\,N},​N→N′NANF N→NANF N′,\displaystyle \dfrac{N \to N'}{\mathit{NANF}\,N \to \mathit{NANF}\,N'},​M→M′λx.M→λx.M′\displaystyle \dfrac{M \to M'}{\lambda x.M \to \lambda x.M'}
(1.36)

The first rule reduces the left part of an application while it remains a non-abstraction; the second moves on to the argument only when the left part is already a NANF\mathit{NANF}; the third takes reduction into the body of an abstraction. The categories NA\mathit{NA} and NANF\mathit{NANF} in the premises are exactly what guarantees the leftmost outermost order: while there is something to contract on the left, we do not look to the right.

The choice of the leftmost outermost redex is no accident: the normalization theorem (Curry) guarantees that if a term has a normal form, then successively contracting exactly such a redex will reach it. For this the normal strategy is called complete.

Completeness is not free: an argument substituted into several places has to be recomputed. For a “big” NN: (λx. F x (G x) x) N(\lambda x.\,F\,x\,(G\,x)\,x)\,N​→βF N (G N) N{} \to_\beta F\,N\,(G\,N)\,N — here NN has to be reduced three times — once per copy. The applicative strategy evaluates NN exactly once, but pays for this with completeness. Let K\mathrm{K}​≡λxy.x{} \equiv \lambda x y.x, I\mathrm{I}​≡λx.x{} \equiv \lambda x.x, and let Ω\Omega​≡(λx.x x) (λx.x x){} \equiv (\lambda x.x\,x)\,(\lambda x.x\,x) — a term with no normal form. The normal strategy computes K I Ω\mathrm{K}\,\mathrm{I}\,\Omega​↠βI{} \twoheadrightarrow_\beta \mathrm{I}, discarding Ω\Omega without a glance; the applicative one first takes on the argument Ω\Omega — and loops forever.

In programming languages the two strategies live under different names. The applicative one is the call-by-value of strict languages such as C: arguments first, then the application. The normal one underlies lazy languages such as Haskell: call-by-name.