Existential Types, Abstract Data, and Representation Independence
Universal polymorphism lets the client choose a type. Abstract data requires the implementation to choose and hide one while exporting operations that share it.
Here an implementation is a package value: a chosen representation constructor together with operations on it. An abstract interface is the existential type visible outside that package, and a client is a closed term whose input type mentions the interface but not its hidden constructor. Opaque sealing means that typing gives the client no syntax for naming that constructor outside an unpacking.
Existential packages hide a constructor
Kinds let an interface mention a representation constructor with its proper arity. They do not hide that constructor. For example, if a counter is published with state type ℕ, a client may apply 𝗌𝗎𝖼 directly to its initial state. Such a client depends on the representation, even if the library intended the state to be manipulated only through its step and read operations.
The desired interface has the shape 𝑋×((𝑋→𝑋)×(𝑋→ℕ)), but the name 𝑋 should be local to one implementation and to one use of that implementation. An existential type binds precisely such a name. Its introduction rule seals a witness constructor together with data at the corresponding instance of the interface. Its elimination rule opens the package under a fresh constructor name, but forbids that name from occurring in the result type.
An existential package seals a constructor witness together with a term at the corresponding instance of an interface. Extend the terms of definition 7.6 by 𝑒::=⋯∣𝗉𝖺𝖼𝗄[𝐶,𝑒]𝖺𝗌∃𝑢::𝜅.𝐴∣𝗎𝗇𝗉𝖺𝖼𝗄[𝑢,𝑥]=𝑒1𝗂𝗇𝑒2. In a package annotation, 𝑢 is bound in 𝐴. In an unpacking, 𝑢 and 𝑥 are bound in 𝑒2, but neither is bound in 𝑒1. Terms are still identified up to consistent renaming of bound variables.
The typing rules are
Δ⊢𝐶::𝜅Δ,𝑢::𝜅⊢𝐴::𝖳𝗒Δ;Γ⊢𝑒:𝐴[𝐶/𝑢]
Δ;Γ⊢𝗉𝖺𝖼𝗄[𝐶,𝑒]𝖺𝗌∃𝑢::𝜅.𝐴:∃𝑢::𝜅.𝐴
T-Pack
Δ;Γ⊢𝑒1:∃𝑢::𝜅.𝐴Δ,𝑢::𝜅;Γ,𝑥:𝐴⊢𝑒2:𝐵Δ⊢𝐵::𝖳𝗒
Δ;Γ⊢𝗎𝗇𝗉𝖺𝖼𝗄[𝑢,𝑥]=𝑒1𝗂𝗇𝑒2:𝐵
T-Unpack
The bound variables are chosen fresh for the surrounding contexts. In particular, the last premise of T-Unpack forms 𝐵 in Δ, not in Δ,𝑢::𝜅. This is the no-escape premise: the result may depend on what the client computes with 𝑥, but its type cannot reveal the hidden constructor 𝑢.
Under Curry–Howard, T-Pack is existential introduction: the witness 𝐶 and payload at 𝐴[𝐶/𝑢] correspond to the witness term and proof in ∃-introduction. Rule T-Unpack is existential elimination. Its premise Δ⊢𝐵::𝖳𝗒 is the no-escape condition corresponding to the eigenvariable condition of the first-order ∃-elimination rule in chapter 3.
The core has constructors 𝟢 and 𝗌𝗎𝖼(𝑒) for ℕ, but no natural-number eliminator or recursor. Thus a client can return an observed number, apply 𝗌𝗎𝖼 to it, or pass it to another interface operation. No typing rule derives a branch or recursive call by inspecting that number. Representation independence quantifies over exactly these well-typed clients.
The no-escape premise is required by preservation, not merely by interface etiquette. If the body were allowed to return type 𝑢, then opening 𝗉𝖺𝖼𝗄[ℕ,𝟢]𝖺𝗌∃𝑢::𝖳𝗒.𝑢 with body 𝑥 would assign the whole unpacking the locally scoped type 𝑢. The computation step produces 𝟢:ℕ, but the alleged result type 𝑢 is free after the binder disappears. The reduct could not even be stated at the source judgment’s type. Forming 𝐵 in the outer Δ prevents exactly this escape.
Rule T-Pack permits a witness of any kind, not only 𝖳𝗒. Recall the operators 𝖬𝖺𝗉 and 𝖯 and the term 𝖽𝗆𝖺𝗉 from example 7.7. Define 𝖬𝖺𝗉𝗉𝖾𝗋:=∃𝑐::𝖳𝗒→𝖳𝗒.𝖬𝖺𝗉𝑐. The derivations already constructed give ⋅⊢𝖯::𝖳𝗒→𝖳𝗒,⋅;⋅⊢𝖽𝗆𝖺𝗉:𝖬𝖺𝗉𝖯. Therefore one use of T-Pack derives the genuinely higher-kinded package ⋅;⋅⊢𝗉𝖺𝖼𝗄[𝖯,𝖽𝗆𝖺𝗉]𝖺𝗌𝖬𝖺𝗉𝗉𝖾𝗋:𝖬𝖺𝗉𝗉𝖾𝗋. The witness is the unary constructor 𝖯, not a term and not a type of kind 𝖳𝗒.
★☆☆ Derive the displayed 𝖬𝖺𝗉𝗉𝖾𝗋 package with T-Pack, including the kinding premise for its existential body. Then replace the witness 𝖯 by ℕ and identify the first premise that fails. State the kind inferred for ℕ, and explain why it cannot serve as the witness for this unary-constructor package.
Define 𝖢𝗈𝗎𝗇𝗍𝖾𝗋:=∃𝑋::𝖳𝗒.𝑋×((𝑋→𝑋)×(𝑋→ℕ)). For a fixed representation 𝑋, a payload consists, in order, of an initial state, a step operation, and a read operation. The association of the products is part of the definition.
Here are two implementations. The first stores only the visible count: 𝑖𝑁:=𝟢,𝑠𝑁:=𝜆𝑛:ℕ.𝗌𝗎𝖼(𝑛),𝑟𝑁:=𝜆𝑛:ℕ.𝑛,𝑞𝑁:=(𝑖𝑁,(𝑠𝑁,𝑟𝑁)), and 𝐶𝑁:=𝗉𝖺𝖼𝗄[ℕ,𝑞𝑁]𝖺𝗌𝖢𝗈𝗎𝗇𝗍𝖾𝗋. The second stores a count together with a shadow count that advances in lockstep: 𝑃:=ℕ×ℕ,𝑖𝑃:=(𝟢,𝟢),𝑠𝑃:=𝜆𝑝:𝑃.(𝗌𝗎𝖼(𝗉𝗋1𝑝),𝗌𝗎𝖼(𝗉𝗋2𝑝)),𝑟𝑃:=𝜆𝑝:𝑃.𝗉𝗋1𝑝,𝑞𝑃:=(𝑖𝑃,(𝑠𝑃,𝑟𝑃)),𝐶𝑃:=𝗉𝖺𝖼𝗄[𝑃,𝑞𝑃]𝖺𝗌𝖢𝗈𝗎𝗇𝗍𝖾𝗋. Every term abbreviation on the right is a term of the core calculus; 𝑃 is a constructor of kind 𝖳𝗒. This plain 𝑃 names the pair-state type; it is distinct from the earlier operator 𝖯, which maps a type to its diagonal product. For the first payload, the rules for naturals, arrows, and products give ⋅;⋅⊢𝑞𝑁:ℕ×((ℕ→ℕ)×(ℕ→ℕ)). This is exactly the existential body with ℕ substituted for 𝑋. Hence T-Pack gives ⋅;⋅⊢𝐶𝑁:𝖢𝗈𝗎𝗇𝗍𝖾𝗋. For the pair-state payload, ⋅;⋅⊢𝑞𝑃:𝑃×((𝑃→𝑃)×(𝑃→ℕ)),⋅;⋅⊢𝐶𝑃:𝖢𝗈𝗎𝗇𝗍𝖾𝗋.
An unpacking client may use all three operations without knowing the state type. For a payload variable 𝑧, write 𝑖𝑧:=𝗉𝗋1𝑧,𝑠𝑧:=𝗉𝗋1(𝗉𝗋2𝑧),𝑟𝑧:=𝗉𝗋2(𝗉𝗋2𝑧). These are abbreviations, not new term forms. Define 𝗍𝗂𝖼𝗄2:=𝜆𝑐:𝖢𝗈𝗎𝗇𝗍𝖾𝗋.𝗎𝗇𝗉𝖺𝖼𝗄[𝑋,𝑧]=𝑐𝗂𝗇𝑟𝑧(𝑠𝑧(𝑠𝑧𝑖𝑧)). The nested expression is easier to check by naming its projections. Under 𝑋::𝖳𝗒;𝑧:𝑋×((𝑋→𝑋)×(𝑋→ℕ)) the projection and application rules derive, in order, 𝑖𝑧:𝑋,𝑠𝑧:𝑋→𝑋,𝑟𝑧:𝑋→ℕ,𝑠𝑧𝑖𝑧:𝑋,𝑠𝑧(𝑠𝑧𝑖𝑧):𝑋,𝑟𝑧(𝑠𝑧(𝑠𝑧𝑖𝑧)):ℕ. The final type ℕ is formed before 𝑋 is introduced. Thus T-Unpack types the unpacking at ℕ, and T-Lam gives ⋅;⋅⊢𝗍𝗂𝖼𝗄2:𝖢𝗈𝗎𝗇𝗍𝖾𝗋→ℕ.
Two tempting clients fail for two different, precise reasons. In the body of the unpacking, 𝗌𝗎𝖼(𝗉𝗋1𝑧) is ill typed: the projection has type 𝑋, whereas T-Suc requires ℕ. The variable 𝑋 does not convert to ℕ, by distinctness of constructor heads. On the other hand, 𝜆𝑐:𝖢𝗈𝗎𝗇𝗍𝖾𝗋.𝗎𝗇𝗉𝖺𝖼𝗄[𝑋,𝑧]=𝑐𝗂𝗇𝗉𝗋1𝑧 has a body of type 𝑋, but cannot use T-Unpack: its proposed result type is not formed in the outer, empty kind context. The first error tries to use a representation-specific operation; the second tries to return the representation itself.
★★☆ Define a term 𝗋𝖾𝗌𝖾𝖺𝗅:𝖢𝗈𝗎𝗇𝗍𝖾𝗋→𝖢𝗈𝗎𝗇𝗍𝖾𝗋 that unpacks a counter and immediately packs the same hidden witness and payload again. Give its T-Unpack derivation. Explain why the hidden 𝑋 does not escape even though 𝑋 occurs in the inner T-Pack premise.
The computation rule for unpacking will perform a constructor substitution and then a term substitution. We therefore record their action on the two new forms before defining evaluation. After renaming binders to satisfy the displayed freshness conditions, (𝗉𝖺𝖼𝗄[𝐷,𝑒]𝖺𝗌∃𝑣::𝜅′.𝐴)[𝐶/𝑢]=𝗉𝖺𝖼𝗄[𝐷[𝐶/𝑢],𝑒[𝐶/𝑢]]𝖺𝗌∃𝑣::𝜅′.𝐴[𝐶/𝑢],(𝗎𝗇𝗉𝖺𝖼𝗄[𝑣,𝑥]=𝑒1𝗂𝗇𝑒2)[𝐶/𝑢]=𝗎𝗇𝗉𝖺𝖼𝗄[𝑣,𝑥]=𝑒1[𝐶/𝑢]𝗂𝗇𝑒2[𝐶/𝑢], where 𝑣≠𝑢 and 𝑣∉fv(𝐶). Term substitution changes no constructor annotation and satisfies (𝗉𝖺𝖼𝗄[𝐶,𝑒]𝖺𝗌∃𝑢::𝜅.𝐴)[𝑑/𝑦]=𝗉𝖺𝖼𝗄[𝐶,𝑒[𝑑/𝑦]]𝖺𝗌∃𝑢::𝜅.𝐴,(𝗎𝗇𝗉𝖺𝖼𝗄[𝑢,𝑥]=𝑒1𝗂𝗇𝑒2)[𝑑/𝑦]=𝗎𝗇𝗉𝖺𝖼𝗄[𝑢,𝑥]=𝑒1[𝑑/𝑦]𝗂𝗇𝑒2[𝑑/𝑦], where 𝑥≠𝑦, 𝑥∉fv(𝑑), and the constructor binder 𝑢 has first been chosen fresh for every constructor occurring free in 𝑑. These are equations of capture-avoiding substitution, not reduction rules.
Proof of Lemma 7.33 — Structural lemmas for package terms
Proof. Term-context weakening, constructor-context weakening, and term substitution are inductions on the typing derivation; constructor substitution is an induction on the same derivation together with kinding substitution. The package-free cases are the four interfaces of lemma 11.34. For a T-Conv premise, weakening uses lemma 11.33. Constructor substitution instead uses lemma 7.27; kinding substitution alone would not transport its equality premise. We give both new package-rule cases, because each contains a constructor binder.
The constructor-substitution induction uses the split context Δ0,𝑢::𝜅,Δ1. It carries this split unchanged through every premise. This is essential beneath T-TLam, K-All, and the two package binders: a new declaration is appended to Δ1, rather than exchanged across 𝑢. If that declaration mentions 𝑢, exchanging it to the left of 𝑢 would make its annotation ill formed because 𝑢 would no longer occur in the prefix where the annotation is checked. For T-Pack, rename the package binder 𝑣 away from 𝑢 and 𝐶. Suppressing the common split, its premises have the form Δ0,𝑢::𝜅,Δ1⊢𝐷::𝜅′,Δ0,𝑢::𝜅,Δ1,𝑣::𝜅′⊢𝐴::𝖳𝗒,Δ0,𝑢::𝜅,Δ1;Γ⊢𝑒:𝐴[𝐷/𝑣]. Kinding substitution and the induction hypothesis give the corresponding premises for 𝐷[𝐶/𝑢], 𝐴[𝐶/𝑢], and 𝑒[𝐶/𝑢]. The substitution-composition law lemma 7.17(1) gives the payload-type equation (𝐴[𝐷/𝑣])[𝐶/𝑢]=𝐴[𝐶/𝑢][𝐷[𝐶/𝑢]/𝑣]. Rule T-Pack now reconstructs the substituted package.
For constructor substitution in T-Unpack, rename its hidden binder 𝑣 away from 𝑢 and 𝐶. Apply the induction hypothesis to the scrutinee. In the body premise use the split-context induction hypothesis with Δ1,𝑣::𝜅′ as the suffix. Freshness makes substitution pass through 𝑣, giving Δ0,Δ1,𝑣::𝜅′;Γ[𝐶/𝑢],𝑥:𝐴[𝐶/𝑢]⊢𝑒2[𝐶/𝑢]:𝐵[𝐶/𝑢]. Kinding substitution forms 𝐵[𝐶/𝑢] in Δ0,Δ1, so T-Unpack reconstructs the conclusion.
For term substitution, T-Pack applies the induction hypothesis only to the payload. In T-Unpack, rename its term binder 𝑥 away from 𝑦 and 𝑑. Apply the induction hypothesis to the scrutinee and to the body. For the latter, first apply constructor-context weakening to the derivation of 𝑑, then term-context weakening through the declaration 𝑥:𝐴; use the body induction hypothesis with that declaration in the trailing context. Reapply T-Unpack. Both weakening inductions repeat these two reconstructions without a replacement step. Thus all four inductions cover the new grammar. ◻
★★☆ Suppose Δ;Γ,𝑦:𝐷⊢𝗎𝗇𝗉𝖺𝖼𝗄[𝑢,𝑥]=𝑝𝗂𝗇𝑒:𝐵andΔ;Γ⊢𝑑:𝐷, with 𝑥≠𝑦 and 𝑥∉fv(𝑑). Invert the unpacking derivation, write the two premises obtained after substituting 𝑑 for 𝑦, and rebuild the final T-Unpack rule. State where weakening 𝑑 under 𝑢::𝜅 is used.
A package hides a constructor; it should not hide an unfinished computation. Call-by-value evaluation therefore evaluates the payload before regarding the package as a value. It also evaluates the scrutinee of an unpacking before opening it.
Values and evaluation contexts for the full term grammar are 𝑣::=𝜆𝑥:𝐴.𝑒∣Λ𝑢::𝜅.𝑒∣(𝑣1,𝑣2)∣𝟢∣𝗌𝗎𝖼(𝑣)∣𝗉𝖺𝖼𝗄[𝐶,𝑣]𝖺𝗌∃𝑢::𝜅.𝐴,𝐸::=[]∣𝐸𝑒∣𝑣𝐸∣𝐸[𝐶]∣(𝐸,𝑒)∣(𝑣,𝐸)∣𝗉𝗋𝑖𝐸∣𝗌𝗎𝖼(𝐸)∣𝗉𝖺𝖼𝗄[𝐶,𝐸]𝖺𝗌∃𝑢::𝜅.𝐴∣𝗎𝗇𝗉𝖺𝖼𝗄[𝑢,𝑥]=𝐸𝗂𝗇𝑒. The root contractions are (𝜆𝑥:𝐴.𝑒)𝑣⟶𝑒[𝑣/𝑥],(Λ𝑢::𝜅.𝑒)[𝐶]⟶𝑒[𝐶/𝑢],𝗉𝗋𝑖(𝑣1,𝑣2)⟶𝑣𝑖,𝗎𝗇𝗉𝖺𝖼𝗄[𝑢,𝑥]=(𝗉𝖺𝖼𝗄[𝐶,𝑣]𝖺𝗌∃𝑎::𝜅.𝐴0)𝗂𝗇𝑒⟶𝑒[𝐶/𝑢][𝑣/𝑥]. If 𝑒⟶𝑒′, then 𝐸⟨𝑒⟩⟶𝐸⟨𝑒′⟩. There is no reduction beneath a term abstraction, a type abstraction, or the body of an unopened unpacking. Write ⟶∗ for the reflexive–transitive closure.
Proof of Lemma 12.5 — Determinism of package evaluation
Proof. First, no value takes a call-by-value step. This is an induction on the value grammar: no root rule has a value as its source, and the evaluation contexts do not descend beneath a value former. Induct on the term. The left-to-right evaluation-context grammar selects at most one immediate subterm: it advances past a position only after that position is a value. Once all required subterms are values, their outer constructor selects at most one of the four root rules. Those roots have disjoint outer forms, and each has one right-hand side. The induction hypothesis gives a unique step in the selected proper subterm. ◻
Call-by-value reduction answers how a program is run. Representation independence needs a larger equality: two terms are beta-convertible even when the decisive contraction lies beneath a binder or in a branch that call-by-value evaluation does not enter.
Compatible term beta reduction ⟶𝛽, called an 𝑒-beta step when the syntactic level must be explicit, is the least relation containing the four roots (𝜆𝑥:𝐴.𝑒)𝑑⟶𝛽𝑒[𝑑/𝑥],(Λ𝑢::𝜅.𝑒)[𝐶]⟶𝛽𝑒[𝐶/𝑢],𝗉𝗋𝑖(𝑒1,𝑒2)⟶𝛽𝑒𝑖,𝗎𝗇𝗉𝖺𝖼𝗄[𝑢,𝑥]=(𝗉𝖺𝖼𝗄[𝐶,𝑑]𝖺𝗌∃𝑎::𝜅.𝐴0)𝗂𝗇𝑒⟶𝛽𝑒[𝐶/𝑢][𝑑/𝑥], and compatible with every term constructor. Thus a step may occur beneath 𝜆 or Λ, in either child of an application or pair, inside a successor or package, and in either the scrutinee or body of an unpacking. None of the four roots requires its argument or payload to be a value.
Write =𝛽 for the reflexive, symmetric, transitive closure and ⟶∗𝛽 for the reflexive–transitive closure. Every call-by-value step of definition 7.34 is a compatible beta step, but not conversely.
The operational relations have the following distinct domains and closures: 𝑒⟶𝑒′call-by-value;noreductionunderbinders𝑒⟶𝛽𝑒′(𝑒-𝛽)compatibletermbetaateverytermformer𝑒⟶∗𝛽𝑒′(𝑒-𝛽)∗reflexive--transitivetermbeta𝑒=𝛽𝑒′symmetric,transitiveterm-betaconversion𝐴⟶𝛽𝐵(𝐴-𝛽)compatibleconstructorbeta𝐴≡𝐵formedconstructorconversion The role macros ⟶𝛽 and ⟶𝛽 deliberately share the same printed beta arrow. Their operand sorts and the 𝑒-beta and 𝐴-beta tags distinguish directed reductions at the term and constructor levels. The relation =𝛽 is reserved for term conversion, while ≡ compares formed constructors.
Proof of Proposition 7.36 — Subject reduction for compatible term beta
Proof. Peel the final chain of T-Conv uses from the typing of the whole expression. Induct on the compatible step at the remaining syntax-directed result type, then restore the conversion chain. The root cases use inversion through any conversions on their operator premises.
For term beta, suppose the application rule expects an operator of type 𝐷→𝐴. Strip conversions from the typing of 𝜆𝑥:𝐶.𝑒0. Its introduction rule gives Δ;Γ,𝑥:𝐶⊢𝑒0:𝐵, while the stripped conversion gives 𝐶→𝐵≡𝐷→𝐴. Arrow-head injectivity yields 𝐶≡𝐷 and 𝐵≡𝐴. Convert the operand from 𝐷 to 𝐶, apply term substitution, and finally convert the result from 𝐵 to 𝐴.
For type beta, suppose type application expects an operator of type ∀𝑢::𝜅.𝐴. Stripping conversions from the typing of Λ𝑣::𝜅′.𝑒0, followed by alpha-renaming, gives Δ,𝑢::𝜅;Γ⊢𝑒0:𝐵 and ∀𝑢::𝜅.𝐵≡∀𝑢::𝜅.𝐴. Universal-head injectivity gives 𝐵≡𝐴 in the extended constructor context. Constructor substitution types 𝑒0[𝐶/𝑢] at 𝐵[𝐶/𝑢]; equality substitution and T-Conv change that result to 𝐴[𝐶/𝑢].
For projection beta, suppose the projection rule expects 𝐷1×𝐷2. Strip conversions from the typing of the displayed pair. Product-head injectivity gives 𝐶𝑖≡𝐷𝑖 for 𝑖∈{1,2}. The selected pair premise has type 𝐶𝑖, and one use of T-Conv gives the required 𝐷𝑖.
For the unpacking root, invert T-Unpack. Write its scrutinee type as ∃𝑢::𝜅.𝐴1 and its body premise as Δ,𝑢::𝜅;Γ,𝑥:𝐴1⊢𝑒0:𝐵,Δ⊢𝐵::𝖳𝗒. Peeling final conversions from the package typing and using existential-head injectivity gives, after alpha-renaming, Δ⊢𝐶::𝜅,Δ;Γ⊢𝑑:𝐴0[𝐶/𝑢],Δ,𝑢::𝜅⊢𝐴0≡𝐴1::𝖳𝗒. Equality substitution and T-Conv type 𝑑 at 𝐴1[𝐶/𝑢]. Constructor substitution types 𝑒0[𝐶/𝑢] at 𝐵 in Γ,𝑥:𝐴1[𝐶/𝑢]; because 𝑢 is absent from the well-formed outer Γ and 𝐵, their substitutions by 𝐶 are literally Γ and 𝐵. Term substitution now types 𝑒0[𝐶/𝑢][𝑑/𝑥] at 𝐵, as required.
For a step in a proper subterm, apply the induction hypothesis to its typing premise and rebuild the same typing rule. Beneath 𝜆, Λ, or the body of an unpacking, the induction hypothesis is applied in the corresponding extended context. These cases cover every term constructor. ◻
The quotient by =𝛽 is taken separately at each fixed type. The proposition ensures that every forward reduction used in a conversion calculation remains at that type.
The existential type displayed in the first premise of T-Unpack need not use the same bound-variable name or the same spelling of its body as the type synthesized for the scrutinee. Typing shows that the two existential types are convertible; the preservation proof above used injectivity of the existential head to reconcile their bodies.
Let 𝑣 be a value and suppose Δ;⋅⊢𝑣:∃𝑢::𝜅.𝐴. Then, after renaming a bound constructor, there are 𝐶, 𝑤, and 𝐴0 such that 𝑣=𝗉𝖺𝖼𝗄[𝐶,𝑤]𝖺𝗌∃𝑢::𝜅.𝐴0,𝑤 is a value, Δ⊢𝐶::𝜅,Δ;⋅⊢𝑤:𝐴0[𝐶/𝑢],Δ,𝑢::𝜅⊢𝐴0≡𝐴::𝖳𝗒. For each other type whose outer head is a constructor former, stripping final uses of T-Conv selects its unique value-introduction rule: an arrow selects T-Lam, a universal selects T-TLam, a product selects T-Pair, and ℕ selects T-Zero or T-Suc. The selected rule supplies the corresponding typing premises, while head injectivity converts each component of its result type to the component demanded by the assumed type. A neutral constructor head is excluded in every later use of this clause: the typing rule being inverted demands one of the displayed former heads.
Proof. Peel off all final uses of T-Conv, composing their equalities. The last remaining rule is determined by the value form. Its syntax-directed result type has outer head →, ∀, ×, ℕ, or ∃, respectively. Distinct heads do not convert (corollary 7.26), so only the form with the requested head can occur.
In the existential case the remaining rule is T-Pack, whose premises give Δ⊢𝐶::𝜅 and the required payload typing. Its result type ∃𝑎::𝜅′.𝐴0 converts to ∃𝑢::𝜅.𝐴. Existential-head injectivity gives 𝜅′=𝜅 and, after opening both binders with one fresh 𝑢, 𝐴0≡𝐴. Alpha-renaming the annotation produces the required package. For the four other heads, replace T-Pack respectively by T-Lam, T-TLam, T-Pair, and T-Zero/T-Suc; head disjointness rules out every other value form, and head injectivity gives the component equalities described in the statement. ◻
Proof. Every call-by-value step is a compatible term-beta step by definition 7.35. Apply proposition 7.36. Notice that this argument also covers a reduction in an evaluation context: compatible closure already contains every call-by-value context. ◻
Proof. Induct on the typing derivation. A variable case is impossible, and a final T-Conv uses the induction hypothesis of its premise. Term and type abstractions are values. For an application, first apply the induction hypothesis to the operator and then to the operand. If both are values, the arrow clause of canonical forms gives an operator 𝜆𝑥:𝐵.𝑠, so term beta applies. For type application, a universal-typed value has form Λ𝑢::𝜅.𝑠, so type beta applies. For a pair, evaluate its components from left to right; it is a value when both are values. For a projection, evaluate its argument; a value of product type is a pair, so projection beta applies. The zero term is a value, and a successor evaluates its argument or is a value.
For a package, apply the induction hypothesis to its payload. A payload step occurs in the package context; if the payload is a value, the package is a value by the value grammar. For 𝗎𝗇𝗉𝖺𝖼𝗄[𝑢,𝑥]=𝑒1𝗂𝗇𝑒2, apply the induction hypothesis to 𝑒1. A step occurs in the unpacking context. If 𝑒1 is a value, lemma 7.37 proves that it has the form 𝗉𝖺𝖼𝗄[𝐶,𝑑]𝖺𝗌∃𝑢::𝜅.𝐴 with value payload 𝑑, so the unpacking contraction applies. These cases exhaust the typing rules. ◻
If Δ;⋅⊢𝑒:𝐴 and 𝑒⟶∗𝑒′, then 𝑒′ is a value or it takes another step. In particular, a closed well-typed package client—closed in term variables, though Δ may contain constructor variables—cannot become stuck because it chose an operation incompatible with the hidden witness.
Proof. Repeated preservation types 𝑒′ at 𝐴; progress gives the alternative. ◻
An open unpacking can be blocked, as an eliminator should be. In the context 𝑦:𝖢𝗈𝗎𝗇𝗍𝖾𝗋 the term 𝗎𝗇𝗉𝖺𝖼𝗄[𝑋,𝑧]=𝑦𝗂𝗇(𝗉𝗋2(𝗉𝗋2𝑧))(𝗉𝗋1𝑧) is well typed at ℕ but takes no step: its scrutinee is the variable 𝑦, not a package value. This does not contradict progress, whose term context is empty.
Running the two counters
The client reduction realizes its typing derivation as follows. After the outer term beta step, opening 𝐶𝑁 substitutes ℕ for 𝑋 and 𝑞𝑁 for 𝑧. The three projection abbreviations satisfy 𝑖𝑞𝑁⟶𝑖𝑁,𝑠𝑞𝑁⟶∗𝑠𝑁,𝑟𝑞𝑁⟶∗𝑟𝑁. For example, 𝑠𝑞𝑁=𝗉𝗋1(𝗉𝗋2𝑞𝑁) first reduces its inner projection to (𝑠𝑁,𝑟𝑁) and then reduces to 𝑠𝑁. The client calculation is therefore 𝗍𝗂𝖼𝗄2𝐶𝑁𝛽⟶𝗎𝗇𝗉𝖺𝖼𝗄[𝑋,𝑧]=𝐶𝑁𝗂𝗇⋯𝑢𝑛𝑝𝑎𝑐𝑘−𝛽⟶𝑟𝑞𝑁(𝑠𝑞𝑁(𝑠𝑞𝑁𝑖𝑞𝑁))𝑝𝑟𝑜𝑗𝑒𝑐𝑡𝑖𝑜𝑛−𝛽⟶∗𝑟𝑁(𝑠𝑁(𝑠𝑁𝑖𝑁))𝛽⟶𝑟𝑁(𝑠𝑁(𝗌𝗎𝖼(𝟢)))𝛽⟶𝑟𝑁(𝗌𝗎𝖼(𝗌𝗎𝖼(𝟢)))𝛽⟶𝗌𝗎𝖼(𝗌𝗎𝖼(𝟢)).
For the pair implementation, put 𝑝0:=(𝟢,𝟢),𝑝1:=(𝗌𝗎𝖼(𝟢),𝗌𝗎𝖼(𝟢)),𝑝2:=(𝗌𝗎𝖼(𝗌𝗎𝖼(𝟢)),𝗌𝗎𝖼(𝗌𝗎𝖼(𝟢))). One step operation performs the following complete calculation: 𝑠𝑃𝑝0𝛽⟶(𝗌𝗎𝖼(𝗉𝗋1𝑝0),𝗌𝗎𝖼(𝗉𝗋2𝑝0))𝑓𝑖𝑟𝑠𝑡𝑝𝑟𝑜𝑗𝑒𝑐𝑡𝑖𝑜𝑛⟶(𝗌𝗎𝖼(𝟢),𝗌𝗎𝖼(𝗉𝗋2𝑝0))𝑠𝑒𝑐𝑜𝑛𝑑𝑝𝑟𝑜𝑗𝑒𝑐𝑡𝑖𝑜𝑛⟶(𝗌𝗎𝖼(𝟢),𝗌𝗎𝖼(𝟢))=𝑝1. The same three contractions with 𝑝1 in place of 𝑝0 yield 𝑠𝑃𝑝1⟶∗𝑝2. Consequently, 𝗍𝗂𝖼𝗄2𝐶𝑃𝛽⟶𝗎𝗇𝗉𝖺𝖼𝗄[𝑋,𝑧]=𝐶𝑃𝗂𝗇⋯𝑢𝑛𝑝𝑎𝑐𝑘−𝛽⟶𝑟𝑞𝑃(𝑠𝑞𝑃(𝑠𝑞𝑃𝑖𝑞𝑃))𝑝𝑟𝑜𝑗𝑒𝑐𝑡𝑖𝑜𝑛−𝛽⟶∗𝑟𝑃(𝑠𝑃(𝑠𝑃𝑝0))𝑠𝑃𝑝0𝑎𝑛𝑑𝑠𝑃𝑝1⟶∗𝑟𝑃𝑝2𝛽⟶𝗉𝗋1𝑝2𝑝𝑟𝑜𝑗𝑒𝑐𝑡𝑖𝑜𝑛−𝛽⟶𝗌𝗎𝖼(𝗌𝗎𝖼(𝟢)). Thus this particular client obtains the same observation from the two packages, although their state values have different types.
This agreement is a calculation, not a representation-independence theorem. Existential typing enforces opacity; by itself it does not assert that any two packages of the same existential type behave alike. To see the difference, replace 𝑠𝑁 by 𝑠+2𝑁:=𝜆𝑛:ℕ.𝗌𝗎𝖼(𝗌𝗎𝖼(𝑛)) and seal the resulting payload at 𝖢𝗈𝗎𝗇𝗍𝖾𝗋. It has the same existential type as 𝐶𝑁, but the calculation above now ends at 𝗌𝗎𝖼(𝗌𝗎𝖼(𝗌𝗎𝖼(𝗌𝗎𝖼(𝟢)))). A relation between witnesses and operations is the additional premise needed to prove representation independence.
★★☆ Define the fast counter 𝐶+2𝑁:𝖢𝗈𝗎𝗇𝗍𝖾𝗋 using 𝑠+2𝑁. Display every call-by-value contraction in 𝗍𝗂𝖼𝗄2𝐶+2𝑁 and prove that its result is the numeral four. Conclude that this one well-typed client distinguishes 𝐶𝑁 from 𝐶+2𝑁: deterministic call-by-value evaluation returns the distinct numeral values two and four.
The relation environment of chapter 6 assigns to a type variable 𝑋 two closed types and a relation between their closed terms. That assignment is insufficient for 𝑐::𝖳𝗒→𝖳𝗒. The expression 𝑐𝐴 is a type, so its interpretation must be a relation; but the relation may depend on the relation chosen for 𝐴. Thus 𝑐 must carry an action: it sends related arguments to a relation between the two results. This is the one new idea. The clauses for constructor abstraction and application will merely form and apply such actions.
Constructor-beta endpoints require the following indexing convention.
For a closed type 𝐴, let 𝖳𝗆(𝐴):={𝑒∣⋅;⋅⊢𝑒:𝐴}/=𝛽, where =𝛽 is exactly the compatible term-beta conversion of definition 7.35, not the directed call-by-value evaluation relation of definition 7.34. It closes all four root contractions under every term context. If 𝐴 and 𝐴′ satisfy the corresponding closed constructor-conversion judgment, the two sets 𝖳𝗆(𝐴) and 𝖳𝗆(𝐴′) have the same terms and beta-classes; T-Conv changes only their assigned type. The index 𝐴 of 𝖳𝗆(𝐴) denotes its constructor-conversion class. The same convention applies to closed constructors of every kind. It makes (𝜆𝑢::𝜅.𝐴)𝐶 and 𝐴[𝐶/𝑢] literally the same endpoint for the relational definitions below. Constructor conversion is always written as a judgment with ≡; =𝛽 below therefore always relates terms.
For relations 𝑅:𝐴0↔𝐴1 and 𝑆:𝐵0↔𝐵1, recall arrow lifting and define product lifting by [𝑓](𝑅⇒𝑆)[𝑔]⟺[𝑎]𝑅[𝑏]⟹[𝑓𝑎]𝑆[𝑔𝑏],[𝑝](𝑅×𝑆)[𝑞]⟺[𝗉𝗋1𝑝]𝑅[𝗉𝗋1𝑞]and[𝗉𝗋2𝑝]𝑆[𝗉𝗋2𝑞]. In the first line the implication is required for every [𝑎]𝑅[𝑏]. Both definitions are independent of representatives because beta conversion is compatible with application and projection. Put 𝖤𝗊ℕ:={([𝑚],[𝑚])∣[𝑚]∈𝖳𝗆(ℕ)}.
For closed 𝐴0,𝐴1::𝜅, define the collection Rel𝜅(𝐴0,𝐴1) by induction on 𝜅: Rel𝖳𝗒(𝐴0,𝐴1):=P(𝖳𝗆(𝐴0)×𝖳𝗆(𝐴1)). An element Φ∈Rel𝜅→𝜅′(𝐹0,𝐹1) is an operation which, for every closed 𝐶0,𝐶1::𝜅 and every 𝑅∈Rel𝜅(𝐶0,𝐶1), returns Φ(𝐶0,𝐶1,𝑅)∈Rel𝜅′(𝐹0𝐶0,𝐹1𝐶1). A relational object of kind 𝜅 is a triple 𝑄=(𝑄0,𝑄1,𝑄𝑅) with 𝑄𝑅∈Rel𝜅(𝑄0,𝑄1).
Proof of Lemma 12.14 — Constructor-convertible relation endpoints
Proof. Induct on 𝜅. At 𝖳𝗒, 𝖳𝗆(𝐴𝑖)=𝖳𝗆(𝐴′𝑖) by T-Conv, so the two power sets are literally equal. At 𝜅0→𝜅1, the same operations occur on both sides: for each pair 𝐶0,𝐶1 and input relation 𝑅, constructor congruence proves 𝐴𝑖𝐶𝑖≡𝐴′𝑖𝐶𝑖, and the induction hypothesis at 𝜅1 gives equality of the required output collections. ◻
The following notation distinguishes beta-classes, type application, and substitution: [𝑒]outerbeta-equivalenceclass𝑒[𝐶]object-languagetypeapplication𝑒[𝐶/𝑢]singleconstructorsubstitution𝑒[𝜌𝑖][𝛾𝑖]endpointconstructorandtermsubstitutions𝗉𝖺𝖼𝗄[𝐶,𝑒],𝗎𝗇𝗉𝖺𝖼𝗄[𝑢,𝑥]packagesyntax Thus the outer brackets in [𝑒[𝜌𝑖][𝛾𝑖]] form one beta-class after the two substitutions.
These collections are meta-level sets for the same reason as in definition 6.1: closed constructors and terms are countable syntax, the base clause uses a power set, and the arrow clause is a set of operations between already constructed sets at proper subkinds.
The naive arrow-kind attempt assigns only a bare set of pairs of closed constructor beta-classes at endpoints 𝐹0 and 𝐹1, without an operation describing how that set acts on a related argument. At an application it then asks for [[𝑐𝐴]]𝜌fromonly𝜌(𝑐)=(𝐹0,𝐹1,𝑅), but 𝑅 contains no relation between 𝐹0𝐶0 and 𝐹1𝐶1—in particular none at the concrete instance 𝖬𝖺𝗉𝖯. The repair is an action Φ that maps each related input triple to a well-indexed output relation. No functor law is imposed: the abstraction theorem needs only that every related input is sent to a well-indexed output relation. In particular, we do not require Φ to preserve identity relations or composition of relations; “functor” here refers to that categorical preservation condition. Parameterized ML modules use the same word for a different construction, and neither use concerns modules over a ring.
Let Δ=𝑢1::𝜅1,…,𝑢𝑛::𝜅𝑛. A relation environment 𝜌 assigns to each 𝑢𝑖 a relational object 𝜌(𝑢𝑖)=(𝐶𝑖0,𝐶𝑖1,𝑅𝑖)ofkind𝜅𝑖. Its endpoint substitutions are 𝜌0(𝑢𝑖)=𝐶𝑖0 and 𝜌1(𝑢𝑖)=𝐶𝑖1. Following definition 6.4, we write 𝜌:𝜌0↔𝜌1𝗈𝗏𝖾𝗋Δ.
As in chapter 6, 𝜖 denotes the unique relation environment over the empty constructor context; it is not an empty relation.
The relational interpretation of a constructor 𝐴 will be written [[𝐴]]𝜌. If Δ⊢𝐴::𝜅, it must belong to Rel𝜅(𝐴[𝜌0],𝐴[𝜌1]). The following definition gives all its clauses. In the binder clauses, the bound variable is first renamed away from the finite ranges of the endpoint substitutions.
For variables and the primitive type, [[𝑢]]𝜌:=𝜌(𝑢)𝑅,[[ℕ]]𝜌:=𝖤𝗊ℕ. The type-former clauses are [[𝐴→𝐵]]𝜌:=[[𝐴]]𝜌⇒[[𝐵]]𝜌,[[𝐴×𝐵]]𝜌:=[[𝐴]]𝜌×[[𝐵]]𝜌. Constructor abstraction creates an action, and constructor application uses one: [[𝜆𝑢::𝜅.𝐴]]𝜌(𝐶0,𝐶1,𝑅):=[[𝐴]]𝜌[𝑢↦(𝐶0,𝐶1,𝑅)],[[𝐴𝐵]]𝜌:=[[𝐴]]𝜌(𝐵[𝜌0],𝐵[𝜌1],[[𝐵]]𝜌). For beta classes [𝑝]∈𝖳𝗆((∀𝑢::𝜅.𝐴)[𝜌0]) and [𝑞]∈𝖳𝗆((∀𝑢::𝜅.𝐴)[𝜌1]), define [𝑝][[∀𝑢::𝜅.𝐴]]𝜌[𝑞] to mean that, for every relational object 𝑄=(𝐶0,𝐶1,𝑅) of kind 𝜅, [𝑝[𝐶0]][[𝐴]]𝜌[𝑢↦𝑄][𝑞[𝐶1]]. First read the existential clause in its literal-annotation special case. Packages 𝗉𝖺𝖼𝗄[𝐶𝑖,𝑎𝑖]𝖺𝗌∃𝑢::𝜅.𝐴[𝜌𝑖] are related when some 𝑅 connects 𝐶0 and 𝐶1 and the payloads are related at [[𝐴]]𝜌[𝑢↦(𝐶0,𝐶1,𝑅)]. The longer clause below allows the written annotations to be any constructor-convertible presentations of those endpoint types; its two equality lines record exactly that extra flexibility. For beta classes [𝑝]∈𝖳𝗆((∃𝑢::𝜅.𝐴)[𝜌0]) and [𝑞]∈𝖳𝗆((∃𝑢::𝜅.𝐴)[𝜌1]), define [𝑝][[∃𝑢::𝜅.𝐴]]𝜌[𝑞] to mean that there are a relational object 𝑄=(𝐶0,𝐶1,𝑅) of kind 𝜅, closed payloads 𝑎0,𝑎1, and package bodies 𝐷0,𝐷1 whose only possible free constructors are their displayed binders, such that 𝑝=𝛽𝗉𝖺𝖼𝗄[𝐶0,𝑎0]𝖺𝗌∃𝑣0::𝜅.𝐷0,𝑞=𝛽𝗉𝖺𝖼𝗄[𝐶1,𝑎1]𝖺𝗌∃𝑣1::𝜅.𝐷1,⋅⊢∃𝑣0::𝜅.𝐷0≡∃𝑢::𝜅.𝐴[𝜌0]::𝖳𝗒,⋅⊢∃𝑣1::𝜅.𝐷1≡∃𝑢::𝜅.𝐴[𝜌1]::𝖳𝗒,[𝑎0][[𝐴]]𝜌[𝑢↦𝑄][𝑎1]. Thus a package annotation may be any constructor-convertible presentation of the corresponding endpoint type. Existential-head injectivity and T-Conv identify each payload with the endpoint expected by the last line. This flexibility is necessary because package annotations are part of term syntax, whereas compatible term beta does not rewrite constructors inside annotations.
The existential clause is asymmetric with the universal clause for a reason. A polymorphic term must work for every relational object. A package hides one pair of witnesses, so related packages need exhibit one relation between those witnesses. Requiring every relation would reject ordinary abstract data types; requiring no witness relation would leave the payloads unconnected.
Recall 𝖯=𝜆𝑢::𝖳𝗒.𝑢×𝑢. For every 𝑅∈Rel𝖳𝗒(𝐶0,𝐶1), [[𝖯]]𝜖(𝐶0,𝐶1,𝑅)𝑎𝑏𝑠𝑡𝑟𝑎𝑐𝑡𝑖𝑜𝑛=[[𝑢×𝑢]]𝑢↦(𝐶0,𝐶1,𝑅)𝑝𝑟𝑜𝑑𝑢𝑐𝑡=𝑅×𝑅. Thus the abstract action demanded by definition 7.41 performs the familiar operation: it relates pairs componentwise. Constructor application recovers the same calculation, [[𝖯ℕ]]𝜖=𝖤𝗊ℕ×𝖤𝗊ℕ.
★★☆ Let 𝑅∈Rel𝖳𝗒(𝐴0,𝐴1). Unfold the action, application, and product clauses in that order to prove [[𝖢𝗈𝗆𝗉𝖯𝖯]]𝜖(𝐴0,𝐴1,𝑅)=(𝑅×𝑅)×(𝑅×𝑅). State the two endpoint types of the relation on the right. Then let 𝖣:=𝜆𝑎::𝖳𝗒.𝑎→𝑎 and prove [[𝖣]]𝜖(𝐴0,𝐴1,𝑅)=𝑅⇒𝑅. Explain why this second action genuinely depends on the supplied relation 𝑅, rather than merely relating two fixed endpoint constructors.
Three lemmas are needed before the term induction. The first prevents silent index changes; the second is the constructor-level analogue of the type-substitution lemma from chapter 6; the third handles rule T-Conv.
Proof of Lemma 7.45 — Endpoints and irrelevant constructor variables
Proof. Prove both claims simultaneously by induction on the kinding derivation. The variable, ℕ, arrow, and product cases follow directly from their defining clauses. For 𝜆𝑢::𝜅0.𝐴0, take an arbitrary relational object 𝑄 of kind 𝜅0. The induction hypothesis under 𝜌[𝑢↦𝑄] indexes the body relation by 𝐴0[𝜌0,𝑢↦𝑄0]and𝐴0[𝜌1,𝑢↦𝑄1]. These are beta-convertible to the applications of the two endpoint abstractions to 𝑄0,𝑄1, so the action has the required arrow-kind index. Agreement away from the free variables of the abstraction remains agreement after extending both environments by the same 𝑄.
For 𝐴1𝐴2, the induction hypothesis for 𝐴1 gives an action and the one for 𝐴2 gives an admissible relational argument. Applying the former to the latter gives exactly the required endpoint applications.
For ∀𝑢::𝜅0.𝐴0, type application at 𝑄𝑖 has endpoint type 𝐴0[𝜌𝑖,𝑢↦𝑄𝑖]; the body induction hypothesis therefore types every relation required by the universal clause.
For ∃𝑢::𝜅0.𝐴0, suppose [𝑝] and [𝑞] satisfy the existential clause, witnessed by 𝑄=(𝐶0,𝐶1,𝑅), payloads 𝑎0,𝑎1, and annotations ∃𝑣𝑖::𝜅0.𝐷𝑖. The body induction hypothesis says that [𝑎0][[𝐴0]]𝜌[𝑢↦𝑄][𝑎1] is indexed by 𝐴0[𝜌0,𝑢↦𝐶0]and𝐴0[𝜌1,𝑢↦𝐶1]. Hence T-Pack, using the endpoint body 𝐴0[𝜌𝑖], types the two literal packages at ∃𝑢::𝜅0.𝐴0[𝜌𝑖]. The annotation equalities in the definition, existential-head injectivity from corollary 7.26, and T-Conv give the same endpoint typing for the displayed 𝐷𝑖 annotations. The domain restriction in the defining clause already places [𝑝] and [𝑞] in the two corresponding 𝖳𝗆 endpoints; the two term-beta equalities choose the displayed package representatives of those classes. Thus all five conditions of the defining clause contribute: two expose the packages, two align their annotations, and the last relates well-typed payloads.
In both binder cases, irrelevance follows by extending the two environments with the same arbitrary 𝑄 and applying the body hypothesis. These cases exhaust the constructor grammar. ◻
Suppose Δ0,𝑢::𝜅,Δ1⊢𝐴::𝜅′,Δ0⊢𝐵::𝜅, and let 𝜌 be a relation environment over Δ0,Δ1. Define the relational object 𝑄𝐵:=(𝐵[𝜌0],𝐵[𝜌1],[[𝐵]]𝜌). Then, under the constructor-beta identification of endpoints, [[𝐴[𝐵/𝑢]]]𝜌=[[𝐴]]𝜌[𝑢↦𝑄𝐵].
Proof of Lemma 7.46 — Relational constructor substitution
Proof. Induct on the kinding derivation of 𝐴. At the variable 𝑢, both sides are [[𝐵]]𝜌; another variable and ℕ are unchanged. For arrows and products, apply the induction hypothesis at both components and form the corresponding relational lifting.
For application 𝐴1𝐴2, the left side applies the interpreted action of 𝐴1[𝐵/𝑢] to the interpreted relational object of 𝐴2[𝐵/𝑢]. The two induction hypotheses replace these by the interpretation of 𝐴1 and the relational object of 𝐴2 under 𝜌[𝑢↦𝑄𝐵], which is the right-hand application clause.
For a binder, first rename its variable 𝑣 so that 𝑣≠𝑢 and 𝑣∉fv(𝐵). In the constructor-abstraction case, apply both sides to an arbitrary relational object 𝑄 for 𝑣. The body induction hypothesis applies under 𝜌[𝑣↦𝑄]. Irrelevance and 𝑣∉fv(𝐵) give equality of relational objects (𝐵[𝜌0,𝑣↦𝑄0],𝐵[𝜌1,𝑣↦𝑄1],[[𝐵]]𝜌[𝑣↦𝑄])=𝑄𝐵. The two environment extensions commute, so the resulting body relations are equal. This proves equality of the actions. For a universal, fix an arbitrary 𝑄; the body induction hypothesis equates the two relations applied to 𝑝[𝑄0] and 𝑞[𝑄1], so the universally quantified membership conditions coincide. For an existential, keep its witnessing 𝑄, payloads, and written annotations fixed; the body induction hypothesis equates the two payload conditions. Its endpoint calculation (𝐴0[𝐵/𝑢])[𝜌𝑖]=𝐴0[𝜌𝑖,𝑢↦𝐵[𝜌𝑖]](𝑖=0,1) is the simultaneous/single substitution-composition equation. It makes the left clause’s annotation condition ∃𝑣.𝐷𝑖≡∃𝑤.𝐴0[𝐵/𝑢][𝜌𝑖] identical to the right clause’s condition ∃𝑣.𝐷𝑖≡∃𝑤.𝐴0[𝜌𝑖,𝑢↦𝐵[𝜌𝑖]] after freshening 𝑣,𝑤. The payload condition is the body equality just proved. ◻
If Δ⊢𝐴≡𝐵::𝜅, then for every relation environment 𝜌 over Δ, [[𝐴]]𝜌=[[𝐵]]𝜌 after the canonical identification of their constructor-beta-convertible endpoints.
Proof of Lemma 7.47 — Invariance under constructor equality
Proof. At arrow kind, equality of actions is ordinary function extensionality in the fixed ZF metatheory. Write Φ(𝑄) for Φ(𝐶0,𝐶1,𝑅) when 𝑄=(𝐶0,𝐶1,𝑅). Then Φ=Ψ⟺Φ(𝑄)=Ψ(𝑄)foreveryrelationalobject𝑄. First prove invariance under one constructor reduction. Induct on the constructor reduction (an 𝐴-beta step). At the root redex, [[(𝜆𝑢::𝜅0.𝐴0)𝐶]]𝜌=[[𝐴0]]𝜌[𝑢↦(𝐶[𝜌0],𝐶[𝜌1],[[𝐶]]𝜌)]=[[𝐴0[𝐶/𝑢]]]𝜌 by lemma 7.46. A congruence step uses the induction hypothesis in the corresponding compositional clause of definition 7.43; at arrow kind apply the displayed extensionality principle and the body induction hypothesis to each arbitrary relational object.
By the common-reduction characterization of constructor equality, theorem 7.25, 𝐴 and 𝐵 reduce to one constructor 𝐶. Repeated one-step invariance gives [[𝐴]]𝜌=[[𝐶]]𝜌=[[𝐵]]𝜌. At an existential endpoint, keep the witness, payloads, and payload relation fixed. If a written endpoint annotation is 𝐸𝑖, its old and new side conditions are 𝐸𝑖≡𝐴[𝜌𝑖],𝐸𝑖≡𝐵[𝜌𝑖]. Applying constructor-equality substitution successively to the closed images of 𝜌𝑖 gives 𝐴[𝜌𝑖]≡𝐵[𝜌𝑖]. Transitivity converts the old condition to the new; symmetry and transitivity give the reverse implication. Thus the two existential membership conditions are equivalent. ◻
The abstraction theorem with packages
For existential elimination, the two endpoint substitutions and the closing term substitutions must be related. Let Δ⊢Γ𝖼𝗍𝗑 and let 𝜌:𝜌0↔𝜌1𝗈𝗏𝖾𝗋Δ. Endpoint substitutions 𝛾𝑖 close the term variables when ⋅;⋅⊢𝛾𝑖(𝑥):𝐴[𝜌𝑖]foreach𝑥:𝐴∈Γ. They are related, written 𝛾0[[Γ]]𝜌𝛾1, when [𝛾0(𝑥)][[𝐴]]𝜌[𝛾1(𝑥)]foreach𝑥:𝐴∈Γ.
Proof of Theorem 7.48 — Abstraction for F_ω with existentials
Proof. Induct on the typing derivation with the displayed relational judgment as the induction property. At a type binder, endpoint irrelevance preserves the relation on Γ. At constructor application, relational constructor substitution rewrites the interpreted result type. At T-Conv, conversion invariance rewrites the endpoint relations. Capture-avoiding substitution commutes with the closing substitutions in every term-binder case.
Variable. The conclusion is the corresponding component of 𝛾0[[Γ]]𝜌𝛾1.
Arrow introduction. For a last premise Δ;Γ,𝑥:𝐵⊢𝑒0:𝐶, take arbitrary closed 𝑎0,𝑎1 with [𝑎0][[𝐵]]𝜌[𝑎1]. The substitutions 𝛾𝑖[𝑥↦𝑎𝑖] are related at the extended context, so the induction hypothesis relates the two substituted bodies at [[𝐶]]𝜌. At endpoint 𝑖, term beta gives (𝜆𝑥:𝐵[𝜌𝑖].𝑒0[𝜌𝑖][𝛾𝑖])𝑎𝑖=𝛽𝑒0[𝜌𝑖][𝛾𝑖[𝑥↦𝑎𝑖]]. Thus the two applications satisfy the arrow-lifting clause.
Arrow elimination. The operator induction hypothesis lies in [[𝐵]]𝜌⇒[[𝐶]]𝜌, and the argument hypothesis lies in [[𝐵]]𝜌. Apply the former to the latter.
Type abstraction (T-TLam). Suppose the premise is Δ,𝑢::𝜅;Γ⊢𝑒0:𝐵, with 𝑢 fresh for Γ. To establish the universal relation, take an arbitrary relational object 𝑄=(𝐶0,𝐶1,𝑅) of kind 𝜅 and extend 𝜌 by 𝑢↦𝑄. Since 𝑢 is absent from every declaration in Γ, endpoint irrelevance says that the original 𝛾0,𝛾1 remain related. The induction hypothesis gives the body relation. The type-application beta law identifies its endpoints with ((Λ𝑢::𝜅.𝑒0)[𝜌𝑖][𝛾𝑖])[𝐶𝑖]. As 𝑄 was arbitrary, this is the universal clause.
Type application (T-TApp). Suppose the operator has type ∀𝑢::𝜅.𝐵 and the argument constructor is 𝐶. Its interpretation forms the relational object 𝑄𝐶=(𝐶[𝜌0],𝐶[𝜌1],[[𝐶]]𝜌). The operator induction hypothesis is universal over relational objects. Instantiating it at 𝑄𝐶 gives the body relation [[𝐵]]𝜌[𝑢↦𝑄𝐶], which equals [[𝐵[𝐶/𝑢]]]𝜌 by lemma 7.46.
Product introduction. The two induction hypotheses relate the components. The projection beta laws therefore put the two pairs in [[𝐴1]]𝜌×[[𝐴2]]𝜌.
Product elimination. The premise induction hypothesis is a pair in the product lifting. Its 𝑖th conjunct is exactly the required relation between the 𝑖th projections.
Natural numbers. The two occurrences of 𝟢 determine the same beta-class, hence are in 𝖤𝗊ℕ. In the successor case the induction hypothesis says the two arguments are beta-equal; compatible conversion makes their successors beta-equal as well.
Conversion. The premise induction hypothesis gives the relation interpreted at the premise type. By lemma 7.47, the conclusion type has the same interpreted relation after the endpoint conversions performed by T-Conv.
Existential introduction. Suppose the package witness is 𝐶::𝜅 and its payload premise has type 𝐵[𝐶/𝑢]. Form 𝑄𝐶 as in the constructor-application case. The payload induction hypothesis lies in [[𝐵[𝐶/𝑢]]]𝜌=[[𝐵]]𝜌[𝑢↦𝑄𝐶], where the equality is lemma 7.46. The two substituted package terms have witnesses 𝐶[𝜌0] and 𝐶[𝜌1], with payloads related by this equation. Hence they are related at [[∃𝑢::𝜅.𝐵]]𝜌.
Existential elimination. Write the last two premises as Δ;Γ⊢𝑒1:∃𝑢::𝜅.𝐵,Δ,𝑢::𝜅;Γ,𝑥:𝐵⊢𝑒2:𝐷, where 𝑢 is absent from Γ and 𝐷. By the first induction hypothesis, the two closed instances of 𝑒1 are related existential packages. Unfolding the existential clause gives a relational object 𝑄=(𝐶0,𝐶1,𝑅) and payloads 𝑎0,𝑎1 such that the endpoint instances of 𝑒1 are beta-equal to the corresponding packages and [𝑎0][[𝐵]]𝜌[𝑢↦𝑄][𝑎1]. Endpoint irrelevance keeps the substitutions 𝛾𝑖 related at Γ after extending 𝜌 by 𝑄. Extending them further by 𝑥↦𝑎𝑖 therefore satisfies the hypotheses for the body induction hypothesis, which gives [𝑒2[𝜌0,𝑢↦𝐶0][𝛾0,𝑥↦𝑎0]][[𝐷]]𝜌[𝑢↦𝑄][𝑒2[𝜌1,𝑢↦𝐶1][𝛾1,𝑥↦𝑎1]]. Since 𝑢 is not free in 𝐷, irrelevance changes the middle relation to [[𝐷]]𝜌. Finally, compatible conversion replaces each endpoint instance of 𝑒1 by its package, and the package computation rule gives 𝗎𝗇𝗉𝖺𝖼𝗄[𝑢,𝑥]=(𝗉𝖺𝖼𝗄[𝐶𝑖,𝑎𝑖])𝗂𝗇𝑒2=𝛽𝑒2[𝐶𝑖/𝑢][𝑎𝑖/𝑥]. This is exactly the pair of terms in the theorem’s conclusion. ◻
Let 𝐸 be a closed type. If [𝑝0][[𝐸]]𝜖[𝑝1] and 𝑘 is any closed term of type 𝐸→ℕ, then 𝑘𝑝0=𝛽𝑘𝑝1. In particular, when 𝐸 is existential, any pair related by its package clause satisfies the premise.
Proof of Corollary 12.23 — Related values are indistinguishable by natural clients
Proof. Self-parametricity gives [𝑘]([[𝐸]]𝜖⇒𝖤𝗊ℕ)[𝑘]. Apply this arrow relation to the assumed pair. Its result belongs to 𝖤𝗊ℕ, which is beta equality by definition. ◻
Representation independence for an existential counter
Representation independence means that clients cannot distinguish implementations related at their abstract interface. The Church-encoded counter of section 6.6 quantified the representation type in every client. The existential type 𝖢𝗈𝗎𝗇𝗍𝖾𝗋 of definition 7.32 moves that quantifier to the implementation boundary. The preceding calculations compared its ℕ implementation 𝐶𝑁 with its shadow-count implementation 𝐶𝑃 for one client. The logical relation proves that the two instances of every closed natural-number client are beta-convertible.
The state constructors are ℕ and 𝑃=ℕ×ℕ. Relate their closed terms by [𝑛]𝑅[𝑝]⟺𝑝=𝛽(𝑛,𝑛). This is a relation in Rel𝖳𝗒(ℕ,𝑃). It records the lockstep invariant used by the second implementation: both stored coordinates are the visible count.
Proof of Lemma 7.50 — The counter packages are related
Proof. Use the relational object (ℕ,𝑃,𝑅) as the hidden witness of the existential clause. We verify the three payload components.
First, 𝑖𝑃=𝛽(𝑖𝑁,𝑖𝑁), so [𝑖𝑁]𝑅[𝑖𝑃]. Next suppose [𝑛]𝑅[𝑝]. Then 𝑝=𝛽(𝑛,𝑛), and the projection and function beta laws give 𝑠𝑃𝑝=𝛽(𝗌𝗎𝖼(𝑛),𝗌𝗎𝖼(𝑛))=𝛽(𝑠𝑁𝑛,𝑠𝑁𝑛). Thus [𝑠𝑁](𝑅⇒𝑅)[𝑠𝑃]. The same hypothesis gives 𝑟𝑃𝑝=𝛽𝑛=𝛽𝑟𝑁𝑛, so [𝑟𝑁](𝑅⇒𝖤𝗊ℕ)[𝑟𝑃]. Two uses of product lifting now yield [𝑞𝑁]𝑅×((𝑅⇒𝑅)×(𝑅⇒𝖤𝗊ℕ))[𝑞𝑃]. This middle relation is [[𝑋×((𝑋→𝑋)×(𝑋→ℕ))]]𝑋↦(ℕ,𝑃,𝑅). In the existential clause, the two term-beta conditions are reflexive on the displayed packages, and the two annotation conditions are literal equalities because both packages are written with annotation 𝖢𝗈𝗎𝗇𝗍𝖾𝗋. The payload relation proved above is its fifth condition. The existential clause therefore relates 𝐶𝑁 and 𝐶𝑃. ◻
No identity-extension theorem is hidden in this proof. Such a theorem would identify the relation assigned to a closed type with equality at that type; section 6.4 showed why beta equality does not validate that principle in general. Equality of the observations follows only because the result constructor is the primitive ℕ and its relational clause was defined to be 𝖤𝗊ℕ. Replacing ℕ by an arbitrary closed type 𝑂 would yield related results at [[𝑂]]𝜖; it would not by itself yield beta equality. The calculations for 𝗍𝗂𝖼𝗄2 above are the visible instance of the theorem. The theorem now establishes their conclusion for every well-typed closed natural-number client.
The result is stated in beta equality, not silently in evaluation equivalence. This chapter has not established term-level normalization and confluence for the full 𝐹𝜔 package calculus. If those standard metatheorems are supplied, any call-by-value evaluations 𝑘𝐶𝑁⟶∗――𝑚 and 𝑘𝐶𝑃⟶∗――𝑛 are compatible beta reductions to normal forms; confluence and the theorem force 𝑚=𝑛. Without that additional metatheory, the proved observation is exactly the displayed beta equality.
★★☆ Keep the first representation ℕ and the second representation 𝑃=ℕ×ℕ, but define [𝑛]𝑅+[𝑝]⟺𝑝=𝛽(𝑛,𝗌𝗎𝖼(𝑛)). Take 𝑖+𝑃=(𝟢,𝗌𝗎𝖼(𝟢)), 𝑠+𝑃=𝜆𝑝:𝑃.(𝗌𝗎𝖼(𝗉𝗋1𝑝),𝗌𝗎𝖼(𝗉𝗋2𝑝)), and 𝑟+𝑃=𝜆𝑝:𝑃.𝗉𝗋1𝑝. Verify, in order, the initial-state, step, and observer relation hypotheses. Package this implementation as 𝐶+𝑃:𝖢𝗈𝗎𝗇𝗍𝖾𝗋 and prove that every closed 𝑘:𝖢𝗈𝗎𝗇𝗍𝖾𝗋→ℕ satisfies 𝑘𝐶𝑁=𝛽𝑘𝐶+𝑃. Your proof must identify the single use of self-parametricity and must not appeal to identity extension.
The package rules, escape condition, and representation independence pattern follow the development of abstract types in [Har16]. Relation environments and the abstraction argument originate with Reynolds; the relation interpretation and abstraction theorem occur on pp. 515–517, and the representation semantics and theorem on pp. 518–519 of [Rey83]. The arrow-kind action, constructor substitution, and conversion proofs above are the extension needed for this chapter’s 𝐹𝜔 signature. Those steps were proved locally rather than attributed to the System F statement in the cited paper.
Optional route.
A higher-rank client hidden inside existential elimination ⋆
The native unpacking rule binds an abstract constructor directly. There is another way to expose the same client boundary: ask a package to accept a polymorphic continuation. This does not replace the native calculus under call-by-value evaluation, but it shows exactly where a higher-rank argument enters the package encoding.
Suppose Δ,𝑢::𝜅⊢𝐴::𝖳𝗒. With 𝑅 fresh, define the Church package type 𝖲𝗈𝗆𝖾𝜅(𝑢.𝐴):=∀𝑅::𝖳𝗒.(∀𝑢::𝜅.𝐴→𝑅)→𝑅. If Δ⊢𝐶::𝜅 and Δ;Γ⊢𝑣:𝐴[𝐶/𝑢], define 𝖼𝗉𝖺𝖼𝗄[𝐶,𝑣]:=Λ𝑅::𝖳𝗒.𝜆𝑘:∀𝑢::𝜅.𝐴→𝑅.𝑘[𝐶]𝑣. Rule T-TApp gives 𝑘[𝐶]:𝐴[𝐶/𝑢]→𝑅; its domain is well formed by constructor substitution. Together with Δ;Γ⊢𝑣:𝐴[𝐶/𝑢], rule T-App gives 𝑘[𝐶]𝑣:𝑅. Repeated uses of T-TLam and T-Lam derive Δ;Γ⊢𝖼𝗉𝖺𝖼𝗄[𝐶,𝑣]:𝖲𝗈𝗆𝖾𝜅(𝑢.𝐴).
Here rank counts how deeply a universal quantifier occurs to the left of arrows. A prenex type has all of its quantifiers at the front and has rank one; placing such a polymorphic type in an arrow domain raises the rank to two. A monomorphic type in this paragraph contains no universal quantifier.
Now suppose Δ⊢Γ𝖼𝗍𝗑,Δ;Γ⊢𝑝:𝖲𝗈𝗆𝖾𝜅(𝑢.𝐴),Δ,𝑢::𝜅;Γ,𝑥:𝐴⊢𝑒:𝐵,Δ⊢𝐵::𝖳𝗒. Formation of Γ before 𝑢 makes the constructor binder fresh for the surrounding term context; formation of 𝐵 before 𝑢 is the escape condition. These are the two corresponding side conditions of native unpacking. The continuation Λ𝑢::𝜅.𝜆𝑥:𝐴.𝑒:∀𝑢::𝜅.𝐴→𝐵 may be passed to a Church package 𝑝 by 𝖼𝗈𝗉𝖾𝗇𝐵(𝑝;𝑢,𝑥.𝑒):=𝑝[𝐵](Λ𝑢::𝜅.𝜆𝑥:𝐴.𝑒). Here a polymorphic term appears in the domain of the package’s continuation arrow. When 𝐴 and 𝐵 contain no nested universal types, the continuation ∀𝑢::𝜅.𝐴→𝐵 has rank one, while the enclosing arrow (∀𝑢::𝜅.𝐴→𝐵)→𝐵 has rank two. If 𝐴 or 𝐵 already has higher-rank structure, the rank may be larger. Higher kinds and higher rank are independent notions: 𝜅 may be 𝖳𝗒; the rank rise comes from placing the polymorphic continuation to the left of an arrow.
For a value payload, the entire administrative calculation is visible: 𝖼𝗈𝗉𝖾𝗇𝐵(𝖼𝗉𝖺𝖼𝗄[𝐶,𝑣];𝑢,𝑥.𝑒)=(Λ𝑅.𝜆𝑘.𝑘[𝐶]𝑣)[𝐵](Λ𝑢.𝜆𝑥.𝑒)𝑡𝑦𝑝𝑒−𝛽⟶(𝜆𝑘.𝑘[𝐶]𝑣)(Λ𝑢.𝜆𝑥.𝑒)𝛽⟶(Λ𝑢.𝜆𝑥.𝑒)[𝐶]𝑣𝑡𝑦𝑝𝑒−𝛽⟶(𝜆𝑥.𝑒[𝐶/𝑢])𝑣𝛽⟶𝑒[𝐶/𝑢][𝑣/𝑥]. Constructor and term annotations have only been suppressed on the middle three lines. The result is the native unpacking contraction.
This calculation does not prove a general call-by-value encoding theorem. A native package evaluates its payload before becoming a value; a Church package begins with Λ𝑅 and can hide an unfinished payload beneath that value. Thus we have proved typing and the value-payload calculation, not operational equivalence for arbitrary effects or divergence. Church checking remains syntax directed because every binder is annotated. The undecidability of Curry-style System F inference from theorem 5.23 is unaffected.
★★☆ Write the Church encoding of 𝐶𝑁 at 𝖲𝗈𝗆𝖾𝖳𝗒(𝑋.𝑋×((𝑋→𝑋)×(𝑋→ℕ))). Use the displayed body of 𝗍𝗂𝖼𝗄2 as the continuation, derive the continuation’s polymorphic type, and reproduce all four contractions above. Identify the polymorphic-continuation subterm, reproduce its type, and explain why the enclosing arrow has rank two when the counter payload and result types are monomorphic.
The existential-as-universal definition and its beta calculation appear in [GLT89]. Harper gives the same client encoding and states the lazy-dynamics qualification in [Har16]. The value restriction in the calculation above is therefore part of the theorem, not an implementation footnote.
First-class packages
A package is an ordinary term, so an eliminator may select between package values at run time. Using the Church booleans of definition 5.15, with their quantified variable kinded by 𝖳𝗒, define 𝖼𝗁𝗈𝗈𝗌𝖾𝖢𝗈𝗎𝗇𝗍𝖾𝗋:𝖡𝗈𝗈𝗅𝐹→𝖢𝗈𝗎𝗇𝗍𝖾𝗋→𝖢𝗈𝗎𝗇𝗍𝖾𝗋→𝖢𝗈𝗎𝗇𝗍𝖾𝗋,𝖼𝗁𝗈𝗈𝗌𝖾𝖢𝗈𝗎𝗇𝗍𝖾𝗋:=𝜆𝑏:𝖡𝗈𝗈𝗅𝐹.𝜆𝑚:𝖢𝗈𝗎𝗇𝗍𝖾𝗋.𝜆𝑛:𝖢𝗈𝗎𝗇𝗍𝖾𝗋.𝑏[𝖢𝗈𝗎𝗇𝗍𝖾𝗋]𝑚𝑛. All three lambda annotations are the types displayed on the first line. The universal elimination for 𝑏, followed by two applications, proves the typing judgment.
The true branch is a complete first-class-package calculation: 𝗍𝗂𝖼𝗄2(𝖼𝗁𝗈𝗈𝗌𝖾𝖢𝗈𝗎𝗇𝗍𝖾𝗋𝗍𝗋𝗎𝖾𝐹𝐶𝑁𝐶𝑃)𝑢𝑛𝑓𝑜𝑙𝑑𝖼𝗁𝗈𝗈𝗌𝖾𝖢𝗈𝗎𝗇𝗍𝖾𝗋⟶∗𝗍𝗂𝖼𝗄2(𝗍𝗋𝗎𝖾𝐹[𝖢𝗈𝗎𝗇𝗍𝖾𝗋]𝐶𝑁𝐶𝑃)𝐵𝑜𝑜𝑙𝑒𝑎𝑛𝛽⟶∗𝗍𝗂𝖼𝗄2𝐶𝑁𝑐𝑜𝑢𝑛𝑡𝑒𝑟𝑐𝑎𝑙𝑐𝑢𝑙𝑎𝑡𝑖𝑜𝑛⟶∗𝗌𝗎𝖼(𝗌𝗎𝖼(𝟢)). Replacing 𝗍𝗋𝗎𝖾𝐹 by 𝖿𝖺𝗅𝗌𝖾𝐹 chooses 𝐶𝑃 and reaches the same displayed numeral by the earlier shadow-count calculation. The choice occurs before unpacking; both branches have the common existential type 𝖢𝗈𝗎𝗇𝗍𝖾𝗋.
First class does not make the hidden constructor projectible. From an arbitrary 𝑚:𝖢𝗈𝗎𝗇𝗍𝖾𝗋 there is no type expression 𝑚.𝑋 in the core grammar. One must unpack 𝑚, receiving a fresh lexical name 𝑋 whose scope is the unpacking body. The core also has no syntax relating the hidden constructors of two packages or naming a component of one package in the type of another. Module systems with static names and sharing judgments add those capabilities; lexical packages alone establish none of them.
★★☆ Give the full type derivation of 𝖼𝗁𝗈𝗈𝗌𝖾𝖢𝗈𝗎𝗇𝗍𝖾𝗋. Then calculate the false branch through the boolean’s three beta contractions and the two counter steps. Finally explain why the proposed assignment 𝖼𝗁𝗈𝗈𝗌𝖾𝖢𝗈𝗎𝗇𝗍𝖾𝗋𝑏𝐶𝑁𝐶𝑃:ℕ would violate package opacity.
The passage between a second-class module and a first-class existential package is given in [Har16]. That comparison does not identify packages with the full ML module hierarchy, and neither do we.
Two record failures, two different missing judgments
Products can encode an ordered tuple, but label-based records expose a different problem. To make the failure exact, temporarily add a static fixed-record fragment with record types and two term forms: 𝐴::=⋯∣{ℓ𝑖:𝐴𝑖}𝑖∈𝐼,𝑒::=⋯∣{ℓ𝑖=𝑒𝑖}𝑖∈𝐼∣𝑒.ℓ. The finite label set has no duplicates. Its formation and typing rules are Δ⊢𝐴𝑖::𝖳𝗒(𝑖∈𝐼)Δ⊢{ℓ𝑖:𝐴𝑖}𝑖∈𝐼::𝖳𝗒Rec−FΔ;Γ⊢𝑒𝑖:𝐴𝑖(𝑖∈𝐼)Δ;Γ⊢{ℓ𝑖=𝑒𝑖}𝑖∈𝐼:{ℓ𝑖:𝐴𝑖}𝑖∈𝐼Rec−I and Δ;Γ⊢𝑒:{ℓ𝑖:𝐴𝑖}𝑖∈𝐼𝑗∈𝐼Δ;Γ⊢𝑒.ℓ𝑗:𝐴𝑗Rec−E. Its only new equality rule is componentwise equality after sorting labels: Δ⊢𝐴𝑖≡𝐵𝑖::𝖳𝗒(𝑖∈𝐼)Δ⊢{ℓ𝑖:𝐴𝑖}𝑖∈𝐼≡{ℓ𝑖:𝐵𝑖}𝑖∈𝐼::𝖳𝗒Q−Rec. We use this fragment only for static typing counterexamples; no record-value or operational theorem is claimed here. In particular, there is still no subtyping judgment.
The first failure asks for an unknown remainder. The intended type of record extension would have the following shape in a hypothetical higher-kinded extension with a row kind: ∀𝜉::𝖱𝗈𝗐.(𝜉\𝗌𝖾𝖼𝗎𝗋𝖾)⇒𝖱𝖾𝖼(𝜉)→𝖱𝖾𝖼({𝗌𝖾𝖼𝗎𝗋𝖾:𝖡𝗈𝗈𝗅𝐹∣𝜉}). Here ⇒ is the qualified-type constraint arrow of chapter 4, not the relation lifting used in the preceding logical relation. This is not merely unprovable in 𝐹𝜔 plus fixed records: it is not a formed type. The kind grammar contains no 𝖱𝗈𝗐, the constructor grammar contains no row extension, and the judgments contain no lacks predicate. Quantifying over 𝑐::𝖳𝗒→𝖳𝗒 does not create field selection or extension operations. The calculus of chapter 4 has a second syntactic sort of rows, row extension, and lacks predicates. Internalizing those ingredients here would add a kind 𝖱𝗈𝗐 and require the constructor metatheory to be rerun for it.
The second failure needs no unknown tail. As already previewed for the row calculus in subsection 7.8.3, define 𝗉𝗈𝗋𝗍𝖮𝖿:{𝗉𝗈𝗋𝗍:ℕ}→ℕ,𝗉𝗈𝗋𝗍𝖮𝖿:=𝜆𝑟:{𝗉𝗈𝗋𝗍:ℕ}.𝑟.𝗉𝗈𝗋𝗍, and the closed larger record 𝗌𝖾𝗋𝗏𝖾𝗋:={𝗉𝗈𝗋𝗍=𝟢,𝗌𝖾𝖼𝗎𝗋𝖾=𝗍𝗋𝗎𝖾𝐹}:{𝗉𝗈𝗋𝗍:ℕ,𝗌𝖾𝖼𝗎𝗋𝖾:𝖡𝗈𝗈𝗅𝐹}. The application 𝗉𝗈𝗋𝗍𝖮𝖿𝗌𝖾𝗋𝗏𝖾𝗋 fails. Its argument has the larger fixed record type, while T-App requires the exact domain {𝗉𝗈𝗋𝗍:ℕ}. The two sorted record constructors are distinct normal forms, so T-Conv cannot remove the extra field. A width relation {𝗉𝗈𝗋𝗍:ℕ,𝗌𝖾𝖼𝗎𝗋𝖾:𝖡𝗈𝗈𝗅𝐹}<:{𝗉𝗈𝗋𝗍:ℕ} would say that the larger record type is usable where the smaller one is expected; in general, 𝐴<:𝐵 proposes that 𝐴 is usable where 𝐵 is expected. Adding that width judgment and a subsumption rule would derive the application: width gives the displayed subtype premise, and subsumption changes the argument’s fixed record type to {𝗉𝗈𝗋𝗍:ℕ}. Neither <: nor subsumption belongs to the 𝐹𝜔 fragment of definition 7.31; constructor equality cannot derive the width premise. The missing term rule would take premises Γ⊢𝑒:𝐴 and 𝐴<:𝐵 to Γ⊢𝑒:𝐵.
The remedies are independent. Width subtyping forgets fields but does not name and preserve an unknown tail through extension. Row polymorphism names that tail but, without a subsumption rule, does not allow every fixed larger record wherever a smaller fixed record is expected.
Existential packages hide a constructor behind typed operations. Package preservation and progress establish the operational boundary; the higher-kinded logical relation proves representation independence for the two counter implementations. First-class selection is an ordinary consequence of native packages. Constructor equality still cannot forget a fixed record field; a subtype judgment and subsumption lie outside this calculus.
Suggested first pass.
None of these problems is a prerequisite for later chapters. Begin with exercise 7.20; it is the shortest route through the two distinct record boundaries and the handoff to subtyping. Then implement exercise 12.10.
★★☆ For the unknown-remainder type, name the three symbols or judgments that are absent from the fixed-record calculus. For the width application, derive the types of 𝗉𝗈𝗋𝗍𝖮𝖿 and 𝗌𝖾𝗋𝗏𝖾𝗋, then show exactly where T-App fails. Add only a width rule and subsumption; rederive the application and explain why the unknown-remainder type is still unformed.
★★★Practical project.existential-package-checker Implement kind inference and explicit 𝐹𝜔 term checking for the constructor and term grammars recalled in this chapter, then add a compatible evaluator including T-Pack, T-Unpack, and the package call-by-value contractions. A checker from exercise 11.9 may be reused, but is not a premise of this project. Preserve the invariant that the result type of an unpacking is formed outside the hidden-constructor scope. The acceptance test must type and evaluate both counter packages through two increments and an observation, reject the two representation-leaking clients described after definition 7.31, and reject 𝗉𝗈𝗋𝗍𝖮𝖿𝗌𝖾𝗋𝗏𝖾𝗋 in the fixed-record fragment. Compare the two successful observations at ℕ; this checks the concrete instance of representation independence without claiming to decide the full logical relation.