Lectures onType Theory
Chapter 2
Chapter 2Core route

Simple Types, Curry–Howard, Safety, and Normalization

Example 1.79 exhibited a closed term that is not a value and cannot take a step. In the language of booleans and functions, the application ttff, a constant in function position, has the same two properties. The evaluator can report the failure only after inspecting the application. The first task is therefore to define a finite static check that rejects ttff before execution and whose answer is preserved by every evaluation step.

A typed language of booleans and functions

Definition 2.1 — Simple types

Fix effective enumerations P0,P1, of atomic type constants and x0,x1, of variables. Equality of two indices, and hence equality of atomic constants and variables, is decidable. We continue to write P,Q, and x,y,z, when their numerical codes are irrelevant. The simple types are the expressions generated by the judgment A type below:

2 type
Ty-Bool
P type
Ty-Atom
A typeB type
AB type
Ty-Arr

Equivalently, as a grammar: A,B::=P2AB. The atomic constants are not type variables and admit no substitution. Types are finite trees whose atomic leaves carry decidable codes, so their constructors are disjoint and injective: AB=AB implies A=A and B=B, and an arrow type equals neither 2 nor an atomic type. Equality of these trees means equality of the root label and, recursively, of the ordered children. Hence an arrow has two uniquely determined children and cannot equal the nullary Boolean constructor. We write 2 for the two-element Boolean type and its values as tt and ff.

The rules already calculate a nontrivial type, the type of two-argument boolean operations:

2 type
Ty-Bool
2 type
Ty-Bool
2 type
Ty-Bool
22 type
Ty-Arr
2(22) type
Ty-Arr

As usual, associates to the right: 222 means 2(22). In a formation judgment, the whole expression to the left of type is its subject; thus AB type means (AB) type.

Definition 2.2 — Raw terms

Using the effective variable enumeration fixed above, raw terms are given by the grammar e::=xλx:A.ee1e2ttffif(e;e1;e2), where the abstraction λx:A.e binds x in e and A ranges over the types of definition 2.1. The free variables of a raw term are computed by structural recursion: FV(x)={x},FV(tt)=FV(ff)=,FV(e1e2)=FV(e1)FV(e2),FV(λx:A.e)=FV(e){x}, and FV(if(e;e1;e2))=FV(e)FV(e1)FV(e2). Write Names(e) for the finite set of every free or bound variable name in e, and BN(e) for its finite set of binder labels, using the constructor-wise clauses of definition 1.50. A term is closed when its free-variable set is empty.

The binding apparatus of chapter 1 was built for a grammar with one binding constructor: abstraction. It consists of fresh renaming, alpha-equivalence, and capture-avoiding substitution. Every proof proceeds constructor by constructor. For example, renaming in an application recurses in both subterms, while renaming under λx:A.e first chooses a representative with a fresh binder. Compared with definition 1.50, this grammar drops the arithmetic constructors 0, suc, and add, retains tt, ff, and if, and adds a type annotation to the binder. Binding ignores the annotation, and each retained nonbinding constructor recurses in its immediate subterms. These clauses give the six binding consequences recorded next.

Convention 2.3 — Terms, binding, and substitution

Unless “raw term” is stated explicitly, term means an alpha-equivalence class of raw terms, using the size-recursive common-opening definition of definition 1.53. A written raw expression is one representative of that class. We import from that construction, extended constructor-wise to the present grammar:

  1. fresh renaming ey/x on a raw representative, defined when yNames(e), with its free-variable, size, composition, and commutation equations;

  2. the alpha-invariants: alpha-equivalent terms have the same outer constructor, the same constructor count, the same free variables, and the same binder annotations. In particular, λx:A.b=αλy:B.c requires A=B and, for one common fresh z, bz/x=αcz/y;

  3. fresh representatives and common opening: for every finite set X, every raw term e has a representative eX with e=αeX, whose binder labels are pairwise distinct and satisfy BN(eX)X=; two alpha-equivalent abstractions have alpha-equivalent bodies after opening with any one name absent from both displayed raw representatives;

  4. a capture-avoiding substitution e[a/x], well defined on alpha-classes, satisfying x[a/x]=a,y[a/x]=y(yx),tt[a/x]=tt,ff[a/x]=ff,(e1e2)[a/x]=e1[a/x]e2[a/x],if(e;e1;e2)[a/x]=if(e[a/x];e1[a/x];e2[a/x]),(λy:B.b)[a/x]=λy:B.b[a/x],(λx:B.b)[a/x]=λx:B.b. The penultimate equation assumes yx and yFV(a). The same clause carries the free-variable equation: if xFV(e) then FV(e[a/x])=(FV(e){x})FV(a), and e[a/x]=e when xFV(e);

  5. substitution by a fresh variable agrees with fresh renaming: if zFV(e), choose a representative of e whose binders are fresh for z; then e[z/x]=ez/x.

  6. fresh renaming can be cancelled: if xz and zNames(e), then ez/x[x/z]=e. Indeed, the fresh-opening cancellation lemma of lemma 1.63, specialized to the variable x, gives the left side as e[x/x]; substitution clause (B4) makes the latter term e.

Here =α compares raw representatives, while ordinary equality compares their alpha-classes. Every term constructor obeys one of two substitution clauses: substitution is componentwise at a nonbinding argument, while a binding argument uses the fresh-binder clause (B4). Each extension of the term grammar states which arguments bind. Typing judgments have alpha-classes as subjects. A rule instance may use any representative whose binders are fresh for the terms being substituted; changing only those bound names changes neither the judgment nor its derivation. An algorithm recurses on one such raw representative and returns a judgment about its alpha-class.

Two calculations show the convention at work. Substitution passes through if componentwise, if(x;ff;x)[tt/x]=if(tt;ff;tt), while a binder equal to a free variable of the inserted term must first be freshened: for distinct x,y,z, (λy:2.x)[y/x]=freshenbinder(λz:2.x)[y/x]=substitutionclauseλz:2.y. Textual replacement without the renaming would produce λy:2.y and capture the inserted variable.

Exercise 2.1

★☆☆ Let x,y,z be distinct. Compute (λy:2.if(x;y;x))[if(y;tt;ff)/x] after alpha-renaming its binder fresh for the substituend, and mark every free occurrence of y in the result. Then compute (λx:2.x)[tt/x] and explain, from the equations of convention 2.3, why the answer is not λx:2.tt.

Definition 2.4 — Contexts

The judgment Γ ctx is inductively defined by

 ctx
Cx-Emp
Γ ctxA typexdom(Γ)
Γ,x:A ctx
Cx-Ext

The symbol denotes the empty context. A context is an ordered list of distinct declarations; Γ,x:A appends one declaration, and Γ1,Γ2 denotes list concatenation when the domains are disjoint. Thus an insertion between two declarations has a definite place, and the declaration introduced for a lambda body is the final one. We write dom(Γ) for the set of variables Γ declares and (x:A)Γ for the occurrence of the declaration x:A in Γ. Whenever we write Γ,x:A, the side condition xdom(Γ) is understood; in particular a context never declares a variable twice. A well-formed context Γ is a declaration-preserving extension of Γ when it is obtained from Γ by finitely many insertions of fresh declarations, without changing the order or type of any declaration already present. Zero insertions give reflexivity, and concatenating insertion sequences gives transitivity. If Γ extends Γ and xdom(Γ), then Γ,x:A extends Γ,x:A: perform the same insertions before the common final declaration.

For example, x:2,f:22 is a context. The freshness formulas printed above bars in this tree are metalevel checks on rule instances, not new judgment forms; the layout merely keeps each check beside the premise it restricts.

 ctx
Cx-Emp
2 typex
x:2 ctx
Cx-Ext
22 typefx
x:2,f:22 ctx
Cx-Ext

Definition 2.5 — Typing

The typing judgment Γe:A, for Γ ctx and A type, is inductively defined by

(x:A)Γ
Γx:A
Var
Γtt:2
True
Γff:2
False
Γe:2Γe1:CΓe2:C
Γif(e;e1;e2):C
If
Γ,x:Ae:B
Γλx:A.e:AB
Lam
Γe1:ABΓe2:A
Γe1e2:B
App

Rule instances range only over well-formed contexts and displayed types. In Lam, context formation requires xdom(Γ). Context membership and binder freshness are metalevel side conditions, not additional judgment forms. The premise of If types both branches by the same C because either branch may be the result. When the context is empty, we may abbreviate e:A by e:A; these are the same judgment.

The typing rules are the static counterpart of the evaluator: they inspect a program constructor by constructor without running it. We type the two boolean programs that will serve as test inputs throughout the chapter.

Example 2.6 — Negation

Let not:=λx:2.if(x;ff;tt). Then not:22:

(x:2)x:2
x:2x:2
Var
x:2ff:2
False
x:2tt:2
True
x:2if(x;ff;tt):2
If
λx:2.if(x;ff;tt):22
Lam

Example 2.7 — Conjunction

Let and:=λx:2.λy:2.if(x;y;ff) and Γ:=x:2,y:2. Reading upward, each abstraction extends the context by one declaration:

(x:2)Γ
Γx:2
Var
(y:2)Γ
Γy:2
Var
Γff:2
False
Γif(x;y;ff):2
If
x:2λy:2.if(x;y;ff):22
Lam
and:222
Lam

Exercise 2.2

★★☆ Define or:=λx:2.λy:2.if(x;tt;y) and exhibit its full typing derivation at 222, labeling every node with its rule. Then write a term xor of the same type whose if has another if in one branch, and type it.

We can now carry out the calculation promised at the head of the chapter: the search for a typing of the stuck term fails, and the failure is located at one specific premise. Any derivation of ttff:C would have to end

tt:ACff:A
ttff:C
App

for some type A. The right premise is derivable, with A=2, by False. The left premise is not derivable for any A: it demands an arrow type for tt, and the only rule that concludes a typing of the subject tt assigns it 2.

Proposition 2.8 — The stuck term is untypable

There are no Γ, C for which Γttff:C is derivable.

Proof of Proposition 2.8 — The stuck term is untypable

Proof. We inspect final rules, as in chapter 1. The subjects of the six typing rules have pairwise distinct outer constructors—a variable, an abstraction, an application, the two constants, and if—and by (B2) of convention 2.3 alpha-equivalence preserves the outer constructor. A derivation of Γttff:C therefore ends with App, whose first premise is Γtt:AC for some A. A derivation of that premise must end with the only rule whose subject is tt, namely True, whose conclusion type is 2. Since types are finite trees (definition 2.1), 2AC. So no derivation exists. ◻

The rejection required no execution: it is a finite failed search through rule instances. The search terminates here because the syntax determines the only possible final typing rule, and every recursive premise concerns a strict subterm. Thus final-rule inspection rejects the term without running it.

Exercise 2.3

★☆☆ Show by final-rule inspection that neither term if(λx:2.x;tt;ff)ff(λx:2.x) is typable in any context. For the conditional, locate the premise of If that fails. For the application, locate the premise of App that fails.

Renaming, weakening, and substitution

The typing rules contain no rule that inserts an unused declaration and no rule that replaces a variable by a term. Both operations are forced on us by the safety proof: when a β-step replaces a bound variable by an argument, the type of the contractum is computed by substituting one derivation into another, and substitution in turn needs weakening. We prove that both are admissible rules in the sense of chapter 1. Renaming comes first because it repairs a name collision that weakening creates.

Here is the collision. Suppose a typing derivation ends in Γ,z:B1b:B2Γλz:B1.b:B1B2Lam To insert x:A into Γ, we would like to insert it into the premise as well. If the displayed binder happens to be z=x, the proposed context declares x twice. We must first rename the binder. Renaming preserves the conclusion and does not increase derivation height. Weakening can therefore recurse on the smaller renamed premise even though it is not a literal subtree of the original derivation. We formalize this with complete induction on derivation height h(D) (chapter 1).

In a ground instance, let xy and start from x:2λy:2.x:22, and try to rename x to y. The captured term λy:2.y is wrong. Choose z{x,y} and first represent the subject as λz:2.x; renaming then gives y:2λz:2.y:22. This two-stage calculation is the abstraction case of lemma 2.9.

Lemma 2.9 — Renaming

Suppose D::Γ1,x:A,Γ2e:B with h(D)=h, and let x be a variable with xx and xdom(Γ1)dom(Γ2)FV(e). Then Γ1,x:A,Γ2e[x/x]:B has a derivation of height at most h.

Proof of Lemma 2.9 — Renaming

Proof. By complete induction on h, with cases on the final rule of D.

Case Var: e=y with (y:B)Γ1,x:A,Γ2. If y=x, then B=A because contexts declare distinct variables, e[x/x]=x, and Var concludes Γ1,x:A,Γ2x:A. If yx, then (y:B) occurs in Γ1 or Γ2, e[x/x]=y, and Var applies unchanged.

Cases True, False: the subject is a constant, unchanged by substitution, and the same axiom applies in the renamed context.

Case Lam: e=λz:B1.b and B=B1B2, with premise D::Γ1,x:A,Γ2,z:B1b:B2 of height h1; by context formation in the premise, zdom(Γ1){x}dom(Γ2).

If zx, the inductive hypothesis applies to D, renaming x to x; here xFV(b) because xFV(e)=FV(b){z} and xz. It yields Γ1,x:A,Γ2,z:B1b[x/x]:B2 at height at most h1, and Lam concludes, with λz:B1.b[x/x]=(λz:B1.b)[x/x] by the abstraction equation of convention 2.3 (zx, zx).

If z=x, choose z outside dom(Γ1)dom(Γ2){x,x} and outside the finite set of all variable names occurring in b. Two uses of the inductive hypothesis, both on derivations of height at most h1, transform the premise: Γ1,x:A,Γ2,z:B1b:B2Γ1,x:A,Γ2,z:B1b[z/z]:B2Γ1,x:A,Γ2,z:B1b[z/z][x/x]:B2. The first use freshens the binder. For the second, recall that x=z: by the free-variable equation in substitution clause (B4), FV(b[z/z])(FV(b){z}){z}, so x=z is not free in the renamed body, and the remaining freshness conditions follow from the choice of z and context formation. Rule Lam now concludes with subject λz:B1.b[z/z][x/x]. To identify this subject with (λz:B1.b)[x/x]: by fresh-substitution clause (B5) the substitution b[z/z] is the fresh renaming bz/z, so the common-opening clause (B3) gives λz:B1.b=λz:B1.bz/z as terms; substituting x for x on both displays—the right display is clean, since z{x,x} and zFV(x)—and using the abstraction equation of substitution clause (B4) on the right yields exactly the displayed subject.

Cases If, App: apply the inductive hypothesis to every premise derivation, each of height at most h1 and with the same decomposition of the context, and re-apply the rule. Substitution commutes with both constructors by substitution clause (B4), so the re-applied rule has the required subject e[x/x]. ◻

Exercise 2.4

★★☆ Carry out lemma 2.9 on the derivation of x:2if(x;x;ff):2, renaming x to y: display the resulting derivation node by node. Then apply the lemma to the premise of example 2.6 with x= a fresh u and confirm that the conclusion of Lam denotes the same alpha-class as the original abstraction, even though its premise is displayed with binder u.

Corollary 2.10 — Opening an abstraction

Suppose Γλx:A.b:C is derivable, and choose z distinct from x, outside dom(Γ), and occurring nowhere in b. Then C=AB for some B, and Γ,z:Abz/x:B is derivable. Thus the typing of an abstraction does not depend on the bound name used to display it.

Proof of Corollary 2.10 — Opening an abstraction

Proof. The final rule must be Lam, since by alpha-invariance clause (B2) alpha-equivalence preserves the outer constructor and the annotation. The derivation may, however, end with another display λy:A.c of the same term, giving a premise Γ,y:Ac:B and the conclusion type AB. We cannot assume the requested z fresh for the hidden body c. Choose w outside the finite set {x,y,z}dom(Γ)Names(b)Names(c).

Renaming the premise from y to w (lemma 2.9) gives Γ,w:Ac[w/y]:B, and c[w/y]=cw/y by fresh-substitution clause (B5). Common-opening clause (B3), applied to the equality of terms λx:A.b=λy:A.c, gives cw/y=bw/x. Now rename once more, from w to z: the target z is absent from the opened body because it is absent from b and distinct from w, so lemma 2.9 and fresh-substitution clause (B5) give Γ,z:Abw/xz/w:B, and the fresh-renaming composition equation (B1) computes bw/xz/w=bz/x. ◻

Corollary 2.11 — Typing respects alpha-equivalence

If raw terms e and e are alpha-equivalent, then Γe:A is derivable if and only if Γe:A is. Moreover the premise derivations of two displays of one abstraction can be opened with a single common fresh binder.

Proof of Corollary 2.11 — Typing respects alpha-equivalence

Proof. The subjects denote the same term under convention 2.3, so the same derivation tree serves for both; the second assertion is corollary 2.10 applied to each display, followed by the common-opening clause (B3) of the two premise subjects. ◻

Convention 2.12 — Fresh binders in displays

By the fresh-representative clause (B3) and corollary 2.11, every statement and proof uses representatives whose bound names are mutually distinct, absent from the variables declared in the ambient contexts, and absent from the free variables of the other terms under discussion, except when a collision is itself the object of the calculation.

Lemma 2.13 — Scope

If Γe:A, then FV(e)dom(Γ).

Proof of Lemma 2.13 — Scope

Proof. By induction on the displayed typing derivation. The Var case is context membership. Constants have no free variables. The application and conditional cases follow by taking unions and applying the induction hypotheses. In the abstraction case the induction hypothesis gives FV(b)dom(Γ){x}; deleting the bound name x leaves FV(λx:A.b)dom(Γ). ◻

Weakening permits insertion at any well-formed position in a context.

Lemma 2.14 — Weakening

Suppose Γ1,Γ2e:B and Γ1,x:A,Γ2 ctx. Then Γ1,x:A,Γ2e:B.

Proof of Lemma 2.14 — Weakening

Proof. Use complete induction on the height of the given typing derivation. The variable case follows because the original declaration remains in Γ1,x:A,Γ2. Constants require no premises. For App and If, weaken each premise and reapply its final rule.

Suppose the last rule is Γ1,Γ2,z:Cb:DΓ1,Γ2λz:C.b:CDLam. Choose w outside the finite set FV(b)dom(Γ1,x:A,Γ2){z}. By convention 2.12, lemma 2.9, alpha-renaming the binder transports the premise, without increasing its height, to Γ1,Γ2,w:Cbw/z:D. The induction hypothesis inserts x:A before Γ2 in this smaller premise. Rule Lam yields λw:C.bw/z:CD under the enlarged context; this term is alpha-equivalent to the displayed conclusion. ◻

Corollary 2.15 — Weakening by a telescope

If Γe:B and Γ,Δ ctx, then Γ,Δe:B.

Proof of Corollary 2.15 — Weakening by a telescope

Proof. Induct on the length of Δ, applying lemma 2.14 at the end of the context at each step. ◻

Theorem 2.16 — Substitution

Suppose Γ1,x:A,Γ2e:BandΓ1,Γ2a:A. Then Γ1,Γ2e[a/x]:B.

Proof of Theorem 2.16 — Substitution

Proof. Induct on the first derivation, keeping the displayed context split in the induction assertion. In the Var case the subject is a variable y. If y=x, context uniqueness gives B=A, and the second hypothesis is the desired conclusion. If yx, then (y:B) remains in Γ1,Γ2, substitution leaves y unchanged, and Var applies. The constants are unchanged. The App and If cases follow by applying the induction hypotheses to all premises and rebuilding the final rule.

For Lam, use convention 2.12 to write its subject as λy:C.b with yx and yFV(a). Its premise is Γ1,x:A,Γ2,y:Cb:D. Weakening the second hypothesis at the end gives Γ1,Γ2,y:Ca:A. The induction hypothesis, with Γ2,y:C as the right part of the split, gives Γ1,Γ2,y:Cb[a/x]:D. Rule Lam concludes Γ1,Γ2λy:C.b[a/x]:CD. Substitution clause (B4) gives λy:C.b[a/x]=α(λy:C.b)[a/x], so the derived subject is the required substitution. ◻

Example 2.17 — Substituting a derivation

Let b=if(x;ff;tt) and a=if(tt;ff;tt). We have x:2b:2 and a:2. Substitution therefore derives if(if(tt;ff;tt);ff;tt):2. At the unique Var leaf for x, the entire derivation of a is inserted; all other rule nodes are copied. Thus substitution on terms is the visible trace of substitution on derivation trees.

Exercise 2.5

★★☆ Write the two premise derivations and the resulting derivation tree for (λy:2.if(x;y;ff))[if(tt;ff;tt)/x]. Point to the weakening step used to type the inserted term under y:2.

Reading typing derivations backward

The structural lemmas transform derivations. Safety also requires information in the opposite direction: the outer form of a term tells us what the final rule of any typing derivation must have been.

Lemma 2.18 — Inversion

The following implications hold.

  1. If Γx:A, then (x:A)Γ.

  2. If Γλx:C.b:A, then A=CD for some D. For every z outside the finite set dom(Γ)FV(b){x}, Γ,z:Cbz/x:D.

  3. If Γe1e2:B, then for some A, Γe1:AB and Γe2:A.

  4. If Γif(e;e1;e2):C, then Γe:2 and Γe1:C and Γe2:C.

  5. If Γtt:A or Γff:A, then A=2.

Proof of Lemma 2.18 — Inversion

Proof. Inspect the final rule. By the alpha-invariants (B2), its subject has the same outer constructor as the displayed subject, so exactly the matching typing rule is possible. Read off that rule’s premises and result type. The abstraction premise is put under the requested displayed binder by corollary 2.10. ◻

Lemma 2.19 — Uniqueness of types

If Γe:A and Γe:B, then A=B.

Proof of Lemma 2.19 — Uniqueness of types

Proof. Use complete induction on the constructor count of a representative of e whose binders are fresh for Γ, using lemma 2.18 on both derivations. A variable has one declaration in a well-formed context. Both constants have type 2. For an abstraction, inversion gives A=CA and B=CB and two typings of the same opened body; the induction hypothesis gives A=B. For an application, inversion gives Γe1:CA and Γe1:DB; the induction hypothesis for e1 gives CA=DB, hence A=B by injectivity of the arrow constructor. For a conditional, either branch has both result types, so its induction hypothesis gives A=B. ◻

Proposition 2.20 — Type synthesis

There is an algorithm which, given a finite well-formed context Γ and a finite raw representative e, either returns the unique type of its alpha-class and a derivation of Γe:A, or correctly reports that no such type exists.

Proof of Proposition 2.20 — Type synthesis

Proof. First clean the input’s binders from dom(Γ), processing sibling subterms from left to right as in lemma 1.56. At each binder choose the least variable code outside the ambient avoidance set, the names of its body, and the old binder; after cleaning a subterm, add its new binder names to the avoidance set used for later siblings. The effective enumeration and decidable equality make every such finite-set choice deterministic. Recurse on the cleaned syntax. A variable succeeds exactly when it has a context declaration. The constants return 2. For λx:A.b, first check A type and synthesize B for b under Γ,x:A; return AB. For e1e2, synthesize both types, require the first to be AB and the second to equal A, and return B. For a conditional, require the guard’s synthesized type to be 2 and the two branch types to be equal; return their common type. Every recursive call is on an immediate subterm, so structural recursion on the finite raw input terminates. Context membership is decidable because a context is a finite list with decidable variable equality. Type equality is decidable by recursion on the two finite type trees, using decidable equality of their atomic codes.

Each successful clause builds the corresponding typing rule, proving soundness. Conversely, lemma 2.18 says that any derivation has exactly the premises tested by its constructor’s clause; structural induction on e therefore proves completeness. Uniqueness is lemma 2.19. Finally, let e1 and e2 be two raw representatives of the same term. Soundness makes every successful result a typing of their common alpha-class, and completeness makes success or failure the same for both. When both succeed, uniqueness gives the same result type. Thus the returned judgment is independent of the supplied representative, although its displayed derivation may use the deterministic cleaned names. ◻

Dynamics and safety

The evaluator is call-by-value. Function position is evaluated before argument position; a beta-redex fires only when its argument is a value.

Definition 2.21 — Values and one-step evaluation

Values, the completed results of evaluation, and the one-step relation ee are generated by v::=ttffλx:A.e and the rules

e1e1
e1e2e1e2
E-AppL
v1 valuee2e2
v1e2v1e2
E-AppR
v value
(λx:A.b)vb[v/x]
E-Beta
ee
if(e;e1;e2)if(e;e1;e2)
E-If
if(tt;e1;e2)e1
E-True
if(ff;e1;e2)e2
E-False

The many-step relation is generated by

ee
M-Refl
ee1e1e2
ee2
M-Step

Here v ranges over the displayed value grammar, and v value is the corresponding grammar-membership judgment. Writing that premise explicitly in both E-AppR and E-Beta avoids making the evaluation order depend on a metavariable letter. After erasing lambda annotations, this presentation is equivalent to the boolean-and-function part of the value rules of definition 1.61; the numeral alternatives were removed with the arithmetic fragment at the chapter boundary. We use the shorter grammar because it has only three alternatives. In the Boolean-and-function fragment, E-AppL and E-AppR restrict chapter 1’s E-App-L and E-App-R; E-True and E-False restrict E-If-T and E-If-F. Likewise, v value restricts that chapter’s v val to functions and booleans.

For example, with not from example 2.6, not(if(ff;ff;tt))EFalse/EAppRnotttEBetaif(tt;ff;tt)ETrueff. The value restriction on E-Beta fixes this order.

Lemma 2.22 — Canonical forms

Let v be a closed value.

  1. If v:2, then v is tt or ff.

  2. If v:AB, then v=λx:A.b for some x,b.

Proof of Lemma 2.22 — Canonical forms

Proof. There are three value forms. Inversion assigns 2 to the two constants and an arrow type to an abstraction. Disjointness of the type constructors excludes the other forms in each clause; arrow injectivity equates the abstraction’s domain annotation with the displayed domain in the second. ◻

Theorem 2.23 — Preservation

If Γe:A and ee, then Γe:A.

Proof of Theorem 2.23 — Preservation

Proof. Induct on the evaluation derivation.

For E-AppL, inversion of the typing of e1e2 gives Γe1:BA and Γe2:B. Apply the induction hypothesis to the first premise and rebuild App. The E-AppR case is the same with the second premise.

For E-Beta, inversion first gives Γλx:B.b:BA and Γv:B; abstraction inversion gives Γ,x:Bb:A. The substitution theorem yields Γb[v/x]:A.

For E-If, inversion gives Γe:2, Γb:A, and Γc:A; apply the induction hypothesis to the guard and rebuild If. In the E-True and E-False cases, inversion says respectively that the selected first or second branch already has the result type. ◻

Theorem 2.24 — Progress

If e:A, then either e is a value or there exists e with ee.

Proof of Theorem 2.24 — Progress

Proof. Induct on the typing derivation with the property “if its context is empty, then its subject is a value or takes a step.” Variables cannot occur when the context is empty. Constants and abstractions are values; in particular, the Lam case does not use its induction hypothesis because an abstraction is already a value. For an application e1e2, the induction hypothesis for e1 either gives an E-AppL step or says e1 is a value. In the latter case, the induction hypothesis for e2 either gives an E-AppR step or says e2 is a value. By lemma 2.13, the typing in the empty context makes e1 closed. Now e1 is a closed value of arrow type, so canonical forms writes it as an abstraction; E-Beta applies.

For if(e;e1;e2), a step of e gives E-If. Otherwise e is a closed value of type 2, hence is tt or ff by canonical forms, and E-True or E-False applies. ◻

Corollary 2.25 — Type safety

If e:A and ee, then e is not stuck. Equivalently, it is a value or it can take another step.

Proof of Corollary 2.25 — Type safety

Proof. First prove by induction on the displayed many-step derivation the strengthened assertion e:A  eee:A. The M-Refl case uses the given typing. In the M-Step case, preservation types the one-step target, and the induction hypothesis types the final endpoint. Progress applied to e:A gives the result. ◻

Safety says that evaluation does not go wrong. It does not yet say that evaluation ends. A well-typed language can be safe and still contain a well-typed looping construct; normalization will require a different proof.

Exercise 2.6

★★☆ Write the complete preservation proof for the three conditional evaluation rules as three displayed derivation transformations. In the congruence case show every premise of the rebuilt If rule.

Products, sums, truth, and falsity

Functions and booleans suffice to state safety, but they cannot package two results, distinguish two alternatives carrying different payload types, or express a type with exactly one or no constructor values. We therefore add four type constructors. A product packages two results; a sum marks which of two alternatives was chosen; 1 has one canonical inhabitant, meaning one constructor value of that type; and 0 has none. A term of a type is also called an inhabitant of it. Rules that build a value of a connective are its introduction rules; rules that inspect or use such a value are its elimination rules.

Definition 2.26 — The propositional extension

Extend types and terms by A,B::=A×B,e::=(e1,e2)fst(e)snd(e). The formation, introduction, and elimination rules are

A typeB type
A×B type
Ty-Prod
Γe1:AΓe2:B
Γ(e1,e2):A×B
Pair
Γe:A×B
Γfst(e):A
Fst
Γe:A×B
Γsnd(e):B
Snd

A pair is a value exactly when both components are values. Its left-to-right evaluation and the two projection contractions are generated by

e1e1
(e1,e2)(e1,e2)
E-PairL
v1 valuee2e2
(v1,e2)(v1,e2)
E-PairR
ee
fst(e)fst(e)
E-Fst
v1 valuev2 value
fst((v1,v2))v1
E-Fst-Pair
ee
snd(e)snd(e)
E-Snd
v1 valuev2 value
snd((v1,v2))v2
E-Snd-Pair

Fresh renaming is componentwise, and substitution satisfies (e1,e2)[a/z]=(e1[a/z],e2[a/z]),fst(e)[a/z]=fst(e[a/z]),snd(e)[a/z]=snd(e[a/z]). The name and binder-label sets take unions over the displayed arguments. The equation (fst(p),snd(p))=p would remove a pair constructor placed immediately around the two projections of p. Such an equation is called a product eta contraction; it is not a reduction rule of this calculus.

The term inspected by a projection is its scrutinee. The first projection computes immediately, while one with a variable scrutinee remains stuck: fst((tt,ff))EFstPairtt,fst(x) has no step.

Example 2.27 — A product program

The term swapA,B:=λp:A×B.(snd(p),fst(p)) has type (A×B)(B×A). The body derivation is

(p:A×B)(p:A×B)
p:A×Bp:A×B
Var
p:A×Bsnd(p):B
Snd
(p:A×B)(p:A×B)
p:A×Bp:A×B
Var
p:A×Bfst(p):A
Fst
p:A×B(snd(p),fst(p)):B×A
Pair

One application of Lam derives the advertised type.

Definition 2.28 — Sum types

Extend types and terms by A,B::=A+B,e::=inl(e)inr(e)case(e;x.e1;y.e2). The notation x.e1 marks x as bound in the left branch body, and y.e2 marks y as bound in the right branch body. The formation, introduction, and elimination rules are

A typeB type
A+B type
Ty-Sum
Γe:AB type
Γinl(e):A+B
Inl
A typeΓe:B
Γinr(e):A+B
Inr
Γe:A+BΓ,x:Ae1:CΓ,y:Be2:C
Γcase(e;x.e1;y.e2):C
Case

The unused summand is printed as a formation premise in each introduction rule because the payload cannot determine it. A left or right injection is a value exactly when its payload is a value. Evaluation uses

ee
inl(e)inl(e)
E-Inl
ee
inr(e)inr(e)
E-Inr
ee
case(e;x.e1;y.e2)case(e;x.e1;y.e2)
E-Case
v value
case(inl(v);x.e1;y.e2)e1[v/x]
E-Case-L
v value
case(inr(v);x.e1;y.e2)e2[v/y]
E-Case-R

Fresh renaming and substitution are componentwise on injections. For a case, choose x and then y outside Names(a)Names(e1)Names(e2){x,y,z}, with xy. Rename the two branch binders independently and define case(e;x.e1;y.e2)[a/z]=case(e[a/z];x.e1[x/x][a/z];y.e2[y/y][a/z]). Two permitted choices give the same alpha-class. Open both left branches at one common fresh name and both right branches at a second common fresh name. Structural induction on the two branch bodies identifies the opened results; the definition of alpha-equivalence for each binding argument then identifies the two case terms. Thus this definition is independent of the displayed branch labels. For name bookkeeping, Names(case(e;x.e1;y.e2)) is the union of the three body name sets with {x,y}; its binder-label set adds x,y to the three body binder-label sets. Injections retain the two sets of their payloads.

Example 2.28 — Eliminating a sum

For arbitrary types A,B, define tagA,B:=λs:A+B.case(s;x.tt;y.ff). The two branch derivations use True and False under their extended contexts, so Case types the body by 2 and Lam gives tagA,B:(A+B)2. This is a genuine elimination: the program is allowed to inspect which introduction rule built its argument. The body derivation is

s:A+Bs:A+B
s:A+Bs:A+B
Var
s:A+B,x:Att:2
True
s:A+B,y:Bff:2
False
s:A+Bcase(s;x.tt;y.ff):2
Case

For values a:A and b:B, the two computation clauses are visible in the complete traces tagA,Binl(a)case(inl(a);x.tt;y.ff)tt,tagA,Binr(b)case(inr(b);x.tt;y.ff)ff.

Definition 2.30 — Unit

Extend types by 1, terms by , and the rules by

1 type
Ty-Unit
Γ:1
Unit-I

The constructor is a value and substitution leaves it fixed. The name and binder-label sets of are empty. The display itself is a complete constructor derivation in every well-formed context. By final-rule inspection, every closed value of type 1 is ; Unit has no eliminator or root contraction in this calculus.

Exercise 2.7

★☆☆ Let Γ=x:A be well formed. Display the derivation of Γ:1, and use final-rule inspection to show that a closed value v:1 cannot be a lambda, Boolean, pair, or injection.

Definition 2.31 — Void

Extend types by 0, terms by abortC(e), and the rules by

0 type
Ty-Empty
Γe:0C type
ΓabortC(e):C
Empty-E
ee
abortC(e)abortC(e)
E-Abort

The result annotation makes the eliminator syntax directed. There is no Void constructor, no value of type 0, and no root contraction for abort. The following open stuck term has the exact derivation

(x:0)(x:0)
x:0x:0
Var
2 type
x:0abort2(x):2
Empty-E

It is not a value and cannot step because its variable argument cannot step. Substitution satisfies abortC(e)[a/z]=abortC(e[a/z]). Abort retains the name and binder-label sets of its argument.

Exercise 2.8

★☆☆ For a formed type A, derive x:0,y:AabortA×2(x):A×2. Explain from the displayed dynamics why the open term has neither a root step nor value status.

Finite algebraic data now require no new metatheory. For instance, set Color:=1+(1+1),red:=inl(),amber:=inr(inl()),green:=inr(inr()). A three-way case analysis is two nested Case rules. Thus a finite list of constructors is represented by a nested sum of copies of 1; a constructor with several fields uses a product in its summand.

Exercise 2.7

★★☆ Write next:ColorColor sending red to green, green to amber, and amber to red. Give its typing derivation and calculate the reductions of nextred, nextamber, and nextgreen to constructor values.

Definition 2.32 — Injection-free terms

The injection-free terms are generated recursively by i::=xλx:A.ii1i2ttffif(i0;i1;i2)(i1,i2)fst(i)snd(i)case(i0;x.i1;y.i2)abortA(i). Thus neither inl(e) nor inr(e) may occur at any depth. In particular, a lambda is injection free exactly when its body is injection free, and a case is injection free exactly when its scrutinee and both branch bodies are injection free.

Proposition 2.29 — Structural metatheory survives the extension

For the extended grammar the following statements hold.

  1. If Γe:A, then FV(e)dom(Γ).

  2. If Γe:A and Γ is a declaration-preserving extension of Γ, then Γe:A.

  3. If Γ1,z:D,Γ2e:A and Γ1,Γ2a:D, then Γ1,Γ2e[a/z]:A.

  4. Typing inversion has exactly the premises displayed in definition 2.26, definition 2.28, definition 2.30, definition 2.31; for Case, inversion gives a type A+B for the scrutinee and branch typings at the same C under x:A and y:B.

  5. Types are unique and synthesis is defined for the injection-free terms of definition 2.32. Given an expected type A+B, checking inl(e) reduces to checking e at A, and checking inr(e) reduces to checking e at B.

Uniqueness and synthesis do not extend to unannotated injections: inl(tt):2+1andinl(tt):2+0. An injection can instead be checked against a given sum type.

Proof of Proposition 2.29 — Structural metatheory survives the extension

Proof. For item 1, induction on typing adds eight rule families. Pair takes the union of the two induction-hypothesis inclusions; projections, injections, and abort retain the inclusion of their premise; Unit-I has empty free-variable set. For Case, the induction hypotheses give FV(e)dom(Γ),FV(e1){x}dom(Γ),FV(e2){y}dom(Γ), which is precisely the free-variable clause for the case expression.

For item 2, first prove the one-insertion assertion Γ1,Γ2e:AΓ1,w:E,Γ2e:A whenever the enlarged context is well formed. Induct on the displayed extended typing derivation while retaining the insertion position Γ1Γ2. A variable keeps its declaration. The two Boolean constants and Unit-I have no term premises. Rules App and If, and every nonbinding added constructor, receive the induction hypothesis at each term premise and are rebuilt by their typing rules.

For Lam, display the binder x fresh for the enlarged context. If the last rule is Γ1,Γ2,x:Be0:CΓ1,Γ2λx:B.e0:BCLam, the induction hypothesis with right suffix Γ2,x:B gives Γ1,w:E,Γ2,x:Be0:C. Rule Lam then gives Γ1,w:E,Γ2λx:B.e0:BC. For Case, display both branch binders fresh for the enlarged context. Apply the induction hypothesis to the scrutinee at the original split, to the left branch at right suffix Γ2,x:B, and to the right branch at right suffix Γ2,y:C; then rebuild Case. This proves one insertion for every extended rule. Induction on the finite insertion sequence proves item 2.

For item 3, induct on the first derivation while retaining the arbitrary split Γ1,z:D,Γ2. In the variable case, the subject is z, or its declaration remains in Γ1,Γ2. Constants are unchanged. Every nonbinding constructor receives the induction hypothesis at each term premise and is rebuilt by the same typing rule.

For Lam, display its binder x outside FV(a)dom(Γ1,z:D,Γ2). Its last rule is Γ1,z:D,Γ2,x:Be0:CΓ1,z:D,Γ2λx:B.e0:BCLam. Item 2 types a under Γ1,Γ2,x:B; the induction hypothesis with right suffix Γ2,x:B gives the premise of Γ1,Γ2,x:Be0[a/z]:CΓ1,Γ2λx:B.e0[a/z]:BCLam. Because xFV(a), the right conclusion is the substitution of the left conclusion.

For Case, display distinct binders x,y outside the same set and each other. The final rule has the form Γ1,z:D,Γ2s:B+CΓ1,z:D,Γ2,x:Be1:FΓ1,z:D,Γ2,y:Ce2:FΓ1,z:D,Γ2case(s;x.e1;y.e2):FCase. Item 2 types a under both branch contexts without z:D. The three induction hypotheses, using right suffixes Γ2, Γ2,x:B, and Γ2,y:C, give Γ1,Γ2case(s[a/z];x.e1[a/z];y.e2[a/z]):F. Because x,yFV(a), this subject is the capture-avoiding substitution specified in definition 2.28.

For item 4, inspect the final rule. Outer constructors are disjoint, so a pair ends only in Pair, a projection in its corresponding projection rule, a unit term in Unit-I, an injection in its corresponding introduction, a case in Case, and an abort in Empty-E. Reading the premises gives the asserted clauses, including the formed unused summand of an injection and the formed result type of abort.

For uniqueness in item 5, induct on the first typing derivation and invert the second. Pair uses both induction hypotheses and injectivity of ×. Fst and Snd use uniqueness of the premise product, then its selected component. Case uses uniqueness on the scrutinee to identify the summands and on a branch to identify the common result type. Unit-I has result 1, while Empty-E obtains its result from the syntax annotation abortC. For synthesis, recurse on the grammar of definition 2.32. Each constructor uses the corresponding inversion clause: a case first synthesizes a sum type for its scrutinee and then synthesizes both branches in the contexts determined by those summands. Because the grammar excludes injections at every depth, no recursive call encounters an introduction whose unused summand is unknown.

For an injection, however, its payload determines only one summand. The two displayed judgments are derived by Inl with different choices of the unused summand, so their result types are unequal. Thus there is no unique type for a synthesis algorithm to return. If checking starts with expected type A+B, inversion of Inl says exactly that its payload checks at A; rebuilding Inl, with formed type B, proves soundness. Inversion and rebuilding Inr give the corresponding equivalence at B. In either case the conclusion retains both summands, although the payload determines only the selected one. ◻

Definition 2.30 — Extended values and computation

The extended value judgment is generated by the three core value rules and the four additional forms , (v1,v2), inl(v), and inr(v), with the displayed components required to be values. The extended step relation is generated by the core rules together with the six product rules of definition 2.26, five sum rules of definition 2.28, and the abort congruence of definition 2.31: exactly twelve new rules. These rules evaluate constructor arguments from left to right. More generally, an eliminator inspects its scrutinee to select an elimination clause. Abort has no root contraction.

The same stuck boundary holds for a case whose scrutinee is a variable: the open term has no step until a value injection is substituted for that variable.

Lemma 2.35 — Extended canonical forms

If v is a closed well-typed value, then type of vform of vA×B(v1,v2) with v1:A and v2:BA+Binl(v1) with v1:A, or inr(v2) with v2:B10no form.

Proof of Lemma 2.35 — Extended canonical forms

Proof. Inspect the four extended value forms and invert their typing derivations. Disjointness of ×,+,1,0 removes all rows except the one named by the result type. By product and sum inversion, the payloads have the displayed types. No value-typing rule concludes at 0, proving the last row. ◻

Theorem 2.31 — Safety for the propositional extension

The extended language satisfies preservation and progress. Consequently, the type-safety conclusion of corollary 2.25 remains valid.

Proof of Theorem 2.31 — Safety for the propositional extension

Proof. For preservation, induct on the displayed evaluation step. The congruence rules E-PairL and E-PairR invert Pair, apply the induction hypothesis to the changed component, and rebuild Pair; the value premise of E-PairR is retained. Rules E-Fst, E-Snd, E-Inl, E-Inr, and E-Abort perform the same three operations with their respective typing rules. E-Case inverts Case, changes only the scrutinee premise by the induction hypothesis, and rebuilds Case with the two unchanged branch premises.

For E-Fst-Pair, inversion first gives Γ(v1,v2):A×B and then Γv1:A, the type of the reduct. The E-Snd-Pair case uses the second premise of the same Pair inversion and concludes Γv2:B. For E-Case-L, inversion of the source typing gives Γinl(v):A+B,Γ,x:Ae1:C,Γ,y:Be2:C. Inverting the first judgment gives Γv:A; substitution gives Γe1[v/x]:C. For E-Case-R, inversion instead gives Γv:B and the right branch Γ,y:Be2:C; substitution concludes Γe2[v/y]:C. These are all twelve new rules.

For progress, induct on the typing derivation. In Pair, apply the left induction hypothesis; a step gives E-PairL. If the left component is a value, apply the right hypothesis; a step gives E-PairR, and two values make the pair a value. In Inl and Inr, a payload step lifts by the corresponding congruence rule and a payload value makes an injection value. The unit introduction is a value.

For Fst and Snd, a scrutinee step lifts by the matching congruence rule. Otherwise the scrutinee is a closed product value, so lemma 2.35 makes it a pair of values and the matching projection contraction applies. In Case, a scrutinee step gives E-Case; otherwise the closed sum value is a left or right injection by extended canonical forms, so E-Case-L or E-Case-R applies. In Empty-E, the scrutinee induction hypothesis gives a step or a value. The first lifts by E-Abort; the second contradicts the 0 row of extended canonical forms. The core typing rules retain the proof of theorem 2.24.

Finally, induction on a many-step derivation iterates preservation; progress at the endpoint proves the stated safety conclusion. ◻

Exercise 2.8

★★☆ Prove preservation for the right sum contraction, showing the inversion and substitution derivations explicitly. Then prove the congruence case in which the scrutinee of a case expression takes a step.

Call-by-value and call-by-name

Typing does not choose an evaluation order. Our safety theorem used call-by-value because E-AppR evaluates the argument and E-Beta requires a value. To see the alternative without overloading the typed metatheory, return briefly to the untyped lambda terms of chapter 1.

Definition 2.32 — Call-by-name

Call-by-name evaluation uses contexts F::=[]Feif(F;e1;e2) and contracts (λx.b)a to b[a/x] without first evaluating a. Boolean case contractions are unchanged. Write n for this relation and v for the call-by-value relation of definition 2.21 after the structural erasure erase(x)=x,erase(λx:A.b)=λx.erase(b),erase(e1e2)=erase(e1)erase(e2), extended identically through booleans and conditionals. Thus both relations act on the same erased Boolean-and-function grammar.

On the terminating term t:=(λx.tt)((λy.y)ff) the two strategies reveal their order: tv(λx.tt)ffvtt,tntt. Call-by-name does not evaluate an argument that the body discards.

Now let Ω:=(λz.zz)(λz.zz). This is the application ωω from exercise 1.17, where the earlier lowercase ω=λx.xx named only the abstraction; uppercase Ω names the complete looping application. Its unique beta contraction reproduces Ω. Consequently (λx.tt)Ωntt,(λx.tt)Ωv(λx.tt)Ωv. The source term is not typable in the simply typed lambda calculus (STLC): typing zz would require the type of z to be both an arrow and its own domain. Thus the example separates evaluation strategies outside the language to which the safety theorem applies.

Exercise 2.9

★★☆ Calculate both strategies on (λx.xx)((λy.y)tt) until a value or a stuck term is reached. Then suppose the self-applied variable x had a simple type X. Use the application rule to derive the two incompatible requirements X=DC and X=D, and explain why no finite simple type satisfies them. No annotations need be invented for the untyped trace.

Propositions as types, derivations as programs

A propositional letter P is an atomic formula. The propositional formulas used here are generated by F::=PFFFFFF. Suppose f:AB, g:BC, and a:A are typed terms. Two applications form the term g(fa):C. Replacing each type arrow by the formula connective turns those two applications into two uses of implication elimination: first derive B from f:AB and a:A, then derive C from g:BC and that result. The problem is whether every proof rule admits such a term decoration and whether erasing the terms recovers the proof.

The Curry–Howard translation fixes propositional letters P,Q, as atomic types and maps these formulas by formulaPABABABtypeP10A×BA+BAB. These are the atomic types fixed in definition 2.1; no grammar extension occurs here. An assumption A is given a label h, written h:A. These names are proof labels, not terms in the formula language; translation turns them into term variables.

Definition 2.38 — Intuitionistic propositional natural deduction

A judgment ΔNA says that A follows from the finite list Δ of named assumptions. Assumption labels in this list are distinct; accordingly Δ,h:A in a rule premise requires hdom(Δ), and the two labels introduced by E are also distinct from each other. The system is intuitionistic: each judgment has exactly one conclusion, and it has no independent rule asserting either excluded middle, the formula A(A) or double-negation elimination, the formula ((A))A. Its rules are

(h:A)Δ
ΔNA
Hyp
ΔN
→p I
ΔN
ΔNC
E
ΔNAΔNB
ΔNAB
I
ΔNAB
ΔNA
E_1
ΔNAB
ΔNB
E_2
Δ,h:ANB
ΔNAB
I
ΔNABΔNA
ΔNB
E
ΔNA
ΔNAB
I_1
ΔNB
ΔNAB
I_2
ΔNABΔ,h:ANCΔ,k:BNC
ΔNC
E

The letters I and E abbreviate introduction and elimination. In I, the assumption h:A is open in the premise and discharged in the conclusion: the conclusion no longer depends on it. The two branch assumptions of E are likewise local and discharged at the rule.

The motivating calculation is now a derivation in the displayed system: g:BCf:ABa:ABC. Decorating its assumption leaves by variables and its two E nodes by application produces the term g(fa).

Proposition 2.33 — Natural deduction is typing

For intuitionistic natural deduction with implication, conjunction, disjunction, truth, and falsity, every introduction or elimination rule is respectively one of the typing rules in this table: connectiveintroductioneliminationLamAppPairFst,SndInl,InrCaseUnitInonenoneEmptyE Translation of a derivation of ΔNA using only Hyp and the displayed connective rules produces a term e. Here every formula in Δ is a formed type, and each assumption label is used as the corresponding term variable, so the named-assumption list is a well-formed typing context. The translation produces a derivation Δe:A; conversely, erasing terms from a typing derivation generated by the corresponding rules, after erasing lambda annotations, produces a natural-deduction derivation of ΔNA. Let the logical skeleton of a typing derivation be the tree obtained by deleting the type-formation premises printed by Inl, Inr, and Empty-E, then replacing each remaining typing rule by the corresponding natural-deduction rule. Starting with a natural-deduction derivation and erasing its decoration recovers that derivation exactly. Starting with a typing derivation recovers its term up to alpha-equivalence and its logical skeleton exactly. The full typing tree has extra formation premises and therefore is not literally the same tree.

Proof of Proposition 2.33 — Natural deduction is typing

Proof. For a natural-deduction derivation D, write T(D) for its term decoration. For a typing derivation T, write E(T) for its erasure.

At an introduction rule, T uses the assumption label as the bound term variable. Induct on the derivation in either direction. We display the two cases that discharge hypotheses or combine alternatives.

Implication introduction transforms Δ,h:ANBΔNABintoΔ,x:Ab:BΔλx:A.b:ABLam. Here choose x=h; the term variable therefore records exactly the logical assumption label that was discharged. A preliminary alpha-renaming makes the label fresh for the surrounding context when necessary.

Disjunction elimination transforms ΔNABΔ,h:ANCΔ,k:BNCΔNC into Case; its two branch binders record the two temporary assumptions. The product, arrow, unit, and assumption rules agree premise for premise with their displayed typing rules. For I1, translation inserts the formed-type premise for the unused right summand; I2 inserts the corresponding left premise. For E, translation inserts formation of the chosen result type. Skeleton erasure deletes precisely these premises. In the reverse direction, the outer term constructor fixes the final typing rule, and skeleton erasure yields the logical rule with the same logical premises.

The same induction proves the two round trips: E(T(D))=D,term(T(E(T)))=αterm(T),skel(T(E(T)))=skel(T). For the first equation, every case reapplies the same logical rule to the inductively identical logical premises; erasure deletes the three kinds of inserted formation premise. For the second, every nonbinding case reapplies the same term constructor to alpha-equivalent premises. At I, erasure records the lambda binder as the discharged assumption label, and translation reuses it; changing the preliminary fresh representative changes only that binder name. The two branch binders of E are each recorded by erasure as the label discharged in that branch, and translation reuses each recorded label. Changing either fresh representative therefore alpha-renames only its own branch binder. These are all binding cases. At injection and empty-elimination nodes, canonical rebuilding may choose a different derivation of the same type-formation judgment, but skeleton erasure deletes it. This proves exactly the displayed claims about the second round trip. ◻

Exercise 2.10

★★☆ Give both a natural-deduction tree and a typing derivation for (AB)(BC)(AC). Then erase the term labels from your typing derivation and verify node by node that the original natural-deduction tree is recovered.

Example 2.34 — Commutativity of conjunction

The natural-deduction proof of ABBA is represented by the already typed program swapA,B. Here are the two trees node for node: p:ABp:ABp:ABNABHypp:ABNBE2p:ABp:ABp:ABNABHypp:ABNAE1p:ABNBAIN(AB)(BA)I and p:A×Bp:A×Bp:A×Bp:A×BVarp:A×Bsnd(p):BSndp:A×Bp:A×Bp:A×Bp:A×BVarp:A×Bfst(p):AFstp:A×B(snd(p),fst(p)):B×APairλp:A×B.(snd(p),fst(p)):(A×B)(B×A)Lam. Erasing terms and reading the connectives through the table gives the first tree exactly.

Example 2.35 — Distributing implication over alternatives

The formula (AC)(BC)(ABC) has proof term λp:(AC)×(BC).λs:A+B.case(s;x.fst(p)x;y.snd(p)y). In the left branch, Fst derives a proof of AC, which App applies to the temporary proof x:A. In the right branch, Snd derives BC and App applies it to y:B. The common branch type is C, exactly the side condition of disjunction elimination.

Proof reduction and subject reduction

Evaluation models a machine strategy. Proof reduction has a different purpose: it removes an introduction immediately followed by its matching elimination, wherever that detour occurs in a proof. It therefore reduces under lambdas and in both branches of a case.

Definition 2.36 — Compatible proof reduction

The root relation rpq consists of (λx:A.b)apb[a/x],fst((a,b))pa,snd((a,b))pb,case(inl(a);x.b;y.c)pb[a/x],case(inr(a);x.b;y.c)pc[a/y],if(tt;b;c)pb,if(ff;b;c)pc. A proof context is a term with one hole, generated by K::=[]λx:A.KKeeKif(K;e1;e2)if(e;K;e2)if(e;e1;K)(K,e)(e,K)fst(K)snd(K)inl(K)inr(K)case(K;x.e1;y.e2)case(e;x.K;y.e2)case(e;x.e1;y.K)abortA(K). Plugging is capture-permitting at the displayed hole: K[e] denotes the literal replacement of the hole by e. Bound names in K are chosen fresh for the root step before plugging, which makes the construction well-defined on alpha-classes. The one-step relation has the single closure rule rpqK[r]pK[q]PCtx. Thus the grammar explicitly includes lambda bodies, both application positions, all three conditional positions, both pair components, every unary constructor, the case scrutinee, and both case branches. Write p for reflexive transitive closure.

Proof reduction can contract below a binder where call-by-value evaluation cannot enter: λx:2.(λy:2.y)xpbeta,compatibleclosureλx:2.x.

Theorem 2.37 — Subject reduction

If Γe:A and epe, then Γe:A.

Proof of Theorem 2.37 — Subject reduction

Proof. First type each of the seven root contractions. The beta contraction is item 3 of proposition 2.29. The two projection contractions follow by two inversions of the typing derivation of the projection: the premise pair has type B×C, so its selected component already has the required type.

For the left sum contraction, inversion gives Γa:B and Γ,x:Bb:A; item 3 of proposition 2.29 gives Γb[a/x]:A. For the right contraction, interchange the two summands and branch binders in that derivation: inversion gives Γa:C and Γ,y:Cc:A, so the same extended substitution result gives Γc[a/y]:A. This interchange preserves the common branch result type. Conditional inversion says both branches already have the result type, so selecting either preserves it. These cases exhaust the root relation.

Now induct on the grammar of the proof context K. The hole case is the root result. For λx:A.K, invert Lam, apply the induction hypothesis under Γ,x:A, and rebuild Lam. For Ke and eK, invert App, change respectively its function or argument premise, and rebuild App. The three conditional contexts change the guard, first branch, or second branch premise of If; the two pair contexts change the corresponding premise of Pair. Each unary context for a projection, injection, or abort changes its unique term premise and rebuilds the same rule. Finally, the three case contexts change respectively the scrutinee premise, the left branch under x:B, or the right branch under y:C, and rebuild Case. These alternatives are exactly the context grammar, so ΓK[q]:A follows from ΓK[r]:A in every case. ◻

Corollary 2.44 — Many-step subject reduction

If Γe:A and epe, then Γe:A.

Proof of Corollary 2.44 — Many-step subject reduction

Proof. Induct on the many-step derivation. Reflexivity preserves the given typing. At a step followed by a tail, apply theorem 2.37 to the first step and the induction hypothesis to the tail. ◻

The beta step above does not require its argument to be a value. Thus proof reduction includes every machine beta step but is not itself the evaluator. Its normal forms are proofs without local introduction–elimination detours.

Exercise 2.11

★★☆ Reduce the proof term of example 2.35 after applying it to (f,g) and then to inl(a) in the context f:AC, g:BC, a:A. Check the injection against A+B. Label the projection, case, and beta contractions. Use subject reduction to write the common type C after each step.

Strong normalization by reducibility

Structural induction on a typing derivation cannot prove termination of an application. Its premises tell us that the function and argument terminate separately, but a terminating function applied to a terminating argument may create a new beta-redex. The missing invariant must say how a term behaves when eliminated at its type. The arrow reducibility candidate requires a function to remain reducible after application to every reducible argument.

Indeed, with P(Γe:A):=SN(e), the application case would have only SN(e1),SN(e2)⟹̸SN(e1e2). When e1=λx:A.b and e2=v, the new reduct is b[v/x]; it is a subterm of neither premise, so the two induction hypotheses give it no bound. We therefore build a type-indexed family that is closed under elimination. Finite reduction height supports induction on reducts; reduction closure proves reducibility of reducts, and the expansion clause puts a redex back into the candidate once all of its immediate reducts are there. The fundamental lemma places every typed term in the family; its normalization clause gives the desired theorem. The dependency chain is lemma2.47supports the height inductions inlemma2.40whose clauses provelemma2.52lemma2.53which discharge the typing cases oftheorem2.42whose normalization clause yieldstheorem2.43. Each vertical phrase states the named use made by the box below it; the display is bookkeeping, not a proof.

Definition 2.38 — Strong normalization and neutral terms

Strong normalization, written SN(e), is the property that there is no infinite chain e=e0pe1p. The introduction forms are λx:A.b,tt,ff,,(a,b),inl(a),inr(b). A neutral term is not an introduction form. Thus a variable and an elimination headed by a variable are neutral, but so is a principal redex such as (λx:A.b)a. This broader notion is needed for expansion: a principal redex is admitted after all of its immediate reducts have been admitted.

The narrower attempt “neutral means variable-headed” would exclude every principal redex. Then the neutral-expansion clause below could not recover (λx:A.b)a from its contractum, so the beta case of the fundamental lemma would stop at exactly the redex that typing creates.

Convention 2.46 — Finitely branching choice

The normalization proof uses the following classical metatheoretic principle: if a finitely branching rooted tree has nodes at every finite depth, then it has an infinite branch. Equivalently, a finitely branching tree with no infinite branch has a finite height. This is the finitely branching form of König’s lemma; it is the only choice principle used below.

Lemma 2.47 — Finite reduction height

Every term has finitely many immediate proof reducts. If SN(e), there is a finite maximum length ν(e) of a reduction beginning at e, and every step epe satisfies ν(e)<ν(e).

Proof of Lemma 2.47 — Finite reduction height

Proof. Finite branching is structural induction on e. Each constructor has finitely many immediate children, each child has finitely many reducts by induction, and the outer term has at most one additional root contraction.

Now suppose e is strongly normalizing. If its finite reduction tree had branches of unbounded finite length, one of the finitely many first reducts would again have branches of unbounded length. Repeating that choice would construct an infinite reduction, contradicting SN(e). Hence a maximum branch length ν(e) exists. A step to e removes the first edge from every continuation, so ν(e)<ν(e). The selection of an unbounded successor at each stage is exactly the principle declared in convention 2.46; its contrapositive gives the required bound. ◻

Reducibility is defined for raw, possibly open terms. This is essential: a fresh variable is the test argument which reveals whether a function itself can reduce forever. Typing enters only in the fundamental lemma.

Definition 2.39 — Reducible terms

For every type A, the reducible terms RA are defined by structural recursion on A. At atomic and nullary types, reducibility is strong normalization: RP=R2=R1=R0={eSN(e)}. The arrow and product clauses use only their immediate component types: eRABfor every aRA, eaRB,eRA×Bfst(e)RA and snd(e)RB. A sum has no single eliminator until a result candidate and two branch bodies have been chosen. Its structural clause records the canonical information that any later case analysis will need. Thus eRA+B exactly when SN(e) and both canonical-reduct conditions hold: epinl(a)aRA,epinr(b)bRB.

The compound clauses express behavior under elimination. Arrows are tested by application and products by projection; the base clauses impose only strong normalization. The sum clause records the reducibility of every payload reached at an injection.

Every recursive occurrence in this definition is indexed by a proper subexpression of the current type. In particular, the 2 and 0 clauses do not quantify over an arbitrary RC; elimination closure is a property of the completed structurally defined family, not a clause in its definition. The tempting alternative would define the Boolean clause by eR2?if(e;b1;b2)RCfor every type C and b1,b2RC. Taking C=22 already asks for a candidate at a type larger than 2 while defining the Boolean candidate. This is not structural recursion on the current type. The displayed definition instead uses strong normalization at 2 and recurses only through proper component types.

The three closure properties below fill each candidate with all of its reducts and with every neutral term whose possible next states are already present. We call the clauses normalization, reduction closure, and neutral expansion, respectively.

Lemma 2.40 — Saturation

For every type A:

  1. if eRA, then SN(e);

  2. if eRA and epe, then eRA;

  3. if n is neutral and every immediate reduct of n belongs to RA, then nRA.

Proof of Lemma 2.40 — Saturation

Proof. Induct on the structure of A, proving the clauses in their displayed order at each type.

Base types.

For P,2,1,0, clause 1 is the definition. Clause 2 follows because a reduct of a strongly normalizing term is strongly normalizing. For clause 3, every immediate reduct of n has a well-founded reduction tree. There are finitely many of them, so adjoining the root n gives another well-founded tree.

Arrow types.

Suppose A=BC. Any variable z belongs to RB by neutral expansion at the smaller type: it is neutral and the requirement on all of its immediate reducts holds vacuously because it has none. If eRBC, then ezRC, hence ez is strongly normalizing by clause 1 at C. An infinite reduction of e would lift by application congruence to one of ez, proving clause 1 at the arrow. If epe and aRB, then eapea; clause 2 at C proves eaRC, which proves clause 2 at the arrow.

For neutral expansion at BC, fix aRB and perform a second, inner induction on ν(a). The outer induction hypotheses concern the smaller types B,C; the inner hypothesis concerns arguments of smaller reduction height. The application na is neutral because an application is not an introduction form. It has no root beta contraction because the neutral term n is not an abstraction. An immediate reduct is na, where the hypothesis gives nRBC, or na, where ν(a)<ν(a). Reduction closure at the smaller type B gives aRB. The arrow clause and the induction hypothesis place these two reducts in RC: the arrow clause handles na, and the inner height induction, with this membership of a, handles na. Neutral expansion at the smaller type C gives naRC. Since a was arbitrary, n belongs to the arrow candidate.

Product types.

Suppose A=B×C. If e reduced forever, so would fst(e); clause 1 at B therefore proves clause 1 for e. For clause 2, place epe under each projection and use clause 2 at B and C. For clause 3, fst(n) is neutral because n is not a pair. Its immediate reducts are exactly fst(n) for immediate reducts n of n; each belongs to RB by the hypothesis and the product clause. Clause 3 at B gives the first projection condition. For the second, replace the smaller target type B by C and the context fst([]) by snd([]). For every immediate reduct n of n, the product hypothesis gives snd(n)RC; clause 3 at C therefore gives snd(n)RC. Both projection conditions hold, so nRB×C.

Sum types.

Suppose A=B+C. Clause 1 is part of the definition. For clause 2, epe preserves strong normalization; moreover any reduction epinl(b) extends to one from e, so bRB. Exchanging the left and right summands gives the required payload in RC for a reachable right injection.

For clause 3, every immediate reduct n is in RB+C and hence is strongly normalizing by clause 1 just proved. Finite branching therefore gives SN(n). If npinl(b), the path has positive length because n is not an introduction. Its first step reaches some nRB+C, whose canonical-reduct condition gives bRB. For a reduction to inr(c), the same positive-length factorization reaches an immediate nRB+C, whose right canonical-reduct condition gives cRC. Thus all parts of the sum definition hold. ◻

Lemma 2.50 — Fresh-renaming invariance

For a term t with zFV(t), choose a raw representative t¯ with zNames(t¯), and define tz/x to be the alpha-class of t¯z/x. This definition is independent of the chosen representative. If zFV(e)FV(e){x}, then epeez/xpez/x,SN(e)SN(ez/x). The same equivalences hold with p replaced by p.

Proof of Lemma 2.50 — Fresh-renaming invariance

Proof. First, fresh-representative clause (B3) gives the required t¯. Fresh-substitution clause (B5) identifies the alpha-class of its raw renaming with the quotient substitution t[z/x]. Well-definedness of substitution, clause (B4), therefore proves independence of t¯.

For preservation of one step, write it as K[r]pK[q] and use clause (B3) to choose representatives of the complete source and target whose binders avoid {x,z}. Renaming distributes over the context and over each of the seven root equations. In the beta root, for example, (b[a/y])z/x=bz/x[az/x/y] because y was chosen outside {x,z}; the two case roots use the same equation separately for their branch binders. The other roots are componentwise. For reflection, first choose representatives of the renamed terms whose binders avoid x, then apply preservation to the inverse renaming zx. Cancellation clause (B6), once for e and once for e, says that the two inverse renamings recover the original alpha-classes. Induction on length gives the many-step equivalence. Applying preservation or reflection pointwise to an infinite chain gives an infinite chain on the other side, proving the two directions of strong-normalization invariance. ◻

Lemma 2.51 — Reduction and substitution compatibility

The following hold.

  1. If bpb, then b[a/x]pb[a/x].

  2. If apa, then b[a/x]pb[a/x].

  3. If xy and yFV(d), then (b[a/y])[d/x]=b[d/x][a[d/x]/y].

Proof of Lemma 2.51 — Reduction and substitution compatibility

Proof. Prove item 3 first by structural induction on b. Variables split into x, y, and every other name; direct calculation gives the equation in each case. Nonbinding constructors apply the induction hypotheses to their arguments. At an abstraction or case branch, choose every displayed binder outside FV(a)FV(d){x,y}. Both sequential substitutions pass under that same binder; apply the body induction hypothesis and reattach it. The representative-independence argument in definition 2.28 shows that the resulting equation is on alpha-classes.

For item 1, write the step as K[r]pK[q], freshen the binders of K,r,q outside FV(a){x}, and induct on K. Substitution rebuilds the same context around the substituted root. At a beta root (λy.b)cpb[c/y], item 3 gives (b[c/y])[a/x]=b[a/x][c[a/x]/y], which is the contractum of the substituted beta redex. The left and right case roots use the same equation with their selected branch binder. Every other root is componentwise.

For item 2, choose a representative of b whose binders lie outside the finite set FV(a)FV(a){x}, and use structural induction on that representative. A variable different from x gives reflexivity; the variable x gives the assumed step. For each nonbinding constructor, reduce the copied occurrences one at a time and compose the resulting many-step derivations. At a binder, choose its name outside FV(a)FV(a){x} and apply the induction hypothesis to the body; the proof-context grammar lifts the resulting sequence under that binder. For a case, perform this argument independently in the scrutinee and the two branch bodies; the independent freshness choices ensure that neither copied sequence captures a free variable of a or a. ◻

Strong normalization supplies reduction heights, reduction closure handles a step in an argument, and neutral expansion admits the rebuilt eliminator. The following lemma records the resulting closure properties.

Lemma 2.52 — Eliminator closure

The following closure properties hold for the reducibility interpretation.

  1. If eR2 and b,cRC, then if(e;b;c)RC.

  2. If eRA+B and aRA, b[a/x]RC,dRB, c[d/y]RC, then case(e;x.b;y.c)RC.

  3. If eR0, then abortC(e)RC.

Proof of Lemma 2.52 — Eliminator closure

Proof. We use lemma 2.51 throughout.

For item 1, induct on ν(e)+ν(b)+ν(c). The conditional is neutral. Its root reduct is b when e=tt and c when e=ff, hence is reducible by hypothesis. Its immediate reducts are exactly if(e;b;c)epe,if(e;b;c)bpb,if(e;b;c)cpc,be=tt,ce=ff. Thus every nonroot immediate step reduces exactly one of e,b,c. Saturation clause 2 puts the changed immediate subterm in its candidate. Its reduction height is smaller, so the induction hypothesis gives membership of the new conditional in RC. Saturation clause 3 now gives the result.

For item 2, choose distinct variables z,w outside the finite set FV(b)FV(c){x,y}. Saturation clause 3 gives zRA and wRB. Hence b[z/x],c[w/y]RC, so both are strongly normalizing. Fresh renaming preserves the reduction tree, and therefore b and c themselves are strongly normalizing.

Induct on ν(e)+ν(b)+ν(c). The case term is neutral. If e=inl(a), the zero-step canonical-reduct condition in RA+B gives aRA, so the root reduct b[a/x] is reducible. If e=inr(d), its right canonical-reduct condition gives dRB, so the root reduct c[d/y] is reducible by the right-branch hypothesis. A step in e uses saturation clause 2 and the induction hypothesis. If bpb, then b[a/x]pb[a/x] for every reducible a; saturation clause 2 therefore establishes the left-branch hypothesis for b. The measure decreases, so the induction hypothesis applies. If cpc, compatibility gives c[d/y]pc[d/y] for every dRB; reduction closure establishes the right-branch hypothesis for c, and the decreased height allows the induction hypothesis. Thus every immediate reduct of the case term lies in RC, and saturation clause 3 concludes.

For item 3, induct on ν(e). The abort term is neutral and has no root contraction. Every immediate reduct is abortC(e) with eR0 by saturation clause 2 and ν(e)<ν(e); the induction hypothesis and saturation clause 3 finish the proof. ◻

Principal expansion is a different closure property. It starts from the contractum, whereas eliminator closure starts from the scrutinee. The proper immediate term arguments of a root redex are the terms immediately carried by its introduction and elimination forms: root redexproper arguments(λx:A.b)ab,afst((a,b)), snd((a,b))a,bcase(inl(a);x.b;y.c), case(inr(a);x.b;y.c)a,b,cif(tt;b;c), if(ff;b;c)b,c. This table defines the phrase for all seven root contractions.

Lemma 2.53 — Principal expansion

Let rpq be one of the seven root contractions in definition 2.36. If qRC and every proper immediate term argument of r is strongly normalizing, then rRC.

Proof of Lemma 2.53 — Principal expansion

Proof. Induct on the sum of the reduction heights of the proper arguments. The redex r is neutral. Its root reduct q is reducible by hypothesis. Any other immediate step reduces one proper argument and leaves a principal redex r of the same kind. Its root contractum q is reachable from q by zero or more compatible steps: a step in an unused branch leaves q unchanged; a step in a selected body gives one compatible step; and a step apa in a substituted argument gives b[a/x]pb[a/x] by the compatibility fact above. Repeated use of saturation clause 2 gives qRC. The height sum has decreased, so the induction hypothesis gives rRC. Every immediate reduct of r is now reducible, and saturation clause 3 gives rRC. ◻

For example, if b[a/x]RC and both b and a are strongly normalizing, principal expansion gives (λx:A.b)aRC. The strong-normalization premise for b matters because proof reduction is compatible under lambda bodies.

A complete calculation is already visible at Boolean type. The two values tt and ff belong to R2. If aR2, eliminator closure gives if(a;ff;tt)R2. The abstraction body is strongly normalizing, so principal expansion applied to an arbitrary such a yields (λx:2.if(x;ff;tt))aR2. Therefore Boolean negation belongs to R22, exactly by the arrow clause.

Definition 2.41 — Reducible substitution

For Γ=x1:A1,,xn:An, a simultaneous substitution σ is a finite map from the declared variables xi to terms. It acts simultaneously and capture-avoidingly on e; variables outside its domain are left unchanged. Write FV(rng(σ)):=xdom(σ)FV(σ(x)). Constants are fixed, and the nonbinding clauses are x[σ]={σ(x)xdom(σ),xotherwise,(e1e2)[σ]=e1[σ]e2[σ],if(e;e1;e2)[σ]=if(e[σ];e1[σ];e2[σ]),(e1,e2)[σ]=(e1[σ],e2[σ]),fst(e)[σ]=fst(e[σ]),snd(e)[σ]=snd(e[σ]),inl(e)[σ]=inl(e[σ]),inr(e)[σ]=inr(e[σ]),abortC(e)[σ]=abortC(e[σ]). Here tt,ff, are the fixed constants. For an abstraction, choose a representative with xFV(rng(σ)) and define (λx:A.b)[σ]=λx:A.b[σx]. For a case choose its two binders independently outside FV(rng(σ)) and each other, then define case(e;x.e1;y.e2)[σ]=case(e[σ];x.e1[σx];y.e2[σy]). These clauses are independent of representatives. Fix raw representatives of the finitely many terms in the range of σ. For two displayed abstraction representatives, choose one name u outside the name sets of both bodies and of all those range representatives. Clause (B3) permits both abstractions to be opened at u. Structural induction identifies the two substituted opened bodies, and rebuilding the common binder u identifies the output abstractions up to alpha-equivalence.

For two displayed case representatives, choose distinct names u,v outside the name sets of both complete case representatives and all range representatives. Clause (B3) opens both left branches at u and both right branches at v. Structural induction identifies the substituted scrutinees and the two pairs of substituted opened branch bodies. Rebuilding the common branch binders u,v identifies the output cases up to alpha-equivalence. Thus simultaneous substitution is well-defined on alpha-classes.

In particular, if xdom(σ) and is fresh for the range of σ, then b[σ,xa]=b[σ][a/x]. This equation is proved by structural induction on b. The variable and nonbinding cases are the displayed clauses. For an abstraction choose its binder y outside FV(rng(σ))FV(a){x}; both sides reattach λy to the body equation. For a case choose distinct branch binders y,z outside the same finite set. Both sides use the same substituted scrutinee and reattach y and z to the two induction-hypothesis equations. This treats every constructor and proves equation 2.1 before it is used in the fundamental lemma.

The substitution is reducible for Γ when σ(xi)RAi for every i. Write e[σ] for simultaneous capture-avoiding substitution. The empty substitution is reducible for the empty context. Write σ,xa for the map which agrees with σ away from x and sends x to a.

Theorem 2.42 — Fundamental lemma

If Γe:A and σ is reducible for Γ, then e[σ]RA.

Proof of Theorem 2.42 — Fundamental lemma

Proof. Induct on the typing derivation. Before a binder case, display its bound name outside the finite set FV(rng(σ))dom(Γ) and outside the other case binder when there are two; convention 2.3 permits this choice.

For Var, the assertion is the corresponding component of σ. For Lam, choose z outside FV(b[σ])FV(rng(σ))dom(Γ){x} and map x first to z. Saturation clause 3 and the induction hypothesis give b[σ,xz]RB. This term is a fresh renaming of b[σ]; saturation clause 1 and lemma 2.50 therefore give SN(b[σ]) in both renaming directions.

For arbitrary aRA, the induction hypothesis under σ,xa gives the beta contractum b[σ,xa]RB. Saturation clause 1 gives SN(a), so principal expansion admits (λx:A.b[σ])a: its contractum is the same alpha-class by equation 2.1. The arrow clause now admits the abstraction. The App case is that clause’s elimination condition.

For Pair, the induction hypotheses give reducible, hence strongly normalizing, components. Principal expansion admits both projections; the product clause then admits the pair. The Fst and Snd cases are the two defining product tests.

For Inl, the induction hypothesis gives aRA, hence SN(a) and SN(inl(a)). Every canonical reduct inl(a) comes from apa, so saturation clause 2 gives aRA; no right injection is reachable. Thus inl(a)RA+B. In Inr, the induction hypothesis gives bRB and hence SN(inr(b)); every reachable inr(b) has bRB by reduction closure, while no left injection is reachable. Therefore inr(b)RA+B.

In the Case case, extend σ by an arbitrary reducible branch argument. The two branch induction hypotheses give aRA, e1[σ][a/x]RC,dRB, e2[σ][d/y]RC. The scrutinee induction hypothesis and eliminator closure item 2 now give the substituted case term.

The constants tt,ff, lie in their base candidates. The If case is eliminator closure item 1, and Empty-E is item 3. There is no introduction case for 0. ◻

Proof of Theorem 2.43 — Strong normalization

Proof. Map every variable x:A in Γ to itself. Variables are reducible by neutral expansion, so this identity substitution is reducible for Γ. The fundamental lemma gives eRA, and saturation clause 1 gives SN(e). ◻

Lemma 2.57 — Machine steps are proof steps

If ee, then epe.

Proof of Lemma 2.57 — Machine steps are proof steps

Proof. Induct on the call-by-value step. Each beta, Boolean, projection, or case contraction is one of the seven proof roots; its value premise only restricts when that root may be used. Every congruence rule selects a position in the proof-context grammar: applications use Ke or vK, conditionals use their guard, pairs use either component, projections, injections, and abort use their unary argument, and cases use their scrutinee. Apply P-Ctx to the induction-hypothesis step in each congruence case. ◻

Corollary 2.58 — Call-by-value normalization

If e:A, then there is a value v such that ev and v:A.

Proof of Corollary 2.58 — Call-by-value normalization

Proof. Strong normalization gives the finite height ν(e). If e is not a value, by extended progress there is a step ee1; by lemma 2.57, ν(e1)<ν(e). Well-founded induction on this natural number therefore reaches a term v with no call-by-value step. Progress makes v a value. Composing the selected steps gives ev, and iterated preservation gives v:A. ◻

Exercise 2.12

★★☆ Assume eRA×B and epe. Display the two lifted steps fst(e)pfst(e) and snd(e)psnd(e), apply reduction closure at A and B, and conclude eRA×B. Then prove directly from definition 2.39, lemma 2.53 that if aRA and bRB, then (a,b)RA×B.

Lemma 2.59 — Typed normal forms

Suppose Γn:A and n has no p reduct. Then exactly one of the following holds:

  1. n is an introduction form;

  2. n is variable-headed, according to the grammar h::=xhefst(h)snd(h)if(h;e1;e2)case(h;x.e1;y.e2)abortA(h), and its head variable has a declaration in Γ.

Proof of Lemma 2.59 — Typed normal forms

Proof. Induct on the structure of n. A variable is in the second class by typing inversion; every introduction form is in the first. It remains to consider an elimination.

For n=e1e2, both subterms are normal. Apply the induction hypothesis to the well-typed function e1. If it is variable-headed, then so is n. If it is an introduction, typing inversion at an arrow type forces it to be an abstraction, making n a beta-redex, contrary to normality. For fst(e) and snd(e), an introductory e of product type must be a pair and would create a projection redex; otherwise the variable head is preserved.

For a case expression, an introductory scrutinee of sum type must be an injection, and either form creates a case redex. For a conditional, an introductory scrutinee of type 2 must be tt or ff, again creating a redex. Finally, an introductory term cannot have type 0: the introduction rules conclude only at 2, an arrow, a product, a sum, or 1. Thus the scrutinee of abortC(e) must be variable-headed. These cases exhaust the term grammar. The two classes are disjoint by their outer forms. ◻

Under proposition 2.33, a logic is consistent when it has no derivation of falsity from no assumptions.

Corollary 2.44 — Consistency

There is no closed term e with e:0.

Proof of Corollary 2.44 — Consistency

Proof. Assume such an e. Strong normalization and lemma 2.47 give the natural-number measure ν(e). While a reduct exists, choose one; its measure is strictly smaller, so after finitely many choices a normal form n is reached. Many-step subject reduction, corollary 2.44, gives n:0. By lemma 2.59, n is an introduction form or is headed by a variable declared in the empty context. The second alternative is impossible. The first is also impossible: inspection of the introduction rules shows that none concludes at 0. Thus no such normal form exists, a contradiction. ◻

Safety alone would not prove this corollary. It permits an infinite, well-typed computation, because an infinite computation is never stuck. Corollary 2.58 gives ev for a value v:0; extended canonical forms shows that no such v exists. Translating a hypothetical natural-deduction derivation of from no assumptions would give a closed term of 0, contradicting the corollary. Hence the uninhabitedness statement is the promised logical consistency theorem.

The first pressure for polymorphism

The identity program has to be copied when its type changes: id2:=λx:2.x:22,id1:=λx:1.x:11. Their erased lambda bodies are identical, yet the grammar contains no type that gives one simply typed term both displayed arrow types. Writing two definitions works; expressing them as one uniform definition does not. A single identity usable at both types requires quantification over its type.

Exercise 2.13

★★☆ Type the two identities above and use each twice in one product term. Then attempt to bind a single simply typed variable i and use i at both types. Use uniqueness of types to prove that the two required arrow types for i would have to be equal, and exhibit the unequal domain or codomain that contradicts this equality.

Suggested first pass.

Do exercise 2.15, exercise 2.14, exercise 2.16, in that order: binding calculation, proof reconstruction, and the Curry–Howard boundary. Continue in printed order for the full pass.

Exercise 2.15

★★☆ Let w,x,y,z be distinct. Compute, with every freshening step shown, case(z;x.(x,w);y.(w,y))[(x,y)/w]. Mark the free occurrences in the result. Explain why retaining the left binder would capture the inserted x, while retaining the right binder would capture the inserted y.

Exercise 2.14

★★★ Begin with the call-by-value function-and-Boolean STLC frames, obtained by restricting definition 1.67: E::=[]EevEif(E;e1;e2). Add frames for products, projections, injections, the case scrutinee, and abortA(E); do not import the arithmetic frames of chapter 1. Prove unique decomposition for the extended language, including the two injection contractions of a case, and derive determinism.

Exercise 2.16

★★★ Put ¬A:=A0. Give proof terms and complete typing derivations for ¬(A+B)(¬A׬B)and(¬A׬B)¬(A+B). Reduce the second term on both injection forms.

Exercise 2.17

★★★ Construct both directions of A×(B+C)(A×B)+(A×C). Show every beta, projection, and case contraction in each composite on constructor inputs. Do not add either of the following equations as a computation rule: (fst(p),snd(p))=p,λx:A.fx=f(xFV(f)).

The next two problems form one normalization reconstruction: the first rebuilds neutral expansion, and the second applies the resulting saturation mechanism to Boolean elimination.

Exercise 2.18

★★★ For every type A, let N(A) be the assertion that every neutral term n belongs to RA whenever all immediate reducts of n belong to RA. Prove N(A) by structural induction on A, without citing clause 3 of lemma 2.40. At a proper component type you may use clauses 1 and 2 of that lemma together with the corresponding outer induction hypothesis N(B) or N(C). In the arrow case, fix a reducible argument and use well-founded induction on its reduction height. State separately the outer type induction hypothesis and the inner height induction hypothesis. Finally, apply N(A) to a variable, which is neutral and has no immediate reducts, to derive xRA.

Exercise 2.19

★★★ Prove item 1 of lemma 2.52 in full. Use induction on ν(e)+ν(b)+ν(c), list the possible immediate reductions of if(e;b;c), and identify where each saturation clause is used. Then prove directly that tt,ffR2.

Exercise 2.22

★★★ Practical project.stlc-safety-checker Implement the syntax-directed checker and call-by-value evaluator for the Boolean-and-function fragment in the following stages.

  1. Define datatypes for types, raw terms, and typing derivations. Make the checker return a type together with a derivation, rather than a Boolean. Write a second traversal that validates every node of the returned derivation against the rules of section 2.1.

  2. Implement free-name calculation, deterministic fresh-name selection, and capture-avoiding substitution. On the body λy:2.x, substitute the free variable y for x. Check that the implementation freshens the binder and that naive textual replacement would capture the inserted y.

  3. Implement values, the six call-by-value one-step rules, and a fueled driver that distinguishes a normal form from exhausted fuel. Use enough fuel to finish every named run below.

  4. Accept notff at 2, validate its returned derivation, and evaluate the same source term to tt. Also evaluate nottt to ff. Reject ttff and λx:2.xx.

  5. Treat finite raw terms as the executable input. Reject λx:2.λx:2.x because its nested binder duplicates a context declaration; an alpha-fresh representative is a separate valid input. Add a regression that fails if either inference or derivation validation accepts the duplicate declaration.

Finally, give the size argument showing that no simple type A can annotate λx:A.xx: typing the body would force A=AB for some B. The executable checks the finite named outcomes; it is not a test of this universal argument.

Submit the program together with a short execution record containing the following five items.

  1. Print the complete validated derivation returned for notff, including the context at every Var node.

  2. Print its call-by-value trace from the named source through the beta and conditional contractions to tt. Beside each term, print the type returned by a fresh checker run.

  3. Give a table with one row for each named input above and columns for checker result, evidence-validation result, final value or rejection, and remaining fuel. A rejected term has no fabricated derivation or final value.

  4. Replace capture-avoiding substitution by textual replacement only for the capture witness of stage 2 above. Record the captured output and the failed witness assertion, then restore the correct implementation before running the acceptance cases.

  5. Explain which observations are finite tests and which claim is proved only by the size argument. In particular, rejection of the displayed self-application is evidence for one raw input, not a normalization or untypability theorem for an unspecified language.

Search the book

Type to search the local edition.