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 𝗍𝗍𝖿𝖿, 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 𝗍𝗍𝖿𝖿 before execution and whose answer is preserved by every evaluation step.
Fix effective enumerations 𝑃0,𝑃1,… of atomic type constants and 𝑥0,𝑥1,… of variables. Equality of two indices, and hence equality of atomic constants and variables, is decidable. We continue to write 𝑃,𝑄,… and 𝑥,𝑦,𝑧,… when their numerical codes are irrelevant. The simple types are the expressions generated by the judgment 𝐴𝗍𝗒𝗉𝖾 below:
𝟐𝗍𝗒𝗉𝖾
Ty-Bool
𝑃𝗍𝗒𝗉𝖾
Ty-Atom
𝐴𝗍𝗒𝗉𝖾𝐵𝗍𝗒𝗉𝖾
𝐴→𝐵𝗍𝗒𝗉𝖾
Ty-Arr
Equivalently, as a grammar: 𝐴,𝐵::=𝑃∣𝟐∣𝐴→𝐵. 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: 𝐴→𝐵=𝐴′→𝐵′ implies 𝐴=𝐴′ and 𝐵=𝐵′, and an arrow type equals neither 𝟐 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 𝟐 for the two-element Boolean type and its values as 𝗍𝗍 and 𝖿𝖿.
The rules already calculate a nontrivial type, the type of two-argument boolean operations:
𝟐𝗍𝗒𝗉𝖾
Ty-Bool
𝟐𝗍𝗒𝗉𝖾
Ty-Bool
𝟐𝗍𝗒𝗉𝖾
Ty-Bool
𝟐→𝟐𝗍𝗒𝗉𝖾
Ty-Arr
𝟐→(𝟐→𝟐)𝗍𝗒𝗉𝖾
Ty-Arr
As usual, → associates to the right: 𝟐→𝟐→𝟐 means 𝟐→(𝟐→𝟐). In a formation judgment, the whole expression to the left of 𝗍𝗒𝗉𝖾 is its subject; thus 𝐴→𝐵𝗍𝗒𝗉𝖾 means (𝐴→𝐵)𝗍𝗒𝗉𝖾.
Using the effective variable enumeration fixed above, raw terms are given by the grammar 𝑒::=𝑥∣𝜆𝑥:𝐴.𝑒∣𝑒1𝑒2∣𝗍𝗍∣𝖿𝖿∣𝗂𝖿(𝑒;𝑒1;𝑒2), where the abstraction 𝜆𝑥:𝐴.𝑒 binds 𝑥 in 𝑒 and 𝐴 ranges over the types of definition 2.1. The free variables of a raw term are computed by structural recursion: FV(𝑥)={𝑥},FV(𝗍𝗍)=FV(𝖿𝖿)=∅,FV(𝑒1𝑒2)=FV(𝑒1)∪FV(𝑒2),FV(𝜆𝑥:𝐴.𝑒)=FV(𝑒)∖{𝑥}, and FV(𝗂𝖿(𝑒;𝑒1;𝑒2))=FV(𝑒)∪FV(𝑒1)∪FV(𝑒2). Write Names(𝑒) for the finite set of every free or bound variable name in 𝑒, and BN(𝑒) 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 𝜆𝑥:𝐴.𝑒 first chooses a representative with a fresh binder. Compared with definition 1.50, this grammar drops the arithmetic constructors 𝟢, 𝗌𝗎𝖼, and 𝖺𝖽𝖽, retains 𝗍𝗍, 𝖿𝖿, and 𝗂𝖿, 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.
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:
fresh renaming 𝑒⟨𝑦/𝑥⟩ on a raw representative, defined when 𝑦∉Names(𝑒), with its free-variable, size, composition, and commutation equations;
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, 𝜆𝑥:𝐴.𝑏=𝛼𝜆𝑦:𝐵.𝑐 requires 𝐴=𝐵 and, for one common fresh 𝑧, 𝑏⟨𝑧/𝑥⟩=𝛼𝑐⟨𝑧/𝑦⟩;
fresh representatives and common opening: for every finite set 𝑋, every raw term 𝑒 has a representative 𝑒𝑋 with 𝑒=𝛼𝑒𝑋, whose binder labels are pairwise distinct and satisfy BN(𝑒𝑋)∩𝑋=∅; two alpha-equivalent abstractions have alpha-equivalent bodies after opening with any one name absent from both displayed raw representatives;
a capture-avoiding substitution 𝑒[𝑎/𝑥], well defined on alpha-classes, satisfying 𝑥[𝑎/𝑥]=𝑎,𝑦[𝑎/𝑥]=𝑦(𝑦≠𝑥),𝗍𝗍[𝑎/𝑥]=𝗍𝗍,𝖿𝖿[𝑎/𝑥]=𝖿𝖿,(𝑒1𝑒2)[𝑎/𝑥]=𝑒1[𝑎/𝑥]𝑒2[𝑎/𝑥],𝗂𝖿(𝑒;𝑒1;𝑒2)[𝑎/𝑥]=𝗂𝖿(𝑒[𝑎/𝑥];𝑒1[𝑎/𝑥];𝑒2[𝑎/𝑥]),(𝜆𝑦:𝐵.𝑏)[𝑎/𝑥]=𝜆𝑦:𝐵.𝑏[𝑎/𝑥],(𝜆𝑥:𝐵.𝑏)[𝑎/𝑥]=𝜆𝑥:𝐵.𝑏. The penultimate equation assumes 𝑦≠𝑥 and 𝑦∉FV(𝑎). The same clause carries the free-variable equation: if 𝑥∈FV(𝑒) then FV(𝑒[𝑎/𝑥])=(FV(𝑒)∖{𝑥})∪FV(𝑎), and 𝑒[𝑎/𝑥]=𝑒 when 𝑥∉FV(𝑒);
substitution by a fresh variable agrees with fresh renaming: if 𝑧∉FV(𝑒), choose a representative of 𝑒 whose binders are fresh for 𝑧; then 𝑒[𝑧/𝑥]=𝑒⟨𝑧/𝑥⟩.
fresh renaming can be cancelled: if 𝑥≠𝑧 and 𝑧∉Names(𝑒), then 𝑒⟨𝑧/𝑥⟩[𝑥/𝑧]=𝑒. Indeed, the fresh-opening cancellation lemma of lemma 1.63, specialized to the variable 𝑥, gives the left side as 𝑒[𝑥/𝑥]; substitution clause (B4) makes the latter term 𝑒.
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 𝗂𝖿 componentwise, 𝗂𝖿(𝑥;𝖿𝖿;𝑥)[𝗍𝗍/𝑥]=𝗂𝖿(𝗍𝗍;𝖿𝖿;𝗍𝗍), while a binder equal to a free variable of the inserted term must first be freshened: for distinct 𝑥,𝑦,𝑧, (𝜆𝑦:𝟐.𝑥)[𝑦/𝑥]𝑓𝑟𝑒𝑠ℎ𝑒𝑛𝑏𝑖𝑛𝑑𝑒𝑟=(𝜆𝑧:𝟐.𝑥)[𝑦/𝑥]𝑠𝑢𝑏𝑠𝑡𝑖𝑡𝑢𝑡𝑖𝑜𝑛𝑐𝑙𝑎𝑢𝑠𝑒=𝜆𝑧:𝟐.𝑦. Textual replacement without the renaming would produce 𝜆𝑦:𝟐.𝑦 and capture the inserted variable.
★☆☆ Let 𝑥,𝑦,𝑧 be distinct. Compute (𝜆𝑦:𝟐.𝗂𝖿(𝑥;𝑦;𝑥))[𝗂𝖿(𝑦;𝗍𝗍;𝖿𝖿)/𝑥] after alpha-renaming its binder fresh for the substituend, and mark every free occurrence of 𝑦 in the result. Then compute (𝜆𝑥:𝟐.𝑥)[𝗍𝗍/𝑥] and explain, from the equations of convention 2.3, why the answer is not 𝜆𝑥:𝟐.𝗍𝗍.
The symbol ⋅ denotes the empty context. A context is an ordered list of distinct declarations; Γ,𝑥:𝐴 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 (𝑥:𝐴)∈Γ for the occurrence of the declaration 𝑥:𝐴 in Γ. Whenever we write Γ,𝑥:𝐴, the side condition 𝑥∉dom(Γ) 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 𝑥∉dom(Γ′), then Γ′,𝑥:𝐴 extends Γ,𝑥:𝐴: perform the same insertions before the common final declaration.
For example, 𝑥:𝟐,𝑓:𝟐→𝟐 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.
The typing judgmentΓ⊢𝑒:𝐴, for Γ𝖼𝗍𝗑 and 𝐴𝗍𝗒𝗉𝖾, is inductively defined by
(𝑥:𝐴)∈Γ
Γ⊢𝑥:𝐴
Var
Γ⊢𝗍𝗍:𝟐
True
Γ⊢𝖿𝖿:𝟐
False
Γ⊢𝑒:𝟐Γ⊢𝑒1:𝐶Γ⊢𝑒2:𝐶
Γ⊢𝗂𝖿(𝑒;𝑒1;𝑒2):𝐶
If
Γ,𝑥:𝐴⊢𝑒:𝐵
Γ⊢𝜆𝑥:𝐴.𝑒:𝐴→𝐵
Lam
Γ⊢𝑒1:𝐴→𝐵Γ⊢𝑒2:𝐴
Γ⊢𝑒1𝑒2:𝐵
App
Rule instances range only over well-formed contexts and displayed types. In Lam, context formation requires 𝑥∉dom(Γ). Context membership and binder freshness are metalevel side conditions, not additional judgment forms. The premise of If types both branches by the same 𝐶 because either branch may be the result. When the context is empty, we may abbreviate ⋅⊢𝑒:𝐴 by ⊢𝑒:𝐴; 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.
★★☆ Define or:=𝜆𝑥:𝟐.𝜆𝑦:𝟐.𝗂𝖿(𝑥;𝗍𝗍;𝑦) and exhibit its full typing derivation at 𝟐→𝟐→𝟐, labeling every node with its rule. Then write a term xor of the same type whose 𝗂𝖿 has another 𝗂𝖿 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 ⋅⊢𝗍𝗍𝖿𝖿:𝐶 would have to end
⋅⊢𝗍𝗍:𝐴→𝐶⋅⊢𝖿𝖿:𝐴
⋅⊢𝗍𝗍𝖿𝖿:𝐶
App
for some type 𝐴. The right premise is derivable, with 𝐴=𝟐, by False. The left premise is not derivable for any 𝐴: it demands an arrow type for 𝗍𝗍, and the only rule that concludes a typing of the subject 𝗍𝗍 assigns it 𝟐.
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 𝗂𝖿—and by (B2) of convention 2.3 alpha-equivalence preserves the outer constructor. A derivation of Γ⊢𝗍𝗍𝖿𝖿:𝐶 therefore ends with App, whose first premise is Γ⊢𝗍𝗍:𝐴→𝐶 for some 𝐴. A derivation of that premise must end with the only rule whose subject is 𝗍𝗍, namely True, whose conclusion type is 𝟐. Since types are finite trees (definition 2.1), 𝟐≠𝐴→𝐶. 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.
★☆☆ Show by final-rule inspection that neither term 𝗂𝖿(𝜆𝑥:𝟐.𝑥;𝗍𝗍;𝖿𝖿)𝖿𝖿(𝜆𝑥:𝟐.𝑥) 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.
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 Γ,𝑧:𝐵1⊢𝑏:𝐵2Γ⊢𝜆𝑧:𝐵1.𝑏:𝐵1→𝐵2Lam To insert 𝑥:𝐴 into Γ, we would like to insert it into the premise as well. If the displayed binder happens to be 𝑧=𝑥, the proposed context declares 𝑥 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 ℎ(D) (chapter 1).
In a ground instance, let 𝑥≠𝑦 and start from 𝑥:𝟐⊢𝜆𝑦:𝟐.𝑥:𝟐→𝟐, and try to rename 𝑥 to 𝑦. The captured term 𝜆𝑦:𝟐.𝑦 is wrong. Choose 𝑧∉{𝑥,𝑦} and first represent the subject as 𝜆𝑧:𝟐.𝑥; renaming then gives 𝑦:𝟐⊢𝜆𝑧:𝟐.𝑦:𝟐→𝟐. This two-stage calculation is the abstraction case of lemma 2.9.
Suppose D::Γ1,𝑥:𝐴,Γ2⊢𝑒:𝐵 with ℎ(D)=ℎ, and let 𝑥′ be a variable with 𝑥′≠𝑥 and 𝑥′∉dom(Γ1)∪dom(Γ2)∪FV(𝑒). Then Γ1,𝑥′:𝐴,Γ2⊢𝑒[𝑥′/𝑥]:𝐵 has a derivation of height at most ℎ.
Proof. By complete induction on ℎ, with cases on the final rule of D.
CaseVar: 𝑒=𝑦 with (𝑦:𝐵)∈Γ1,𝑥:𝐴,Γ2. If 𝑦=𝑥, then 𝐵=𝐴 because contexts declare distinct variables, 𝑒[𝑥′/𝑥]=𝑥′, and Var concludes Γ1,𝑥′:𝐴,Γ2⊢𝑥′:𝐴. If 𝑦≠𝑥, then (𝑦:𝐵) occurs in Γ1 or Γ2, 𝑒[𝑥′/𝑥]=𝑦, and Var applies unchanged.
CasesTrue, False: the subject is a constant, unchanged by substitution, and the same axiom applies in the renamed context.
CaseLam: 𝑒=𝜆𝑧:𝐵1.𝑏 and 𝐵=𝐵1→𝐵2, with premise D′::Γ1,𝑥:𝐴,Γ2,𝑧:𝐵1⊢𝑏:𝐵2 of height ℎ−1; by context formation in the premise, 𝑧∉dom(Γ1)∪{𝑥}∪dom(Γ2).
If 𝑧≠𝑥′, the inductive hypothesis applies to D′, renaming 𝑥 to 𝑥′; here 𝑥′∉FV(𝑏) because 𝑥′∉FV(𝑒)=FV(𝑏)∖{𝑧} and 𝑥′≠𝑧. It yields Γ1,𝑥′:𝐴,Γ2,𝑧:𝐵1⊢𝑏[𝑥′/𝑥]:𝐵2 at height at most ℎ−1, and Lam concludes, with 𝜆𝑧:𝐵1.𝑏[𝑥′/𝑥]=(𝜆𝑧:𝐵1.𝑏)[𝑥′/𝑥] by the abstraction equation of convention 2.3 (𝑧≠𝑥, 𝑧≠𝑥′).
If 𝑧=𝑥′, choose 𝑧″ outside dom(Γ1)∪dom(Γ2)∪{𝑥,𝑥′} and outside the finite set of all variable names occurring in 𝑏. Two uses of the inductive hypothesis, both on derivations of height at most ℎ−1, transform the premise: Γ1,𝑥:𝐴,Γ2,𝑧:𝐵1⊢𝑏:𝐵2⟹Γ1,𝑥:𝐴,Γ2,𝑧″:𝐵1⊢𝑏[𝑧″/𝑧]:𝐵2⟹Γ1,𝑥′:𝐴,Γ2,𝑧″:𝐵1⊢𝑏[𝑧″/𝑧][𝑥′/𝑥]:𝐵2. The first use freshens the binder. For the second, recall that 𝑥′=𝑧: by the free-variable equation in substitution clause (B4), FV(𝑏[𝑧″/𝑧])⊆(FV(𝑏)∖{𝑧})∪{𝑧″}, so 𝑥′=𝑧 is not free in the renamed body, and the remaining freshness conditions follow from the choice of 𝑧″ and context formation. Rule Lam now concludes with subject 𝜆𝑧″:𝐵1.𝑏[𝑧″/𝑧][𝑥′/𝑥]. To identify this subject with (𝜆𝑧:𝐵1.𝑏)[𝑥′/𝑥]: by fresh-substitution clause (B5) the substitution 𝑏[𝑧″/𝑧] is the fresh renaming 𝑏⟨𝑧″/𝑧⟩, so the common-opening clause (B3) gives 𝜆𝑧:𝐵1.𝑏=𝜆𝑧″:𝐵1.𝑏⟨𝑧″/𝑧⟩ as terms; substituting 𝑥′ for 𝑥 on both displays—the right display is clean, since 𝑧″∉{𝑥,𝑥′} and 𝑧″∉FV(𝑥′)—and using the abstraction equation of substitution clause (B4) on the right yields exactly the displayed subject.
CasesIf, App: apply the inductive hypothesis to every premise derivation, each of height at most ℎ−1 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 𝑒[𝑥′/𝑥]. ◻
★★☆ Carry out lemma 2.9 on the derivation of 𝑥:𝟐⊢𝗂𝖿(𝑥;𝑥;𝖿𝖿):𝟐, renaming 𝑥 to 𝑦: display the resulting derivation node by node. Then apply the lemma to the premise of example 2.6 with 𝑥′= a fresh 𝑢 and confirm that the conclusion of Lam denotes the same alpha-class as the original abstraction, even though its premise is displayed with binder 𝑢.
Suppose Γ⊢𝜆𝑥:𝐴.𝑏:𝐶 is derivable, and choose 𝑧 distinct from 𝑥, outside dom(Γ), and occurring nowhere in 𝑏. Then 𝐶=𝐴→𝐵 for some 𝐵, and Γ,𝑧:𝐴⊢𝑏⟨𝑧/𝑥⟩:𝐵 is derivable. Thus the typing of an abstraction does not depend on the bound name used to display it.
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 𝜆𝑦:𝐴.𝑐 of the same term, giving a premise Γ,𝑦:𝐴⊢𝑐:𝐵 and the conclusion type 𝐴→𝐵. We cannot assume the requested 𝑧 fresh for the hidden body 𝑐. Choose 𝑤 outside the finite set {𝑥,𝑦,𝑧}∪dom(Γ)∪Names(𝑏)∪Names(𝑐).
Renaming the premise from 𝑦 to 𝑤 (lemma 2.9) gives Γ,𝑤:𝐴⊢𝑐[𝑤/𝑦]:𝐵, and 𝑐[𝑤/𝑦]=𝑐⟨𝑤/𝑦⟩ by fresh-substitution clause (B5). Common-opening clause (B3), applied to the equality of terms 𝜆𝑥:𝐴.𝑏=𝜆𝑦:𝐴.𝑐, gives 𝑐⟨𝑤/𝑦⟩=𝑏⟨𝑤/𝑥⟩. Now rename once more, from 𝑤 to 𝑧: the target 𝑧 is absent from the opened body because it is absent from 𝑏 and distinct from 𝑤, so lemma 2.9 and fresh-substitution clause (B5) give Γ,𝑧:𝐴⊢𝑏⟨𝑤/𝑥⟩⟨𝑧/𝑤⟩:𝐵, and the fresh-renaming composition equation (B1) computes 𝑏⟨𝑤/𝑥⟩⟨𝑧/𝑤⟩=𝑏⟨𝑧/𝑥⟩. ◻
If raw terms 𝑒 and 𝑒′ are alpha-equivalent, then Γ⊢𝑒:𝐴 is derivable if and only if Γ⊢𝑒′:𝐴 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. ◻
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.
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(𝑏)⊆dom(Γ)∪{𝑥}; deleting the bound name 𝑥 leaves FV(𝜆𝑥:𝐴.𝑏)⊆dom(Γ). ◻
Weakening permits insertion at any well-formed position in a context.
Proof. Use complete induction on the height of the given typing derivation. The variable case follows because the original declaration remains in Γ1,𝑥:𝐴,Γ2. Constants require no premises. For App and If, weaken each premise and reapply its final rule.
Suppose the last rule is Γ1,Γ2,𝑧:𝐶⊢𝑏:𝐷Γ1,Γ2⊢𝜆𝑧:𝐶.𝑏:𝐶→𝐷Lam. Choose 𝑤 outside the finite set FV(𝑏)∪dom(Γ1,𝑥:𝐴,Γ2)∪{𝑧}. By convention 2.12, lemma 2.9, alpha-renaming the binder transports the premise, without increasing its height, to Γ1,Γ2,𝑤:𝐶⊢𝑏⟨𝑤/𝑧⟩:𝐷. The induction hypothesis inserts 𝑥:𝐴 before Γ2 in this smaller premise. Rule Lam yields 𝜆𝑤:𝐶.𝑏⟨𝑤/𝑧⟩:𝐶→𝐷 under the enlarged context; this term is alpha-equivalent to the displayed conclusion. ◻
Proof. Induct on the first derivation, keeping the displayed context split in the induction assertion. In the Var case the subject is a variable 𝑦. If 𝑦=𝑥, context uniqueness gives 𝐵=𝐴, and the second hypothesis is the desired conclusion. If 𝑦≠𝑥, then (𝑦:𝐵) remains in Γ1,Γ2, substitution leaves 𝑦 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 𝜆𝑦:𝐶.𝑏 with 𝑦≠𝑥 and 𝑦∉FV(𝑎). Its premise is Γ1,𝑥:𝐴,Γ2,𝑦:𝐶⊢𝑏:𝐷. Weakening the second hypothesis at the end gives Γ1,Γ2,𝑦:𝐶⊢𝑎:𝐴. The induction hypothesis, with Γ2,𝑦:𝐶 as the right part of the split, gives Γ1,Γ2,𝑦:𝐶⊢𝑏[𝑎/𝑥]:𝐷. Rule Lam concludes Γ1,Γ2⊢𝜆𝑦:𝐶.𝑏[𝑎/𝑥]:𝐶→𝐷. Substitution clause (B4) gives 𝜆𝑦:𝐶.𝑏[𝑎/𝑥]=𝛼(𝜆𝑦:𝐶.𝑏)[𝑎/𝑥], so the derived subject is the required substitution. ◻
Let 𝑏=𝗂𝖿(𝑥;𝖿𝖿;𝗍𝗍) and 𝑎=𝗂𝖿(𝗍𝗍;𝖿𝖿;𝗍𝗍). We have 𝑥:𝟐⊢𝑏:𝟐 and ⊢𝑎:𝟐. Substitution therefore derives ⋅⊢𝗂𝖿(𝗂𝖿(𝗍𝗍;𝖿𝖿;𝗍𝗍);𝖿𝖿;𝗍𝗍):𝟐. At the unique Var leaf for 𝑥, the entire derivation of 𝑎 is inserted; all other rule nodes are copied. Thus substitution on terms is the visible trace of substitution on derivation trees.
★★☆ Write the two premise derivations and the resulting derivation tree for (𝜆𝑦:𝟐.𝗂𝖿(𝑥;𝑦;𝖿𝖿))[𝗂𝖿(𝗍𝗍;𝖿𝖿;𝗍𝗍)/𝑥]. Point to the weakening step used to type the inserted term under 𝑦:𝟐.
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.
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. ◻
Proof. Use complete induction on the constructor count of a representative of 𝑒 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 𝟐. For an abstraction, inversion gives 𝐴=𝐶→𝐴′ and 𝐵=𝐶→𝐵′ and two typings of the same opened body; the induction hypothesis gives 𝐴′=𝐵′. For an application, inversion gives Γ⊢𝑒1:𝐶→𝐴 and Γ⊢𝑒1:𝐷→𝐵; the induction hypothesis for 𝑒1 gives 𝐶→𝐴=𝐷→𝐵, hence 𝐴=𝐵 by injectivity of the arrow constructor. For a conditional, either branch has both result types, so its induction hypothesis gives 𝐴=𝐵. ◻
There is an algorithm which, given a finite well-formed context Γ and a finite raw representative 𝑒, either returns the unique type of its alpha-class and a derivation of Γ⊢𝑒:𝐴, or correctly reports that no such type exists.
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 𝟐. For 𝜆𝑥:𝐴.𝑏, first check 𝐴𝗍𝗒𝗉𝖾 and synthesize 𝐵 for 𝑏 under Γ,𝑥:𝐴; return 𝐴→𝐵. For 𝑒1𝑒2, synthesize both types, require the first to be 𝐴→𝐵 and the second to equal 𝐴, and return 𝐵. For a conditional, require the guard’s synthesized type to be 𝟐 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 𝑒 therefore proves completeness. Uniqueness is lemma 2.19. Finally, let 𝑒1 and 𝑒2 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.
Values, the completed results of evaluation, and the one-step relation 𝑒⟼𝑒′ are generated by 𝑣::=𝗍𝗍∣𝖿𝖿∣𝜆𝑥:𝐴.𝑒 and the rules
𝑒1⟼𝑒′1
𝑒1𝑒2⟼𝑒′1𝑒2
E-AppL
𝑣1𝗏𝖺𝗅𝗎𝖾𝑒2⟼𝑒′2
𝑣1𝑒2⟼𝑣1𝑒′2
E-AppR
𝑣𝗏𝖺𝗅𝗎𝖾
(𝜆𝑥:𝐴.𝑏)𝑣⟼𝑏[𝑣/𝑥]
E-Beta
𝑒⟼𝑒′
𝗂𝖿(𝑒;𝑒1;𝑒2)⟼𝗂𝖿(𝑒′;𝑒1;𝑒2)
E-If
𝗂𝖿(𝗍𝗍;𝑒1;𝑒2)⟼𝑒1
E-True
𝗂𝖿(𝖿𝖿;𝑒1;𝑒2)⟼𝑒2
E-False
The many-step relation is generated by
𝑒⟼∗𝑒
M-Refl
𝑒⟼𝑒1𝑒1⟼∗𝑒2
𝑒⟼∗𝑒2
M-Step
Here 𝑣 ranges over the displayed value grammar, and 𝑣𝗏𝖺𝗅𝗎𝖾 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, 𝑣𝗏𝖺𝗅𝗎𝖾 restricts that chapter’s 𝑣𝗏𝖺𝗅 to functions and booleans.
For example, with not from example 2.6, not(𝗂𝖿(𝖿𝖿;𝖿𝖿;𝗍𝗍))𝐸−𝐹𝑎𝑙𝑠𝑒/𝐸−𝐴𝑝𝑝𝑅⟼not𝗍𝗍𝐸−𝐵𝑒𝑡𝑎⟼𝗂𝖿(𝗍𝗍;𝖿𝖿;𝗍𝗍)𝐸−𝑇𝑟𝑢𝑒⟼𝖿𝖿. The value restriction on E-Beta fixes this order.
Proof. There are three value forms. Inversion assigns 𝟐 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. ◻
For E-AppL, inversion of the typing of 𝑒1𝑒2 gives Γ⊢𝑒1:𝐵→𝐴 and Γ⊢𝑒2:𝐵. 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 Γ⊢𝜆𝑥:𝐵.𝑏:𝐵→𝐴 and Γ⊢𝑣:𝐵; abstraction inversion gives Γ,𝑥:𝐵⊢𝑏:𝐴. The substitution theorem yields Γ⊢𝑏[𝑣/𝑥]:𝐴.
For E-If, inversion gives Γ⊢𝑒:𝟐, Γ⊢𝑏:𝐴, and Γ⊢𝑐:𝐴; 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. ◻
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 𝑒1𝑒2, the induction hypothesis for 𝑒1 either gives an E-AppL step or says 𝑒1 is a value. In the latter case, the induction hypothesis for 𝑒2 either gives an E-AppR step or says 𝑒2 is a value. By lemma 2.13, the typing in the empty context makes 𝑒1 closed. Now 𝑒1 is a closed value of arrow type, so canonical forms writes it as an abstraction; E-Beta applies.
For 𝗂𝖿(𝑒;𝑒1;𝑒2), a step of 𝑒 gives E-If. Otherwise 𝑒 is a closed value of type 𝟐, hence is 𝗍𝗍 or 𝖿𝖿 by canonical forms, and E-True or E-False applies. ◻
Proof. First prove by induction on the displayed many-step derivation the strengthened assertion ⋅⊢𝑒:𝐴∧𝑒⟼∗𝑒′⟹⋅⊢𝑒′:𝐴. 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 ⋅⊢𝑒′:𝐴 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.
★★☆ 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.
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; 𝟏 has one canonical inhabitant, meaning one constructor value of that type; and 𝟎 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.
Extend types and terms by 𝐴,𝐵::=⋯∣𝐴×𝐵,𝑒::=⋯∣(𝑒1,𝑒2)∣𝖿𝗌𝗍(𝑒)∣𝗌𝗇𝖽(𝑒). The formation, introduction, and elimination rules are
𝐴𝗍𝗒𝗉𝖾𝐵𝗍𝗒𝗉𝖾
𝐴×𝐵𝗍𝗒𝗉𝖾
Ty-Prod
Γ⊢𝑒1:𝐴Γ⊢𝑒2:𝐵
Γ⊢(𝑒1,𝑒2):𝐴×𝐵
Pair
Γ⊢𝑒:𝐴×𝐵
Γ⊢𝖿𝗌𝗍(𝑒):𝐴
Fst
Γ⊢𝑒:𝐴×𝐵
Γ⊢𝗌𝗇𝖽(𝑒):𝐵
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
𝑒1⟼𝑒′1
(𝑒1,𝑒2)⟼(𝑒′1,𝑒2)
E-PairL
𝑣1𝗏𝖺𝗅𝗎𝖾𝑒2⟼𝑒′2
(𝑣1,𝑒2)⟼(𝑣1,𝑒′2)
E-PairR
𝑒⟼𝑒′
𝖿𝗌𝗍(𝑒)⟼𝖿𝗌𝗍(𝑒′)
E-Fst
𝑣1𝗏𝖺𝗅𝗎𝖾𝑣2𝗏𝖺𝗅𝗎𝖾
𝖿𝗌𝗍((𝑣1,𝑣2))⟼𝑣1
E-Fst-Pair
𝑒⟼𝑒′
𝗌𝗇𝖽(𝑒)⟼𝗌𝗇𝖽(𝑒′)
E-Snd
𝑣1𝗏𝖺𝗅𝗎𝖾𝑣2𝗏𝖺𝗅𝗎𝖾
𝗌𝗇𝖽((𝑣1,𝑣2))⟼𝑣2
E-Snd-Pair
Fresh renaming is componentwise, and substitution satisfies (𝑒1,𝑒2)[𝑎/𝑧]=(𝑒1[𝑎/𝑧],𝑒2[𝑎/𝑧]),𝖿𝗌𝗍(𝑒)[𝑎/𝑧]=𝖿𝗌𝗍(𝑒[𝑎/𝑧]),𝗌𝗇𝖽(𝑒)[𝑎/𝑧]=𝗌𝗇𝖽(𝑒[𝑎/𝑧]). The name and binder-label sets take unions over the displayed arguments. The equation (𝖿𝗌𝗍(𝑝),𝗌𝗇𝖽(𝑝))=𝑝 would remove a pair constructor placed immediately around the two projections of 𝑝. 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: 𝖿𝗌𝗍((𝗍𝗍,𝖿𝖿))𝐸−𝐹𝑠𝑡−𝑃𝑎𝑖𝑟⟼𝗍𝗍,𝖿𝗌𝗍(𝑥)hasnostep.
Extend types and terms by 𝐴,𝐵::=⋯∣𝐴+𝐵,𝑒::=⋯∣𝗂𝗇𝗅(𝑒)∣𝗂𝗇𝗋(𝑒)∣𝖼𝖺𝗌𝖾(𝑒;𝑥.𝑒1;𝑦.𝑒2). The notation 𝑥.𝑒1 marks 𝑥 as bound in the left branch body, and 𝑦.𝑒2 marks 𝑦 as bound in the right branch body. The formation, introduction, and elimination rules are
𝐴𝗍𝗒𝗉𝖾𝐵𝗍𝗒𝗉𝖾
𝐴+𝐵𝗍𝗒𝗉𝖾
Ty-Sum
Γ⊢𝑒:𝐴𝐵𝗍𝗒𝗉𝖾
Γ⊢𝗂𝗇𝗅(𝑒):𝐴+𝐵
Inl
𝐴𝗍𝗒𝗉𝖾Γ⊢𝑒:𝐵
Γ⊢𝗂𝗇𝗋(𝑒):𝐴+𝐵
Inr
Γ⊢𝑒:𝐴+𝐵Γ,𝑥:𝐴⊢𝑒1:𝐶Γ,𝑦:𝐵⊢𝑒2:𝐶
Γ⊢𝖼𝖺𝗌𝖾(𝑒;𝑥.𝑒1;𝑦.𝑒2):𝐶
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
𝑒⟼𝑒′
𝗂𝗇𝗅(𝑒)⟼𝗂𝗇𝗅(𝑒′)
E-Inl
𝑒⟼𝑒′
𝗂𝗇𝗋(𝑒)⟼𝗂𝗇𝗋(𝑒′)
E-Inr
𝑒⟼𝑒′
𝖼𝖺𝗌𝖾(𝑒;𝑥.𝑒1;𝑦.𝑒2)⟼𝖼𝖺𝗌𝖾(𝑒′;𝑥.𝑒1;𝑦.𝑒2)
E-Case
𝑣𝗏𝖺𝗅𝗎𝖾
𝖼𝖺𝗌𝖾(𝗂𝗇𝗅(𝑣);𝑥.𝑒1;𝑦.𝑒2)⟼𝑒1[𝑣/𝑥]
E-Case-L
𝑣𝗏𝖺𝗅𝗎𝖾
𝖼𝖺𝗌𝖾(𝗂𝗇𝗋(𝑣);𝑥.𝑒1;𝑦.𝑒2)⟼𝑒2[𝑣/𝑦]
E-Case-R
Fresh renaming and substitution are componentwise on injections. For a case, choose 𝑥′ and then 𝑦′ outside Names(𝑎)∪Names(𝑒1)∪Names(𝑒2)∪{𝑥,𝑦,𝑧}, with 𝑥′≠𝑦′. Rename the two branch binders independently and define 𝖼𝖺𝗌𝖾(𝑒;𝑥.𝑒1;𝑦.𝑒2)[𝑎/𝑧]=𝖼𝖺𝗌𝖾(𝑒[𝑎/𝑧];𝑥′.𝑒1[𝑥′/𝑥][𝑎/𝑧];𝑦′.𝑒2[𝑦′/𝑦][𝑎/𝑧]). 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(𝖼𝖺𝗌𝖾(𝑒;𝑥.𝑒1;𝑦.𝑒2)) is the union of the three body name sets with {𝑥,𝑦}; its binder-label set adds 𝑥,𝑦 to the three body binder-label sets. Injections retain the two sets of their payloads.
For arbitrary types 𝐴,𝐵, define tag𝐴,𝐵:=𝜆𝑠:𝐴+𝐵.𝖼𝖺𝗌𝖾(𝑠;𝑥.𝗍𝗍;𝑦.𝖿𝖿). The two branch derivations use True and False under their extended contexts, so Case types the body by 𝟐 and Lam gives tag𝐴,𝐵:(𝐴+𝐵)→𝟐. This is a genuine elimination: the program is allowed to inspect which introduction rule built its argument. The body derivation is
𝑠:𝐴+𝐵∈𝑠:𝐴+𝐵
𝑠:𝐴+𝐵⊢𝑠:𝐴+𝐵
Var
𝑠:𝐴+𝐵,𝑥:𝐴⊢𝗍𝗍:𝟐
True
𝑠:𝐴+𝐵,𝑦:𝐵⊢𝖿𝖿:𝟐
False
𝑠:𝐴+𝐵⊢𝖼𝖺𝗌𝖾(𝑠;𝑥.𝗍𝗍;𝑦.𝖿𝖿):𝟐
Case
For values 𝑎:𝐴 and 𝑏:𝐵, the two computation clauses are visible in the complete traces tag𝐴,𝐵𝗂𝗇𝗅(𝑎)⟼𝖼𝖺𝗌𝖾(𝗂𝗇𝗅(𝑎);𝑥.𝗍𝗍;𝑦.𝖿𝖿)⟼𝗍𝗍,tag𝐴,𝐵𝗂𝗇𝗋(𝑏)⟼𝖼𝖺𝗌𝖾(𝗂𝗇𝗋(𝑏);𝑥.𝗍𝗍;𝑦.𝖿𝖿)⟼𝖿𝖿.
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 𝟏 is ⋆; Unit has no eliminator or root contraction in this calculus.
★☆☆ Let Γ=𝑥:𝐴 be well formed. Display the derivation of Γ⊢⋆:𝟏, and use final-rule inspection to show that a closed value 𝑣:𝟏 cannot be a lambda, Boolean, pair, or injection.
Extend types by 𝟎, terms by 𝖺𝖻𝗈𝗋𝗍𝐶(𝑒), and the rules by
𝟎𝗍𝗒𝗉𝖾
Ty-Empty
Γ⊢𝑒:𝟎𝐶𝗍𝗒𝗉𝖾
Γ⊢𝖺𝖻𝗈𝗋𝗍𝐶(𝑒):𝐶
Empty-E
𝑒⟼𝑒′
𝖺𝖻𝗈𝗋𝗍𝐶(𝑒)⟼𝖺𝖻𝗈𝗋𝗍𝐶(𝑒′)
E-Abort
The result annotation makes the eliminator syntax directed. There is no Void constructor, no value of type 𝟎, and no root contraction for 𝖺𝖻𝗈𝗋𝗍. The following open stuck term has the exact derivation
(𝑥:𝟎)∈(𝑥:𝟎)
𝑥:𝟎⊢𝑥:𝟎
Var
𝟐𝗍𝗒𝗉𝖾
𝑥:𝟎⊢𝖺𝖻𝗈𝗋𝗍𝟐(𝑥):𝟐
Empty-E
It is not a value and cannot step because its variable argument cannot step. Substitution satisfies 𝖺𝖻𝗈𝗋𝗍𝐶(𝑒)[𝑎/𝑧]=𝖺𝖻𝗈𝗋𝗍𝐶(𝑒[𝑎/𝑧]). Abort retains the name and binder-label sets of its argument.
★☆☆ For a formed type 𝐴, derive 𝑥:𝟎,𝑦:𝐴⊢𝖺𝖻𝗈𝗋𝗍𝐴×𝟐(𝑥):𝐴×𝟐. 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 𝖢𝗈𝗅𝗈𝗋:=𝟏+(𝟏+𝟏),𝗋𝖾𝖽:=𝗂𝗇𝗅(⋆),𝖺𝗆𝖻𝖾𝗋:=𝗂𝗇𝗋(𝗂𝗇𝗅(⋆)),𝗀𝗋𝖾𝖾𝗇:=𝗂𝗇𝗋(𝗂𝗇𝗋(⋆)). 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 𝟏; a constructor with several fields uses a product in its summand.
★★☆ Write next:𝖢𝗈𝗅𝗈𝗋→𝖢𝗈𝗅𝗈𝗋 sending red to green, green to amber, and amber to red. Give its typing derivation and calculate the reductions of next𝗋𝖾𝖽, next𝖺𝗆𝖻𝖾𝗋, and next𝗀𝗋𝖾𝖾𝗇 to constructor values.
The injection-free terms are generated recursively by 𝑖::=𝑥∣𝜆𝑥:𝐴.𝑖∣𝑖1𝑖2∣𝗍𝗍∣𝖿𝖿∣𝗂𝖿(𝑖0;𝑖1;𝑖2)∣(𝑖1,𝑖2)∣𝖿𝗌𝗍(𝑖)∣𝗌𝗇𝖽(𝑖)∣⋆∣𝖼𝖺𝗌𝖾(𝑖0;𝑥.𝑖1;𝑦.𝑖2)∣𝖺𝖻𝗈𝗋𝗍𝐴(𝑖). Thus neither 𝗂𝗇𝗅(𝑒) nor 𝗂𝗇𝗋(𝑒) 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.
Types are unique and synthesis is defined for the injection-free terms of definition 2.32. Given an expected type 𝐴+𝐵, checking 𝗂𝗇𝗅(𝑒) reduces to checking 𝑒 at 𝐴, and checking 𝗂𝗇𝗋(𝑒) reduces to checking 𝑒 at 𝐵.
Uniqueness and synthesis do not extend to unannotated injections: ⊢𝗂𝗇𝗅(𝗍𝗍):𝟐+𝟏and⊢𝗂𝗇𝗅(𝗍𝗍):𝟐+𝟎. 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(𝑒)⊆dom(Γ),FV(𝑒1)∖{𝑥}⊆dom(Γ),FV(𝑒2)∖{𝑦}⊆dom(Γ), which is precisely the free-variable clause for the case expression.
For item 2, first prove the one-insertion assertion Γ1,Γ2⊢𝑒:𝐴⟹Γ1,𝑤:𝐸,Γ2⊢𝑒:𝐴 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 𝑥 fresh for the enlarged context. If the last rule is Γ1,Γ2,𝑥:𝐵⊢𝑒0:𝐶Γ1,Γ2⊢𝜆𝑥:𝐵.𝑒0:𝐵→𝐶Lam, the induction hypothesis with right suffix Γ2,𝑥:𝐵 gives Γ1,𝑤:𝐸,Γ2,𝑥:𝐵⊢𝑒0:𝐶. Rule Lam then gives Γ1,𝑤:𝐸,Γ2⊢𝜆𝑥:𝐵.𝑒0:𝐵→𝐶. 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,𝑥:𝐵, and to the right branch at right suffix Γ2,𝑦:𝐶; 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,𝑧:𝐷,Γ2. In the variable case, the subject is 𝑧, 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 𝑥 outside FV(𝑎)∪dom(Γ1,𝑧:𝐷,Γ2). Its last rule is Γ1,𝑧:𝐷,Γ2,𝑥:𝐵⊢𝑒0:𝐶Γ1,𝑧:𝐷,Γ2⊢𝜆𝑥:𝐵.𝑒0:𝐵→𝐶Lam. Item 2 types 𝑎 under Γ1,Γ2,𝑥:𝐵; the induction hypothesis with right suffix Γ2,𝑥:𝐵 gives the premise of Γ1,Γ2,𝑥:𝐵⊢𝑒0[𝑎/𝑧]:𝐶Γ1,Γ2⊢𝜆𝑥:𝐵.𝑒0[𝑎/𝑧]:𝐵→𝐶Lam. Because 𝑥∉FV(𝑎), the right conclusion is the substitution of the left conclusion.
For Case, display distinct binders 𝑥,𝑦 outside the same set and each other. The final rule has the form Γ1,𝑧:𝐷,Γ2⊢𝑠:𝐵+𝐶Γ1,𝑧:𝐷,Γ2,𝑥:𝐵⊢𝑒1:𝐹Γ1,𝑧:𝐷,Γ2,𝑦:𝐶⊢𝑒2:𝐹Γ1,𝑧:𝐷,Γ2⊢𝖼𝖺𝗌𝖾(𝑠;𝑥.𝑒1;𝑦.𝑒2):𝐹Case. Item 2 types 𝑎 under both branch contexts without 𝑧:𝐷. The three induction hypotheses, using right suffixes Γ2, Γ2,𝑥:𝐵, and Γ2,𝑦:𝐶, give Γ1,Γ2⊢𝖼𝖺𝗌𝖾(𝑠[𝑎/𝑧];𝑥.𝑒1[𝑎/𝑧];𝑦.𝑒2[𝑎/𝑧]):𝐹. Because 𝑥,𝑦∉FV(𝑎), 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 𝟏, while Empty-E obtains its result from the syntax annotation 𝖺𝖻𝗈𝗋𝗍𝐶. 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 𝐴+𝐵, inversion of Inl says exactly that its payload checks at 𝐴; rebuilding Inl, with formed type 𝐵, proves soundness. Inversion and rebuilding Inr give the corresponding equivalence at 𝐵. In either case the conclusion retains both summands, although the payload determines only the selected one. ◻
The extended value judgment is generated by the three core value rules and the four additional forms ⋆, (𝑣1,𝑣2), 𝗂𝗇𝗅(𝑣), and 𝗂𝗇𝗋(𝑣), 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.
Proof. Inspect the four extended value forms and invert their typing derivations. Disjointness of ×,+,𝟏,𝟎 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 𝟎, proving the last row. ◻
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 Γ⊢(𝑣1,𝑣2):𝐴×𝐵 and then Γ⊢𝑣1:𝐴, the type of the reduct. The E-Snd-Pair case uses the second premise of the same Pair inversion and concludes Γ⊢𝑣2:𝐵. For E-Case-L, inversion of the source typing gives Γ⊢𝗂𝗇𝗅(𝑣):𝐴+𝐵,Γ,𝑥:𝐴⊢𝑒1:𝐶,Γ,𝑦:𝐵⊢𝑒2:𝐶. Inverting the first judgment gives Γ⊢𝑣:𝐴; substitution gives Γ⊢𝑒1[𝑣/𝑥]:𝐶. For E-Case-R, inversion instead gives Γ⊢𝑣:𝐵 and the right branch Γ,𝑦:𝐵⊢𝑒2:𝐶; substitution concludes Γ⊢𝑒2[𝑣/𝑦]:𝐶. 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 𝟎 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. ◻
★★☆ 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.
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.
Call-by-name evaluation uses contexts 𝐹::=[−]∣𝐹𝑒∣𝗂𝖿(𝐹;𝑒1;𝑒2) and contracts (𝜆𝑥.𝑏)𝑎 to 𝑏[𝑎/𝑥] without first evaluating 𝑎. 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 𝖾𝗋𝖺𝗌𝖾(𝑥)=𝑥,𝖾𝗋𝖺𝗌𝖾(𝜆𝑥:𝐴.𝑏)=𝜆𝑥.𝖾𝗋𝖺𝗌𝖾(𝑏),𝖾𝗋𝖺𝗌𝖾(𝑒1𝑒2)=𝖾𝗋𝖺𝗌𝖾(𝑒1)𝖾𝗋𝖺𝗌𝖾(𝑒2), extended identically through booleans and conditionals. Thus both relations act on the same erased Boolean-and-function grammar.
On the terminating term 𝑡:=(𝜆𝑥.𝗍𝗍)((𝜆𝑦.𝑦)𝖿𝖿) the two strategies reveal their order: 𝑡⟼v(𝜆𝑥.𝗍𝗍)𝖿𝖿⟼v𝗍𝗍,𝑡⟼n𝗍𝗍. Call-by-name does not evaluate an argument that the body discards.
Now let Ω:=(𝜆𝑧.𝑧𝑧)(𝜆𝑧.𝑧𝑧). This is the application 𝜔𝜔 from exercise 1.17, where the earlier lowercase 𝜔=𝜆𝑥.𝑥𝑥 named only the abstraction; uppercase Ω names the complete looping application. Its unique beta contraction reproduces Ω. Consequently (𝜆𝑥.𝗍𝗍)Ω⟼n𝗍𝗍,(𝜆𝑥.𝗍𝗍)Ω⟼v(𝜆𝑥.𝗍𝗍)Ω⟼v⋯. The source term is not typable in the simply typed lambda calculus (STLC): typing 𝑧𝑧 would require the type of 𝑧 to be both an arrow and its own domain. Thus the example separates evaluation strategies outside the language to which the safety theorem applies.
★★☆ Calculate both strategies on (𝜆𝑥.𝑥𝑥)((𝜆𝑦.𝑦)𝗍𝗍) until a value or a stuck term is reached. Then suppose the self-applied variable 𝑥 had a simple type 𝑋. Use the application rule to derive the two incompatible requirements 𝑋=𝐷→𝐶 and 𝑋=𝐷, and explain why no finite simple type satisfies them. No annotations need be invented for the untyped trace.
A propositional letter𝑃 is an atomic formula. The propositional formulas used here are generated by 𝐹::=𝑃∣⊤∣⊥∣𝐹∧𝐹∣𝐹∨𝐹∣𝐹⇒𝐹. Suppose 𝑓:𝐴→𝐵, 𝑔:𝐵→𝐶, and 𝑎:𝐴 are typed terms. Two applications form the term 𝑔(𝑓𝑎):𝐶. Replacing each type arrow by the formula connective ⇒ turns those two applications into two uses of implication elimination: first derive 𝐵 from 𝑓:𝐴⇒𝐵 and 𝑎:𝐴, then derive 𝐶 from 𝑔:𝐵⇒𝐶 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 𝑃,𝑄,… as atomic types and maps these formulas by formula𝑃⊤⊥𝐴∧𝐵𝐴∨𝐵𝐴⇒𝐵type𝑃𝟏𝟎𝐴×𝐵𝐴+𝐵𝐴→𝐵. These are the atomic types fixed in definition 2.1; no grammar extension occurs here. An assumption 𝐴 is given a label ℎ, written ℎ:𝐴. These names are proof labels, not terms in the formula language; translation turns them into term variables.
A judgment Δ⊢𝖭𝐴 says that 𝐴 follows from the finite list Δ of named assumptions. Assumption labels in this list are distinct; accordingly Δ,ℎ:𝐴 in a rule premise requires ℎ∉dom(Δ), 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 𝐴∨(𝐴⇒⊥) or double-negation elimination, the formula ((𝐴⇒⊥)⇒⊥)⇒𝐴. Its rules are
(ℎ:𝐴)∈Δ
Δ⊢𝖭𝐴
Hyp
Δ⊢𝖭⊤
→p I
Δ⊢𝖭⊥
Δ⊢𝖭𝐶
E
Δ⊢𝖭𝐴Δ⊢𝖭𝐵
Δ⊢𝖭𝐴∧𝐵
I
Δ⊢𝖭𝐴∧𝐵
Δ⊢𝖭𝐴
E_1
Δ⊢𝖭𝐴∧𝐵
Δ⊢𝖭𝐵
E_2
Δ,ℎ:𝐴⊢𝖭𝐵
Δ⊢𝖭𝐴⇒𝐵
I
Δ⊢𝖭𝐴⇒𝐵Δ⊢𝖭𝐴
Δ⊢𝖭𝐵
E
Δ⊢𝖭𝐴
Δ⊢𝖭𝐴∨𝐵
I_1
Δ⊢𝖭𝐵
Δ⊢𝖭𝐴∨𝐵
I_2
Δ⊢𝖭𝐴∨𝐵Δ,ℎ:𝐴⊢𝖭𝐶Δ,𝑘:𝐵⊢𝖭𝐶
Δ⊢𝖭𝐶
E
The letters I and E abbreviate introduction and elimination. In ⇒I, the assumption ℎ:𝐴 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: 𝑔:𝐵⇒𝐶𝑓:𝐴⇒𝐵𝑎:𝐴𝐵𝐶. Decorating its assumption leaves by variables and its two ⇒E nodes by application produces the term 𝑔(𝑓𝑎).
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: connectiveintroductionelimination⇒𝐿𝑎𝑚𝐴𝑝𝑝∧𝑃𝑎𝑖𝑟𝐹𝑠𝑡,𝑆𝑛𝑑∨𝐼𝑛𝑙,𝐼𝑛𝑟𝐶𝑎𝑠𝑒⊤𝑈𝑛𝑖𝑡−𝐼none⊥none𝐸𝑚𝑝𝑡𝑦−𝐸 Translation of a derivation of Δ⊢𝖭𝐴 using only Hyp and the displayed connective rules produces a term 𝑒. 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 Δ⊢𝑒:𝐴; conversely, erasing terms from a typing derivation generated by the corresponding rules, after erasing lambda annotations, produces a natural-deduction derivation of Δ⊢𝖭𝐴. 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 𝐷, write T(𝐷) for its term decoration. For a typing derivation 𝑇, write E(𝑇) 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 Δ,ℎ:𝐴⊢𝖭𝐵Δ⊢𝖭𝐴⇒𝐵intoΔ,𝑥:𝐴⊢𝑏:𝐵Δ⊢𝜆𝑥:𝐴.𝑏:𝐴→𝐵Lam. Here choose 𝑥=ℎ; 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 Δ⊢𝖭𝐴∨𝐵Δ,ℎ:𝐴⊢𝖭𝐶Δ,𝑘:𝐵⊢𝖭𝐶Δ⊢𝖭𝐶 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(𝐷))=𝐷,term(T(E(𝑇)))=𝛼term(𝑇),skel(T(E(𝑇)))=skel(𝑇). 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. ◻
★★☆ Give both a natural-deduction tree and a typing derivation for (𝐴⇒𝐵)⇒(𝐵⇒𝐶)⇒(𝐴⇒𝐶). Then erase the term labels from your typing derivation and verify node by node that the original natural-deduction tree is recovered.
The natural-deduction proof of 𝐴∧𝐵⇒𝐵∧𝐴 is represented by the already typed program swap𝐴,𝐵. Here are the two trees node for node: 𝑝:𝐴∧𝐵∈𝑝:𝐴∧𝐵𝑝:𝐴∧𝐵⊢𝖭𝐴∧𝐵Hyp𝑝:𝐴∧𝐵⊢𝖭𝐵E2𝑝:𝐴∧𝐵∈𝑝:𝐴∧𝐵𝑝:𝐴∧𝐵⊢𝖭𝐴∧𝐵Hyp𝑝:𝐴∧𝐵⊢𝖭𝐴E1𝑝:𝐴∧𝐵⊢𝖭𝐵∧𝐴I⋅⊢𝖭(𝐴∧𝐵)⇒(𝐵∧𝐴)I and 𝑝:𝐴×𝐵∈𝑝:𝐴×𝐵𝑝:𝐴×𝐵⊢𝑝:𝐴×𝐵Var𝑝:𝐴×𝐵⊢𝗌𝗇𝖽(𝑝):𝐵Snd𝑝:𝐴×𝐵∈𝑝:𝐴×𝐵𝑝:𝐴×𝐵⊢𝑝:𝐴×𝐵Var𝑝:𝐴×𝐵⊢𝖿𝗌𝗍(𝑝):𝐴Fst𝑝:𝐴×𝐵⊢(𝗌𝗇𝖽(𝑝),𝖿𝗌𝗍(𝑝)):𝐵×𝐴Pair⋅⊢𝜆𝑝:𝐴×𝐵.(𝗌𝗇𝖽(𝑝),𝖿𝗌𝗍(𝑝)):(𝐴×𝐵)→(𝐵×𝐴)Lam. Erasing terms and reading the connectives through the table gives the first tree exactly.
The formula (𝐴⇒𝐶)∧(𝐵⇒𝐶)⇒(𝐴∨𝐵⇒𝐶) has proof term 𝜆𝑝:(𝐴→𝐶)×(𝐵→𝐶).𝜆𝑠:𝐴+𝐵.𝖼𝖺𝗌𝖾(𝑠;𝑥.𝖿𝗌𝗍(𝑝)𝑥;𝑦.𝗌𝗇𝖽(𝑝)𝑦). In the left branch, Fst derives a proof of 𝐴⇒𝐶, which App applies to the temporary proof 𝑥:𝐴. In the right branch, Snd derives 𝐵⇒𝐶 and App applies it to 𝑦:𝐵. The common branch type is 𝐶, exactly the side condition of disjunction elimination.
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.
The root relation 𝑟⇝𝗉𝑞 consists of (𝜆𝑥:𝐴.𝑏)𝑎⇝𝗉𝑏[𝑎/𝑥],𝖿𝗌𝗍((𝑎,𝑏))⇝𝗉𝑎,𝗌𝗇𝖽((𝑎,𝑏))⇝𝗉𝑏,𝖼𝖺𝗌𝖾(𝗂𝗇𝗅(𝑎);𝑥.𝑏;𝑦.𝑐)⇝𝗉𝑏[𝑎/𝑥],𝖼𝖺𝗌𝖾(𝗂𝗇𝗋(𝑎);𝑥.𝑏;𝑦.𝑐)⇝𝗉𝑐[𝑎/𝑦],𝗂𝖿(𝗍𝗍;𝑏;𝑐)⇝𝗉𝑏,𝗂𝖿(𝖿𝖿;𝑏;𝑐)⇝𝗉𝑐. A proof context is a term with one hole, generated by 𝐾::=[−]∣𝜆𝑥:𝐴.𝐾∣𝐾𝑒∣𝑒𝐾∣𝗂𝖿(𝐾;𝑒1;𝑒2)∣𝗂𝖿(𝑒;𝐾;𝑒2)∣𝗂𝖿(𝑒;𝑒1;𝐾)∣(𝐾,𝑒)∣(𝑒,𝐾)∣𝖿𝗌𝗍(𝐾)∣𝗌𝗇𝖽(𝐾)∣𝗂𝗇𝗅(𝐾)∣𝗂𝗇𝗋(𝐾)∣𝖼𝖺𝗌𝖾(𝐾;𝑥.𝑒1;𝑦.𝑒2)∣𝖼𝖺𝗌𝖾(𝑒;𝑥.𝐾;𝑦.𝑒2)∣𝖼𝖺𝗌𝖾(𝑒;𝑥.𝑒1;𝑦.𝐾)∣𝖺𝖻𝗈𝗋𝗍𝐴(𝐾). Plugging is capture-permitting at the displayed hole: 𝐾[𝑒] denotes the literal replacement of the hole by 𝑒. Bound names in 𝐾 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 𝑟⇝𝗉𝑞𝐾[𝑟]⟶𝗉𝐾[𝑞]P−Ctx. 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 ⟶∗𝗉 for reflexive transitive closure.
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 𝐵×𝐶, so its selected component already has the required type.
For the left sum contraction, inversion gives Γ⊢𝑎:𝐵 and Γ,𝑥:𝐵⊢𝑏:𝐴; item 3 of proposition 2.29 gives Γ⊢𝑏[𝑎/𝑥]:𝐴. For the right contraction, interchange the two summands and branch binders in that derivation: inversion gives Γ⊢𝑎:𝐶 and Γ,𝑦:𝐶⊢𝑐:𝐴, so the same extended substitution result gives Γ⊢𝑐[𝑎/𝑦]:𝐴. 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 𝐾. The hole case is the root result. For 𝜆𝑥:𝐴.𝐾, invert Lam, apply the induction hypothesis under Γ,𝑥:𝐴, and rebuild Lam. For 𝐾𝑒 and 𝑒𝐾, 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 𝑥:𝐵, or the right branch under 𝑦:𝐶, and rebuild Case. These alternatives are exactly the context grammar, so Γ⊢𝐾[𝑞]:𝐴 follows from Γ⊢𝐾[𝑟]:𝐴 in every case. ◻
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.
★★☆ Reduce the proof term of example 2.35 after applying it to (𝑓,𝑔) and then to 𝗂𝗇𝗅(𝑎) in the context 𝑓:𝐴→𝐶,𝑔:𝐵→𝐶,𝑎:𝐴. Check the injection against 𝐴+𝐵. Label the projection, case, and beta contractions. Use subject reduction to write the common type 𝐶 after each step.
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 𝑃(Γ⊢𝑒:𝐴):=𝖲𝖭(𝑒), the application case would have only 𝖲𝖭(𝑒1),𝖲𝖭(𝑒2)⟹̸𝖲𝖭(𝑒1𝑒2). When 𝑒1=𝜆𝑥:𝐴.𝑏 and 𝑒2=𝑣, the new reduct is 𝑏[𝑣/𝑥]; 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 𝑙𝑒𝑚𝑚𝑎2.47supportstheheightinductionsin𝑙𝑒𝑚𝑚𝑎2.40whoseclausesprove𝑙𝑒𝑚𝑚𝑎2.52𝑙𝑒𝑚𝑚𝑎2.53whichdischargethetypingcasesof𝑡ℎ𝑒𝑜𝑟𝑒𝑚2.42whosenormalizationclauseyields𝑡ℎ𝑒𝑜𝑟𝑒𝑚2.43. Each vertical phrase states the named use made by the box below it; the display is bookkeeping, not a proof.
Strong normalization, written 𝖲𝖭(𝑒), is the property that there is no infinite chain 𝑒=𝑒0⟶𝗉𝑒1⟶𝗉⋯. The introduction forms are 𝜆𝑥:𝐴.𝑏,𝗍𝗍,𝖿𝖿,⋆,(𝑎,𝑏),𝗂𝗇𝗅(𝑎),𝗂𝗇𝗋(𝑏). 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 (𝜆𝑥:𝐴.𝑏)𝑎. 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 (𝜆𝑥:𝐴.𝑏)𝑎 from its contractum, so the beta case of the fundamental lemma would stop at exactly the redex that typing creates.
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.
Every term has finitely many immediate proof reducts. If 𝖲𝖭(𝑒), there is a finite maximum length 𝜈(𝑒) of a reduction beginning at 𝑒, and every step 𝑒⟶𝗉𝑒′ satisfies 𝜈(𝑒′)<𝜈(𝑒).
Proof. Finite branching is structural induction on 𝑒. 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 𝑒 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 𝖲𝖭(𝑒). Hence a maximum branch length 𝜈(𝑒) exists. A step to 𝑒′ removes the first edge from every continuation, so 𝜈(𝑒′)<𝜈(𝑒). 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.
For every type 𝐴, the reducible termsR𝐴 are defined by structural recursion on 𝐴. At atomic and nullary types, reducibility is strong normalization: R𝑃=R𝟐=R𝟏=R𝟎={𝑒∣𝖲𝖭(𝑒)}. The arrow and product clauses use only their immediate component types: 𝑒∈R𝐴→𝐵⟺forevery𝑎∈R𝐴,𝑒𝑎∈R𝐵,𝑒∈R𝐴×𝐵⟺𝖿𝗌𝗍(𝑒)∈R𝐴and𝗌𝗇𝖽(𝑒)∈R𝐵. 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 𝑒∈R𝐴+𝐵 exactly when 𝖲𝖭(𝑒) and both canonical-reduct conditions hold: 𝑒⟶∗𝗉𝗂𝗇𝗅(𝑎)⟹𝑎∈R𝐴,𝑒⟶∗𝗉𝗂𝗇𝗋(𝑏)⟹𝑏∈R𝐵.
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 𝟐 and 𝟎 clauses do not quantify over an arbitrary R𝐶; 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 𝑒∈R?𝟐⟺𝗂𝖿(𝑒;𝑏1;𝑏2)∈R𝐶foreverytype𝐶and𝑏1,𝑏2∈R𝐶. Taking 𝐶=𝟐→𝟐 already asks for a candidate at a type larger than 𝟐 while defining the Boolean candidate. This is not structural recursion on the current type. The displayed definition instead uses strong normalization at 𝟐 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.
Proof. Induct on the structure of 𝐴, proving the clauses in their displayed order at each type.
Base types.
For 𝑃,𝟐,𝟏,𝟎, 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 𝑛 has a well-founded reduction tree. There are finitely many of them, so adjoining the root 𝑛 gives another well-founded tree.
Arrow types.
Suppose 𝐴=𝐵→𝐶. Any variable 𝑧 belongs to R𝐵 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 𝑒∈R𝐵→𝐶, then 𝑒𝑧∈R𝐶, hence 𝑒𝑧 is strongly normalizing by clause 1 at 𝐶. An infinite reduction of 𝑒 would lift by application congruence to one of 𝑒𝑧, proving clause 1 at the arrow. If 𝑒⟶𝗉𝑒′ and 𝑎∈R𝐵, then 𝑒𝑎⟶𝗉𝑒′𝑎; clause 2 at 𝐶 proves 𝑒′𝑎∈R𝐶, which proves clause 2 at the arrow.
For neutral expansion at 𝐵→𝐶, fix 𝑎∈R𝐵 and perform a second, inner induction on 𝜈(𝑎). The outer induction hypotheses concern the smaller types 𝐵,𝐶; the inner hypothesis concerns arguments of smaller reduction height. The application 𝑛𝑎 is neutral because an application is not an introduction form. It has no root beta contraction because the neutral term 𝑛 is not an abstraction. An immediate reduct is 𝑛′𝑎, where the hypothesis gives 𝑛′∈R𝐵→𝐶, or 𝑛𝑎′, where 𝜈(𝑎′)<𝜈(𝑎). Reduction closure at the smaller type 𝐵 gives 𝑎′∈R𝐵. The arrow clause and the induction hypothesis place these two reducts in R𝐶: the arrow clause handles 𝑛′𝑎, and the inner height induction, with this membership of 𝑎′, handles 𝑛𝑎′. Neutral expansion at the smaller type 𝐶 gives 𝑛𝑎∈R𝐶. Since 𝑎 was arbitrary, 𝑛 belongs to the arrow candidate.
Product types.
Suppose 𝐴=𝐵×𝐶. If 𝑒 reduced forever, so would 𝖿𝗌𝗍(𝑒); clause 1 at 𝐵 therefore proves clause 1 for 𝑒. For clause 2, place 𝑒⟶𝗉𝑒′ under each projection and use clause 2 at 𝐵 and 𝐶. For clause 3, 𝖿𝗌𝗍(𝑛) is neutral because 𝑛 is not a pair. Its immediate reducts are exactly 𝖿𝗌𝗍(𝑛′) for immediate reducts 𝑛′ of 𝑛; each belongs to R𝐵 by the hypothesis and the product clause. Clause 3 at 𝐵 gives the first projection condition. For the second, replace the smaller target type 𝐵 by 𝐶 and the context 𝖿𝗌𝗍([−]) by 𝗌𝗇𝖽([−]). For every immediate reduct 𝑛′ of 𝑛, the product hypothesis gives 𝗌𝗇𝖽(𝑛′)∈R𝐶; clause 3 at 𝐶 therefore gives 𝗌𝗇𝖽(𝑛)∈R𝐶. Both projection conditions hold, so 𝑛∈R𝐵×𝐶.
Sum types.
Suppose 𝐴=𝐵+𝐶. Clause 1 is part of the definition. For clause 2, 𝑒⟶𝗉𝑒′ preserves strong normalization; moreover any reduction 𝑒′⟶∗𝗉𝗂𝗇𝗅(𝑏) extends to one from 𝑒, so 𝑏∈R𝐵. Exchanging the left and right summands gives the required payload in R𝐶 for a reachable right injection.
For clause 3, every immediate reduct 𝑛′ is in R𝐵+𝐶 and hence is strongly normalizing by clause 1 just proved. Finite branching therefore gives 𝖲𝖭(𝑛). If 𝑛⟶∗𝗉𝗂𝗇𝗅(𝑏), the path has positive length because 𝑛 is not an introduction. Its first step reaches some 𝑛′∈R𝐵+𝐶, whose canonical-reduct condition gives 𝑏∈R𝐵. For a reduction to 𝗂𝗇𝗋(𝑐), the same positive-length factorization reaches an immediate 𝑛′∈R𝐵+𝐶, whose right canonical-reduct condition gives 𝑐∈R𝐶. Thus all parts of the sum definition hold. ◻
For a term 𝑡 with 𝑧∉FV(𝑡), choose a raw representative ¯𝑡 with 𝑧∉Names(¯𝑡), and define 𝑡⟨𝑧/𝑥⟩ to be the alpha-class of ¯𝑡⟨𝑧/𝑥⟩. This definition is independent of the chosen representative. If 𝑧∉FV(𝑒)∪FV(𝑒′)∪{𝑥}, then 𝑒⟶𝗉𝑒′⟺𝑒⟨𝑧/𝑥⟩⟶𝗉𝑒′⟨𝑧/𝑥⟩,𝖲𝖭(𝑒)⟺𝖲𝖭(𝑒⟨𝑧/𝑥⟩). The same equivalences hold with ⟶𝗉 replaced by ⟶∗𝗉.
Proof. First, fresh-representative clause (B3) gives the required ¯𝑡. Fresh-substitution clause (B5) identifies the alpha-class of its raw renaming with the quotient substitution 𝑡[𝑧/𝑥]. Well-definedness of substitution, clause (B4), therefore proves independence of ¯𝑡.
For preservation of one step, write it as 𝐾[𝑟]⟶𝗉𝐾[𝑞] and use clause (B3) to choose representatives of the complete source and target whose binders avoid {𝑥,𝑧}. Renaming distributes over the context and over each of the seven root equations. In the beta root, for example, (𝑏[𝑎/𝑦])⟨𝑧/𝑥⟩=𝑏⟨𝑧/𝑥⟩[𝑎⟨𝑧/𝑥⟩/𝑦] because 𝑦 was chosen outside {𝑥,𝑧}; 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 𝑥, then apply preservation to the inverse renaming 𝑧↦𝑥. Cancellation clause (B6), once for 𝑒 and once for 𝑒′, 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. ◻
Proof of Lemma 2.51 — Reduction and substitution compatibility
Proof. Prove item 3 first by structural induction on 𝑏. Variables split into 𝑥, 𝑦, 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(𝑎)∪FV(𝑑)∪{𝑥,𝑦}. 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 𝐾[𝑟]⟶𝗉𝐾[𝑞], freshen the binders of 𝐾,𝑟,𝑞 outside FV(𝑎)∪{𝑥}, and induct on 𝐾. Substitution rebuilds the same context around the substituted root. At a beta root (𝜆𝑦.𝑏)𝑐⇝𝗉𝑏[𝑐/𝑦], item 3 gives (𝑏[𝑐/𝑦])[𝑎/𝑥]=𝑏[𝑎/𝑥][𝑐[𝑎/𝑥]/𝑦], 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 𝑏 whose binders lie outside the finite set FV(𝑎)∪FV(𝑎′)∪{𝑥}, and use structural induction on that representative. A variable different from 𝑥 gives reflexivity; the variable 𝑥 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(𝑎)∪FV(𝑎′)∪{𝑥} 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 𝑎 or 𝑎′. ◻
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.
For item 1, induct on 𝜈(𝑒)+𝜈(𝑏)+𝜈(𝑐). The conditional is neutral. Its root reduct is 𝑏 when 𝑒=𝗍𝗍 and 𝑐 when 𝑒=𝖿𝖿, hence is reducible by hypothesis. Its immediate reducts are exactly 𝗂𝖿(𝑒′;𝑏;𝑐)𝑒⟶𝗉𝑒′,𝗂𝖿(𝑒;𝑏′;𝑐)𝑏⟶𝗉𝑏′,𝗂𝖿(𝑒;𝑏;𝑐′)𝑐⟶𝗉𝑐′,𝑏𝑒=𝗍𝗍,𝑐𝑒=𝖿𝖿. Thus every nonroot immediate step reduces exactly one of 𝑒,𝑏,𝑐. 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 R𝐶. Saturation clause 3 now gives the result.
For item 2, choose distinct variables 𝑧,𝑤 outside the finite set FV(𝑏)∪FV(𝑐)∪{𝑥,𝑦}. Saturation clause 3 gives 𝑧∈R𝐴 and 𝑤∈R𝐵. Hence 𝑏[𝑧/𝑥],𝑐[𝑤/𝑦]∈R𝐶, so both are strongly normalizing. Fresh renaming preserves the reduction tree, and therefore 𝑏 and 𝑐 themselves are strongly normalizing.
Induct on 𝜈(𝑒)+𝜈(𝑏)+𝜈(𝑐). The case term is neutral. If 𝑒=𝗂𝗇𝗅(𝑎), the zero-step canonical-reduct condition in R𝐴+𝐵 gives 𝑎∈R𝐴, so the root reduct 𝑏[𝑎/𝑥] is reducible. If 𝑒=𝗂𝗇𝗋(𝑑), its right canonical-reduct condition gives 𝑑∈R𝐵, so the root reduct 𝑐[𝑑/𝑦] is reducible by the right-branch hypothesis. A step in 𝑒 uses saturation clause 2 and the induction hypothesis. If 𝑏⟶𝗉𝑏′, then 𝑏[𝑎/𝑥]⟶𝗉𝑏′[𝑎/𝑥] for every reducible 𝑎; saturation clause 2 therefore establishes the left-branch hypothesis for 𝑏′. The measure decreases, so the induction hypothesis applies. If 𝑐⟶𝗉𝑐′, compatibility gives 𝑐[𝑑/𝑦]⟶𝗉𝑐′[𝑑/𝑦] for every 𝑑∈R𝐵; reduction closure establishes the right-branch hypothesis for 𝑐′, and the decreased height allows the induction hypothesis. Thus every immediate reduct of the case term lies in R𝐶, and saturation clause 3 concludes.
For item 3, induct on 𝜈(𝑒). The abort term is neutral and has no root contraction. Every immediate reduct is 𝖺𝖻𝗈𝗋𝗍𝐶(𝑒′) with 𝑒′∈R𝟎 by saturation clause 2 and 𝜈(𝑒′)<𝜈(𝑒); 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: rootredexproperarguments(𝜆𝑥:𝐴.𝑏)𝑎𝑏,𝑎𝖿𝗌𝗍((𝑎,𝑏)),𝗌𝗇𝖽((𝑎,𝑏))𝑎,𝑏𝖼𝖺𝗌𝖾(𝗂𝗇𝗅(𝑎);𝑥.𝑏;𝑦.𝑐),𝖼𝖺𝗌𝖾(𝗂𝗇𝗋(𝑎);𝑥.𝑏;𝑦.𝑐)𝑎,𝑏,𝑐𝗂𝖿(𝗍𝗍;𝑏;𝑐),𝗂𝖿(𝖿𝖿;𝑏;𝑐)𝑏,𝑐. This table defines the phrase for all seven root contractions.
Let 𝑟⟶𝗉𝑞 be one of the seven root contractions in definition 2.36. If 𝑞∈R𝐶 and every proper immediate term argument of 𝑟 is strongly normalizing, then 𝑟∈R𝐶.
Proof. Induct on the sum of the reduction heights of the proper arguments. The redex 𝑟 is neutral. Its root reduct 𝑞 is reducible by hypothesis. Any other immediate step reduces one proper argument and leaves a principal redex 𝑟′ of the same kind. Its root contractum 𝑞′ is reachable from 𝑞 by zero or more compatible steps: a step in an unused branch leaves 𝑞 unchanged; a step in a selected body gives one compatible step; and a step 𝑎⟶𝗉𝑎′ in a substituted argument gives 𝑏[𝑎/𝑥]⟶∗𝗉𝑏[𝑎′/𝑥] by the compatibility fact above. Repeated use of saturation clause 2 gives 𝑞′∈R𝐶. The height sum has decreased, so the induction hypothesis gives 𝑟′∈R𝐶. Every immediate reduct of 𝑟 is now reducible, and saturation clause 3 gives 𝑟∈R𝐶. ◻
For example, if 𝑏[𝑎/𝑥]∈R𝐶 and both 𝑏 and 𝑎 are strongly normalizing, principal expansion gives (𝜆𝑥:𝐴.𝑏)𝑎∈R𝐶. The strong-normalization premise for 𝑏 matters because proof reduction is compatible under lambda bodies.
A complete calculation is already visible at Boolean type. The two values 𝗍𝗍 and 𝖿𝖿 belong to R𝟐. If 𝑎∈R𝟐, eliminator closure gives 𝗂𝖿(𝑎;𝖿𝖿;𝗍𝗍)∈R𝟐. The abstraction body is strongly normalizing, so principal expansion applied to an arbitrary such 𝑎 yields (𝜆𝑥:𝟐.𝗂𝖿(𝑥;𝖿𝖿;𝗍𝗍))𝑎∈R𝟐. Therefore Boolean negation belongs to R𝟐→𝟐, exactly by the arrow clause.
For Γ=𝑥1:𝐴1,…,𝑥𝑛:𝐴𝑛, a simultaneous substitution 𝜎 is a finite map from the declared variables 𝑥𝑖 to terms. It acts simultaneously and capture-avoidingly on 𝑒; variables outside its domain are left unchanged. Write FV(rng(𝜎)):=⋃𝑥∈dom(𝜎)FV(𝜎(𝑥)). Constants are fixed, and the nonbinding clauses are 𝑥[𝜎]={𝜎(𝑥)𝑥∈dom(𝜎),𝑥otherwise,(𝑒1𝑒2)[𝜎]=𝑒1[𝜎]𝑒2[𝜎],𝗂𝖿(𝑒;𝑒1;𝑒2)[𝜎]=𝗂𝖿(𝑒[𝜎];𝑒1[𝜎];𝑒2[𝜎]),(𝑒1,𝑒2)[𝜎]=(𝑒1[𝜎],𝑒2[𝜎]),𝖿𝗌𝗍(𝑒)[𝜎]=𝖿𝗌𝗍(𝑒[𝜎]),𝗌𝗇𝖽(𝑒)[𝜎]=𝗌𝗇𝖽(𝑒[𝜎]),𝗂𝗇𝗅(𝑒)[𝜎]=𝗂𝗇𝗅(𝑒[𝜎]),𝗂𝗇𝗋(𝑒)[𝜎]=𝗂𝗇𝗋(𝑒[𝜎]),𝖺𝖻𝗈𝗋𝗍𝐶(𝑒)[𝜎]=𝖺𝖻𝗈𝗋𝗍𝐶(𝑒[𝜎]). Here 𝗍𝗍,𝖿𝖿,⋆ are the fixed constants. For an abstraction, choose a representative with 𝑥∉FV(rng(𝜎)) and define (𝜆𝑥:𝐴.𝑏)[𝜎]=𝜆𝑥:𝐴.𝑏[𝜎∖𝑥]. For a case choose its two binders independently outside FV(rng(𝜎)) and each other, then define 𝖼𝖺𝗌𝖾(𝑒;𝑥.𝑒1;𝑦.𝑒2)[𝜎]=𝖼𝖺𝗌𝖾(𝑒[𝜎];𝑥.𝑒1[𝜎∖𝑥];𝑦.𝑒2[𝜎∖𝑦]). 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 𝑢 outside the name sets of both bodies and of all those range representatives. Clause (B3) permits both abstractions to be opened at 𝑢. Structural induction identifies the two substituted opened bodies, and rebuilding the common binder 𝑢 identifies the output abstractions up to alpha-equivalence.
For two displayed case representatives, choose distinct names 𝑢,𝑣 outside the name sets of both complete case representatives and all range representatives. Clause (B3) opens both left branches at 𝑢 and both right branches at 𝑣. Structural induction identifies the substituted scrutinees and the two pairs of substituted opened branch bodies. Rebuilding the common branch binders 𝑢,𝑣 identifies the output cases up to alpha-equivalence. Thus simultaneous substitution is well-defined on alpha-classes.
In particular, if 𝑥∉dom(𝜎) and is fresh for the range of 𝜎, then 𝑏[𝜎,𝑥↦𝑎]=𝑏[𝜎][𝑎/𝑥]. This equation is proved by structural induction on 𝑏. The variable and nonbinding cases are the displayed clauses. For an abstraction choose its binder 𝑦 outside FV(rng(𝜎))∪FV(𝑎)∪{𝑥}; both sides reattach 𝜆𝑦 to the body equation. For a case choose distinct branch binders 𝑦,𝑧 outside the same finite set. Both sides use the same substituted scrutinee and reattach 𝑦 and 𝑧 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 𝜎(𝑥𝑖)∈R𝐴𝑖 for every 𝑖. Write 𝑒[𝜎] for simultaneous capture-avoiding substitution. The empty substitution is reducible for the empty context. Write 𝜎,𝑥↦𝑎 for the map which agrees with 𝜎 away from 𝑥 and sends 𝑥 to 𝑎.
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 𝑧 outside FV(𝑏[𝜎])∪FV(rng(𝜎))∪dom(Γ)∪{𝑥} and map 𝑥 first to 𝑧. Saturation clause 3 and the induction hypothesis give 𝑏[𝜎,𝑥↦𝑧]∈R𝐵. This term is a fresh renaming of 𝑏[𝜎]; saturation clause 1 and lemma 2.50 therefore give 𝖲𝖭(𝑏[𝜎]) in both renaming directions.
For arbitrary 𝑎∈R𝐴, the induction hypothesis under 𝜎,𝑥↦𝑎 gives the beta contractum 𝑏[𝜎,𝑥↦𝑎]∈R𝐵. Saturation clause 1 gives 𝖲𝖭(𝑎), so principal expansion admits (𝜆𝑥:𝐴.𝑏[𝜎])𝑎: 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 𝑎∈R𝐴, hence 𝖲𝖭(𝑎) and 𝖲𝖭(𝗂𝗇𝗅(𝑎)). Every canonical reduct 𝗂𝗇𝗅(𝑎′) comes from 𝑎⟶∗𝗉𝑎′, so saturation clause 2 gives 𝑎′∈R𝐴; no right injection is reachable. Thus 𝗂𝗇𝗅(𝑎)∈R𝐴+𝐵. In Inr, the induction hypothesis gives 𝑏∈R𝐵 and hence 𝖲𝖭(𝗂𝗇𝗋(𝑏)); every reachable 𝗂𝗇𝗋(𝑏′) has 𝑏′∈R𝐵 by reduction closure, while no left injection is reachable. Therefore 𝗂𝗇𝗋(𝑏)∈R𝐴+𝐵.
In the Case case, extend 𝜎 by an arbitrary reducible branch argument. The two branch induction hypotheses give ∀𝑎∈R𝐴,𝑒1[𝜎][𝑎/𝑥]∈R𝐶,∀𝑑∈R𝐵,𝑒2[𝜎][𝑑/𝑦]∈R𝐶. The scrutinee induction hypothesis and eliminator closure item 2 now give the substituted case term.
The constants 𝗍𝗍,𝖿𝖿,⋆ 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 𝟎. ◻
Proof. Map every variable 𝑥:𝐴 in Γ to itself. Variables are reducible by neutral expansion, so this identity substitution is reducible for Γ. The fundamental lemma gives 𝑒∈R𝐴, and saturation clause 1 gives 𝖲𝖭(𝑒). ◻
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 𝐾𝑒 or 𝑣𝐾, 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. ◻
Proof of Corollary 2.58 — Call-by-value normalization
Proof. Strong normalization gives the finite height 𝜈(𝑒). If 𝑒 is not a value, by extended progress there is a step 𝑒⟼𝑒1; by lemma 2.57, 𝜈(𝑒1)<𝜈(𝑒). Well-founded induction on this natural number therefore reaches a term 𝑣 with no call-by-value step. Progress makes 𝑣 a value. Composing the selected steps gives 𝑒⟼∗𝑣, and iterated preservation gives ⋅⊢𝑣:𝐴. ◻
★★☆ Assume 𝑒∈R𝐴×𝐵 and 𝑒⟶𝗉𝑒′. Display the two lifted steps 𝖿𝗌𝗍(𝑒)⟶𝗉𝖿𝗌𝗍(𝑒′) and 𝗌𝗇𝖽(𝑒)⟶𝗉𝗌𝗇𝖽(𝑒′), apply reduction closure at 𝐴 and 𝐵, and conclude 𝑒′∈R𝐴×𝐵. Then prove directly from definition 2.39, lemma 2.53 that if 𝑎∈R𝐴 and 𝑏∈R𝐵, then (𝑎,𝑏)∈R𝐴×𝐵.
Suppose Γ⊢𝑛:𝐴 and 𝑛 has no ⟶𝗉 reduct. Then exactly one of the following holds:
𝑛 is an introduction form;
𝑛 is variable-headed, according to the grammar ℎ::=𝑥∣ℎ𝑒∣𝖿𝗌𝗍(ℎ)∣𝗌𝗇𝖽(ℎ)∣𝗂𝖿(ℎ;𝑒1;𝑒2)∣𝖼𝖺𝗌𝖾(ℎ;𝑥.𝑒1;𝑦.𝑒2)∣𝖺𝖻𝗈𝗋𝗍𝐴(ℎ), and its head variable has a declaration in Γ.
Proof. Induct on the structure of 𝑛. A variable is in the second class by typing inversion; every introduction form is in the first. It remains to consider an elimination.
For 𝑛=𝑒1𝑒2, both subterms are normal. Apply the induction hypothesis to the well-typed function 𝑒1. If it is variable-headed, then so is 𝑛. If it is an introduction, typing inversion at an arrow type forces it to be an abstraction, making 𝑛 a beta-redex, contrary to normality. For 𝖿𝗌𝗍(𝑒) and 𝗌𝗇𝖽(𝑒), an introductory 𝑒 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 𝟐 must be 𝗍𝗍 or 𝖿𝖿, again creating a redex. Finally, an introductory term cannot have type 𝟎: the introduction rules conclude only at 𝟐, an arrow, a product, a sum, or 𝟏. Thus the scrutinee of 𝖺𝖻𝗈𝗋𝗍𝐶(𝑒) 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.
Proof. Assume such an 𝑒. Strong normalization and lemma 2.47 give the natural-number measure 𝜈(𝑒). While a reduct exists, choose one; its measure is strictly smaller, so after finitely many choices a normal form 𝑛 is reached. Many-step subject reduction, corollary 2.44, gives ⊢𝑛:𝟎. By lemma 2.59, 𝑛 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 𝟎. 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 𝑒⟼∗𝑣 for a value 𝑣:𝟎; extended canonical forms shows that no such 𝑣 exists. Translating a hypothetical natural-deduction derivation of ⊥ from no assumptions would give a closed term of 𝟎, 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: id𝟐:=𝜆𝑥:𝟐.𝑥:𝟐→𝟐,id𝟏:=𝜆𝑥:𝟏.𝑥:𝟏→𝟏. 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.
★★☆ Type the two identities above and use each twice in one product term. Then attempt to bind a single simply typed variable 𝑖 and use 𝑖 at both types. Use uniqueness of types to prove that the two required arrow types for 𝑖 would have to be equal, and exhibit the unequal domain or codomain that contradicts this equality.
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.
★★☆ Let 𝑤,𝑥,𝑦,𝑧 be distinct. Compute, with every freshening step shown, 𝖼𝖺𝗌𝖾(𝑧;𝑥.(𝑥,𝑤);𝑦.(𝑤,𝑦))[(𝑥,𝑦)/𝑤]. Mark the free occurrences in the result. Explain why retaining the left binder would capture the inserted 𝑥, while retaining the right binder would capture the inserted 𝑦.
★★★ Begin with the call-by-value function-and-Boolean STLC frames, obtained by restricting definition 1.67: 𝐸::=[−]∣𝐸𝑒∣𝑣𝐸∣𝗂𝖿(𝐸;𝑒1;𝑒2). Add frames for products, projections, injections, the case scrutinee, and 𝖺𝖻𝗈𝗋𝗍𝐴(𝐸); 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.
★★★ Construct both directions of 𝐴×(𝐵+𝐶)⟷(𝐴×𝐵)+(𝐴×𝐶). 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: (𝖿𝗌𝗍(𝑝),𝗌𝗇𝖽(𝑝))=𝑝,𝜆𝑥:𝐴.𝑓𝑥=𝑓(𝑥∉FV(𝑓)).
The next two problems form one normalization reconstruction: the first rebuilds neutral expansion, and the second applies the resulting saturation mechanism to Boolean elimination.
★★★ For every type 𝐴, let 𝑁(𝐴) be the assertion that every neutral term 𝑛 belongs to R𝐴 whenever all immediate reducts of 𝑛 belong to R𝐴. Prove 𝑁(𝐴) by structural induction on 𝐴, 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 𝑁(𝐵) or 𝑁(𝐶). 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 𝑁(𝐴) to a variable, which is neutral and has no immediate reducts, to derive 𝑥∈R𝐴.
★★★ Prove item 1 of lemma 2.52 in full. Use induction on 𝜈(𝑒)+𝜈(𝑏)+𝜈(𝑐), list the possible immediate reductions of 𝗂𝖿(𝑒;𝑏;𝑐), and identify where each saturation clause is used. Then prove directly that 𝗍𝗍,𝖿𝖿∈R𝟐.
★★★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.
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.
Implement free-name calculation, deterministic fresh-name selection, and capture-avoiding substitution. On the body 𝜆𝑦:𝟐.𝑥, substitute the free variable 𝑦 for 𝑥. Check that the implementation freshens the binder and that naive textual replacement would capture the inserted 𝑦.
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.
Accept not𝖿𝖿 at 𝟐, validate its returned derivation, and evaluate the same source term to 𝗍𝗍. Also evaluate not𝗍𝗍 to 𝖿𝖿. Reject 𝗍𝗍𝖿𝖿 and 𝜆𝑥:𝟐.𝑥𝑥.
Treat finite raw terms as the executable input. Reject 𝜆𝑥:𝟐.𝜆𝑥:𝟐.𝑥 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 𝐴 can annotate 𝜆𝑥:𝐴.𝑥𝑥: typing the body would force 𝐴=𝐴→𝐵 for some 𝐵. 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.
Print the complete validated derivation returned for not𝖿𝖿, including the context at every Var node.
Print its call-by-value trace from the named source through the beta and conditional contractions to 𝗍𝗍. Beside each term, print the type returned by a fresh checker run.
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.
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.
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.