Prerequisites. Direct starred prerequisites: none. No later core chapter depends on this route.
The existential packages of chapter 10 can hide one representation. Reusing that chapter’s counter, for example, gives the interface ∃𝑡::𝖳𝗒.𝑡×((𝑡→𝑡)×(𝑡→ℕ)). After unpacking, a client receives a fresh type name, an initial state, a step, and an observation. This is the right lexical account of one abstract value. It does not yet describe 𝗌𝗍𝗋𝗎𝖼𝗍𝗎𝗋𝖾 𝖭𝖺𝗍𝖮𝗋𝖽𝖾𝗋:𝖮𝖱𝖣𝖤𝖱𝖤𝖣,𝖿𝗎𝗇𝖼𝗍𝗈𝗋 𝖲𝖾𝗍𝖥𝗇(𝑋:𝖮𝖱𝖣𝖤𝖱𝖤𝖣):𝖲𝖤𝖳 𝗌𝗁𝖺𝗋𝗂𝗇𝗀 𝗍𝗒𝗉𝖾 𝖾𝗅𝖾𝗆=𝑋.𝑠,𝗌𝗍𝗋𝗎𝖼𝗍𝗎𝗋𝖾 𝖭𝖺𝗍𝖲𝖾𝗍=𝖲𝖾𝗍𝖥𝗇(𝖭𝖺𝗍𝖮𝗋𝖽𝖾𝗋). The sharing clause requires the result’s element type to be the very constructor selected by the argument’s component s, not merely a constructor of the same kind. An ML functor takes one statically classified module to another, and its result signature may mention the argument’s type component. A signature is a module’s static classifier; a module is the packaged implementation. The result interface must remember that its element type is the very type selected by the argument. Packing the argument and result independently creates unrelated existential witnesses. Unpacking the argument inside the functor body makes its witness lexical: the name cannot occur in the result type after that unpacking ends. Adding an equation outside the packages merely asserts the sharing that the encoding failed to transport.
The failure can be displayed before adding module signatures. If 𝑂 and 𝑆 are independently packed order and set implementations, the attempt 𝗎𝗇𝗉𝖺𝖼𝗄[𝑡,𝑜]=𝑂 𝗂𝗇 𝗎𝗇𝗉𝖺𝖼𝗄[𝑢,𝑠]=𝑆 𝗂𝗇𝗉𝖺𝖼𝗄[𝑡,⟨𝑜,𝑠⟩]:∃𝑎::𝖳𝗒.(𝑎→𝑎→𝟐)×𝖲𝖾𝗍(𝑎) does not type: its second component has type 𝖲𝖾𝗍(𝑢), not 𝖲𝖾𝗍(𝑡). Choosing witness 𝑢 makes the order component fail instead. The two lexical witnesses provide no equation between 𝑡 and 𝑢.
A projectible path is a module path whose static projections carry a stable type identity. Signature matching propagates that identity into later components before any dynamic code runs. In the reduced calculus, opaque sealing is generative and functor application is nonprojectible.
★★☆ Write separate existential packages for 𝖭𝖺𝗍𝖮𝗋𝖽𝖾𝗋 and a set of its elements. Unpack the order package in the smallest possible scope. Mark the point at which its witness would have to escape to type the set package. Explain why replacing both witnesses by ℕ destroys abstraction.
Referenced from 3 locations
One reduced module calculus
The constructor and pure-term core is the 𝐹𝜔 calculus of chapter 9, restricted to 𝖳𝗒, singleton kinds, arrows, products, and the pure terms appearing in module components. The only new constructor feature is a singleton kind 𝖲𝗂𝗇𝗀(𝑐). A mixed context Γ contains constructor assumptions 𝑢 ::𝜅, expression assumptions 𝑥 :𝜏, and module assumptions 𝑋 :𝜎. Its exact singleton delta is Γ⊢𝑐::𝖳𝗒Γ⊢𝖲𝗂𝗇𝗀(𝑐) 𝗄𝗂𝗇𝖽Sing−Kind,Γ⊢𝑐::𝖳𝗒Γ⊢𝑐::𝖲𝗂𝗇𝗀(𝑐)Sing−I, Γ⊢𝑐::𝖳𝗒Γ⊢𝖲𝗂𝗇𝗀(𝑐)⪯𝗄𝖳𝗒Sing−Sub,Γ⊢𝑑::𝖲𝗂𝗇𝗀(𝑐)Γ⊢𝑑≡𝑐::𝖳𝗒Sing−E. Thus 𝑑 ::𝖲𝗂𝗇𝗀(𝑐) entails 𝑑 ≡𝑐 ::𝖳𝗒: a singleton kind records a static constructor equation. Subkinding is the least reflexive and transitive relation containing Sing-Sub and closed under kind equivalence; constructor kinding admits subsumption along it. Dynamic-type subtyping in this reduced calculus is conversion: Γ ⊢𝜏1 <:𝜏2 exactly when Γ ⊢𝜏1 ≡𝜏2 𝗍𝗒𝗉𝖾. Constructor equivalence and pure-term typing otherwise use the inherited 𝐹𝜔 rules, but Sing-E adds the directed conclusion Γ ⊢𝑑 ≡𝑐 ::𝖳𝗒 from Γ ⊢𝑑 ::𝖲𝗂𝗇𝗀(𝑐). A singleton kind is therefore a static equation, not a runtime test.
The selected fragment uses an acyclic manifest environment. Read the context from left to right. A manifest atom is either a declaration 𝑢 ::𝖲𝗂𝗇𝗀(𝑐) or a projectible component 𝑄.𝑠 whose signature carries that singleton kind; its manifest equation is 𝑢 ↦𝑐 or 𝑄.𝑠 ↦𝑐. The right-hand side 𝑐 must be well kinded in the earlier context. Constructor variables and projectible static projections are the only atoms. Define 𝖾𝗑𝗉𝖺𝗇𝖽Γ(𝑑) by replacing each manifest atom by its earlier right-hand side, recursively, and then taking the inherited 𝐹𝜔 beta-eta normal form. The declaration index strictly decreases at every manifest replacement.
Algorithmic constructor conversion first synthesizes the inherited kind of both inputs, erasing 𝖲𝗂𝗇𝗀(𝑐) to 𝖳𝗒, and then compares 𝖾𝗑𝗉𝖺𝗇𝖽Γ(𝑑1) and 𝖾𝗑𝗉𝖺𝗇𝖽Γ(𝑑2) up to alpha-equivalence. Algorithmic subkinding accepts equal normalized kinds and the one strict shape 𝖲𝗂𝗇𝗀(𝑐) ⪯𝗄𝖳𝗒. Checking 𝑑 at 𝖲𝗂𝗇𝗀(𝑐) synthesizes 𝑑 ::𝖳𝗒 and applies the conversion test to 𝑑 and 𝑐; checking at any other kind uses inherited 𝐹𝜔 kinding.
On well-formed acyclic manifest contexts, the preceding kinding, subkinding, and conversion procedures terminate. They are sound and complete for the displayed singleton rules together with the inherited 𝐹𝜔 rules.
Referenced from 3 locations
Proof of Proposition 14.1 — Decision for the singleton constructor fragment
Proof. Manifest expansion terminates because every replacement decreases the declaration index. The inherited normalization and comparison terminate by the 𝐹𝜔 normalization and conversion result of corollary 7.26; the subkinding test is a finite shape comparison.
For soundness, induction on expansion replaces 𝑞 by 𝑐 using the singleton equation recorded when 𝑞 entered the context. Inherited beta-eta normalization preserves constructor equality, so equal normal forms give declarative conversion. The strict subkind case is Sing-Sub, and singleton checking ends with Sing-I followed by conversion.
For completeness, induct on a declarative derivation. The inherited cases are complete by the 𝐹𝜔 procedure. In the new Sing-E case, the manifest atom and its recorded right-hand side expand to the same normal form. Reflexivity, symmetry, and transitivity preserve equality of normal forms, and congruence follows because expansion is homomorphic before normalization. The only strict generated subkind is Sing-Sub. After equality steps are contracted, a subkinding derivation contains at most one strict step: no rule derives 𝖳𝗒 ⪯𝗄𝖲𝗂𝗇𝗀(𝑐). The finite test therefore covers every derivation. ◻
The signatures of the reduced calculus are 𝜎::=𝖡(𝑢::𝜅;𝜏)∣𝖲𝗂𝗀𝗆𝖺(𝑋:𝜎1).𝜎2∣𝖯𝗂(𝑋:𝜎1).𝜎2. A basic signature contains one static constructor component 𝑢 and one dynamic component of type 𝜏, which may mention 𝑢. A hierarchy signature lets the second component mention the first path. A functor signature lets its result mention its argument path.
Referenced from 8 locations
The formation rules state each dependency explicitly: the dynamic type 𝜏 in B-Sig is formed under its static component 𝑢, while the codomain signature 𝜎2 in Sigma-Sig and Pi-Sig is formed under the module path 𝑋: Γ⊢𝜅 𝗄𝗂𝗇𝖽Γ,𝑢::𝜅⊢𝜏 𝗍𝗒𝗉𝖾Γ⊢𝖡(𝑢::𝜅;𝜏) 𝗌𝗂𝗀B−Sig, Γ⊢𝜎1 𝗌𝗂𝗀Γ,𝑋:𝜎1⊢𝜎2 𝗌𝗂𝗀Γ⊢𝖲𝗂𝗀𝗆𝖺(𝑋:𝜎1).𝜎2 𝗌𝗂𝗀Sigma−Sig. Γ⊢𝜎1 𝗌𝗂𝗀Γ,𝑋:𝜎1⊢𝜎2 𝗌𝗂𝗀Γ⊢𝖯𝗂(𝑋:𝜎1).𝜎2 𝗌𝗂𝗀Pi−Sig. Signature equivalence contains alpha-equivalence and the inherited kind, constructor, and type equivalences. It is closed under the congruence rules below. In B-Eq, write 𝛽𝑖:=𝖡(𝑢::𝜅𝑖;𝜏𝑖). Its new congruence rules are Γ⊢𝜅1≡𝜅2 𝗄𝗂𝗇𝖽Γ,𝑢::𝜅1⊢𝜏1≡𝜏2 𝗍𝗒𝗉𝖾Γ⊢𝛽1≡𝛽2 𝗌𝗂𝗀B−Eq, Γ⊢𝜎1≡𝜎′1 𝗌𝗂𝗀Γ,𝑋:𝜎1⊢𝜎2≡𝜎′2 𝗌𝗂𝗀Γ⊢𝖲𝗂𝗀𝗆𝖺(𝑋:𝜎1).𝜎2≡𝖲𝗂𝗀𝗆𝖺(𝑋:𝜎′1).𝜎′2 𝗌𝗂𝗀Sigma−Eq. Γ⊢𝜎1≡𝜎′1 𝗌𝗂𝗀Γ,𝑋:𝜎1⊢𝜎2≡𝜎′2 𝗌𝗂𝗀Γ⊢𝖯𝗂(𝑋:𝜎1).𝜎2≡𝖯𝗂(𝑋:𝜎′1).𝜎′2 𝗌𝗂𝗀Pi−Eq.
Let 𝑠 ::𝖳𝗒 and suppose the inherited constructor rules derive 𝑠 →𝑠 →𝖡𝗈𝗈𝗅 𝗍𝗒𝗉𝖾. Then the complete signature formation is Γ⊢𝖳𝗒 𝗄𝗂𝗇𝖽Γ,𝑠::𝖳𝗒⊢𝑠→𝑠→𝖡𝗈𝗈𝗅 𝗍𝗒𝗉𝖾Γ⊢𝖡(𝑠::𝖳𝗒;𝑠→𝑠→𝖡𝗈𝗈𝗅) 𝗌𝗂𝗀B−Sig. This is the one-field core of the order signature 𝖡(𝑠 ::𝖳𝗒;𝑠 →𝑠 →𝖡𝗈𝗈𝗅): the static component chooses the carrier and the dynamic component may mention it.
Referenced from 2 locations
Surface records with several type and value fields are right-associated hierarchies of basic signatures. This convention is structural, not an equation identifying differently associated hierarchies.
The module phrases, together with the two projections from a basic module, are 𝑀::=𝑋∣⟨𝑐;𝑒⟩∣𝑀↾𝜎∣(𝗅𝖾𝗍 𝑋=𝑀1 𝗂𝗇 𝑀2):𝜎∣⟨𝑀1;𝑀2⟩∣𝑀.1∣𝑀.2∣𝜆𝑋:𝜎.𝑀∣𝑀1(𝑀2). The static constructor grammar additionally admits 𝑀.𝑠, and the dynamic term grammar admits 𝑀.𝑑. These projections are defined only when 𝑀 has a basic signature. The basic structure ⟨𝑐;𝑒⟩ has static part 𝑐 and dynamic part 𝑒. The seal 𝑀 ↾𝜎 is opaque. The annotation on module 𝗅𝖾𝗍 is part of the language, not a hint.
A module value and a projectible path are different notions. In an open context the open module-value judgment, written Γ ⊢𝑀 𝗆𝗏𝖺𝗅, is generated by 𝑋:𝜎∈ΓΓ⊢𝑋 𝗆𝗏𝖺𝗅V−Var,Γ⊢𝑣 𝗏𝖺𝗅Γ⊢⟨𝑐;𝑣⟩ 𝗆𝗏𝖺𝗅V−Basic, Γ⊢𝑉1 𝗆𝗏𝖺𝗅Γ⊢𝑉2 𝗆𝗏𝖺𝗅Γ⊢⟨𝑉1;𝑉2⟩ 𝗆𝗏𝖺𝗅V−Hierarchy. 𝑋Γ⊢𝜆𝑋:𝜎.𝑀 𝗆𝗏𝖺𝗅V−Functor. A projectible phrase is generated by 𝑄::=𝑋∣⟨𝑐;𝑣⟩∣⟨𝑄1;𝑄2⟩∣𝑄.1∣𝑄.2, where each projection is well typed. Its judgment is generated by 𝑋:𝜎∈ΓΓ⊢𝑋 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾P−Var,Γ⊢𝑣 𝗏𝖺𝗅Γ⊢⟨𝑐;𝑣⟩ 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾P−Basic, Γ⊢𝑄1 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾Γ⊢𝑄2 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾Γ⊢⟨𝑄1;𝑄2⟩ 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾P−Hierarchy. Γ⊢𝑄 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾Γ⊢𝑄.𝑖 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾P−Projection. A seal, annotated let, functor, and functor application are not projectible. A functor abstraction is a value but not projectible. Only projectible phrases may occur to the left of the static selector .𝑠.
Referenced from 3 locations
The judgment Γ ⊢𝑀 :𝜎 is generated by the following module rules. Basic structures expose singleton kinds; sealing checks a match and exports only the sealed signature: 𝑋:𝜎∈ΓΓ⊢𝑋:𝜎Var,Γ⊢𝑐::𝜅Γ⊢𝑒:𝜏[𝑐/𝑢]Γ⊢⟨𝑐;𝑒⟩:𝖡(𝑢::𝖲𝗂𝗇𝗀(𝑐);𝜏)Basic, Γ⊢𝑀:𝜎0D::Γ⊢𝜎0⪯𝗌𝜎Γ⊢𝑀↾𝜎:𝜎Seal. Γ⊢𝜎 𝗌𝗂𝗀Γ⊢𝑀1:𝜎1Γ,𝑋:𝜎1⊢𝑀2:𝜎Γ⊢(𝗅𝖾𝗍 𝑋=𝑀1 𝗂𝗇 𝑀2):𝜎Let, Γ⊢𝑀:𝜎1D::Γ⊢𝜎1⪯𝗌𝜎2Γ⊢𝑀:𝜎2Sub. Hierarchy introduction is intentionally nondependent. Dependency is added by matching and self-recognition, not guessed by the introduction rule: Γ⊢𝑀1:𝜎1Γ⊢𝑀2:𝜎2Γ⊢⟨𝑀1;𝑀2⟩:𝖲𝗂𝗀𝗆𝖺(:𝜎1).𝜎2Hierarchy. Γ⊢𝑀:𝖲𝗂𝗀𝗆𝖺(𝑋:𝜎1).𝜎2Γ⊢𝑀.1:𝜎1First, Γ⊢𝑀:𝖲𝗂𝗀𝗆𝖺(𝑋:𝜎1).𝜎2𝑋∉FV(𝜎2)Γ⊢𝑀.2:𝜎2Second. Direct second projection is therefore forbidden while the range mentions the first path. The abbreviation 𝖲𝗂𝗀𝗆𝖺(:𝜎1).𝜎2 records this displayed freshness premise; it does not encode an additional rule.
The two-sorted basic projections have distinct judgments: Γ⊢𝑄 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾Γ⊢𝑄:𝖡(𝑢::𝜅;𝜏)Γ⊢𝑄.𝑠::𝜅Static. Γ⊢𝑀:𝖡(𝑢::𝜅;𝜏)𝑢∉FV(𝜏)Γ⊢𝑀.𝑑:𝜏Dynamic. Thus Static requires a stable path, and Dynamic requires a nondependent basic signature. A dependent dynamic type is first made nondependent by self-recognition and signature equivalence: Γ⊢𝑄:𝖡(𝑢::𝜅;𝜏)Γ⊢𝑄 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾Γ⊢𝑄:𝖡(𝑢::𝖲𝗂𝗇𝗀(𝑄.𝑠);𝜏)Self. Hierarchy self-recognition propagates the signatures of projectible components: Γ⊢𝑄 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾Γ⊢𝑄:𝖲𝗂𝗀𝗆𝖺(𝑋:𝜎1).𝜎2Γ⊢𝑄.1:𝜎′1Γ⊢𝜎′1⪯𝗌𝜎1Γ⊢𝑄:𝖲𝗂𝗀𝗆𝖺(𝑋:𝜎′1).𝜎2Self−First, Γ⊢𝑄 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾Γ⊢𝑄:𝖲𝗂𝗀𝗆𝖺(:𝜎1).𝜎2Γ⊢𝑄.2:𝜎′2Γ⊢𝜎′2⪯𝗌𝜎2Γ⊢𝑄:𝖲𝗂𝗀𝗆𝖺(:𝜎1).𝜎′2Self−Second. Finally, functors are checked by Γ,𝑋:𝜎1⊢𝑀:𝜎2Γ⊢𝜆𝑋:𝜎1.𝑀:𝖯𝗂(𝑋:𝜎1).𝜎2Functor. Γ⊢𝐹:𝖯𝗂(𝑋:𝜎1).𝜎2Γ⊢𝐴:𝜎1𝑋∉FV(𝜎2)Γ⊢𝐹(𝐴):𝜎2Apply. Thus the range dependency must be eliminated before application. As above, an underscore in this binder abbreviates the displayed freshness premise.
The conclusion of Basic recognizes the constructor it contains. The conclusion of Seal has exactly the written interface, and the result is not a path. Transparent ascription is not a second term former: it is matching by subsignature, which retains every singleton written in the target. Opaque sealing forgets every equation absent from its target.
A surface constraint with type s = c is represented by the singleton signature 𝖡(𝑠 ::𝖲𝗂𝗇𝗀(𝑐);𝜏). A sharing type constraint uses 𝖲𝗂𝗀𝗆𝖺-dependency followed by singleton matching, while opaque ascription is 𝑀 ↾𝜎.
For 𝑐 ::𝖳𝗒, define 𝖮𝖱𝖣𝖤𝖱𝖤𝖣:=𝖡(𝑠::𝖳𝗒;𝑠→𝑠→𝟐),𝖮𝖱𝖣𝖤𝖱𝖤𝖣[𝑐]:=𝖡(𝑠::𝖲𝗂𝗇𝗀(𝑐);𝑠→𝑠→𝟐). If 𝗅𝖾𝖭𝖺𝗍 :ℕ →ℕ →𝟐, then 𝖭𝖺𝗍𝖮𝗋𝖽𝖾𝗋0:=⟨ℕ;𝗅𝖾𝖭𝖺𝗍⟩:𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ]. Transparent matching against 𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ] preserves 𝑠 =ℕ. The opaque module 𝖭𝖺𝗍𝖮𝗋𝖽𝖾𝗋0↾𝖮𝖱𝖣𝖤𝖱𝖤𝖣:𝖮𝖱𝖣𝖤𝖱𝖤𝖣 hides it.
Referenced from 2 locations
★☆☆ Give a Boolean implementation of 𝖮𝖱𝖣𝖤𝖱𝖤𝖣[𝟐]. Type it once by transparent matching and once by opaque sealing to 𝖮𝖱𝖣𝖤𝖱𝖤𝖣. For each result, decide whether a client may pass 𝗍𝗋𝗎𝖾 directly to the comparison operation, citing its exported static kind.
Referenced from 3 locations
Matching, hierarchies, and sharing
Write Γ ⊢𝜎1 ⪯𝗌𝜎2 when every module matching 𝜎1 may be used at 𝜎2. Subkinding is written 𝜅1 ⪯𝗄𝜅2; ordinary dynamic-type subtyping retains 𝜏1 <:𝜏2. These judgments express signature matching, kind inclusion, and dynamic type conversion, respectively; none entails either of the others. Subsignature matching is the least relation generated by Γ⊢𝜎 𝗌𝗂𝗀Γ⊢𝜎⪯𝗌𝜎Sig−Refl,Γ⊢𝜎1⪯𝗌𝜎2Γ⊢𝜎2⪯𝗌𝜎3Γ⊢𝜎1⪯𝗌𝜎3Sig−Trans, Γ⊢𝜎1≡𝜎′1 𝗌𝗂𝗀Γ⊢𝜎′1⪯𝗌𝜎′2Γ⊢𝜎′2≡𝜎2 𝗌𝗂𝗀Γ⊢𝜎1⪯𝗌𝜎2Sig−Convert, and these variance rules: Γ,𝑢::𝜅1⊢𝜏1<:𝜏2Γ⊢𝜅1⪯𝗄𝜅2Γ⊢𝖡(𝑢::𝜅1;𝜏1)⪯𝗌𝖡(𝑢::𝜅2;𝜏2)B−Match, Γ⊢𝜎1⪯𝗌𝜎′1Γ,𝑋:𝜎1⊢𝜎2⪯𝗌𝜎′2Γ⊢𝖲𝗂𝗀𝗆𝖺(𝑋:𝜎1).𝜎2⪯𝗌𝖲𝗂𝗀𝗆𝖺(𝑋:𝜎′1).𝜎′2Sigma−Match, Γ⊢𝜎′1⪯𝗌𝜎1Γ,𝑋:𝜎′1⊢𝜎2⪯𝗌𝜎′2Γ⊢𝖯𝗂(𝑋:𝜎1).𝜎2⪯𝗌𝖯𝗂(𝑋:𝜎′1).𝜎′2Pi−Match. In Sigma-Match, self-recognition of the first component propagates its singleton equations while the second components are compared. This is the sharing mechanism.
Write 𝗆𝖺𝗍𝖼𝗁Γ(𝜎1,𝜎2)=D when the following partial procedure returns a declarative matching derivation D. First alpha-normalize binders and normalize every constructor with 𝖾𝗑𝗉𝖺𝗇𝖽Γ.
For two basic signatures, decide 𝜅1 ⪯𝗄𝜅2 and, under 𝑢 ::𝜅1, decide 𝜏1 ≡𝜏2 𝗍𝗒𝗉𝖾. On success return B-Match.
For two hierarchy signatures, recursively match their first components. Then extend the context by 𝑋 :𝜎1, so the source component’s singleton facts are available, normalize both continuations, and recursively match them. On success return Sigma-Match.
For two functor signatures, recursively match the target domain against the source domain. Under 𝑋 :𝜎′1, recursively match the source codomain against the target codomain, and return Pi-Match.
Signatures with different outer constructors do not match.
Here 𝜏1 <:𝜏2 is the conversion test fixed in the core calculus. The output derivation records every normalization equality and the structural rule used at each node.
Referenced from 3 locations
The procedure of definition 14.6 terminates. If it returns D, then D ::Γ ⊢𝜎1 ⪯𝗌𝜎2.
Referenced from 3 locations
Proof of Proposition 14.7 — Termination and soundness of algorithmic matching
Proof. Order calls by the sum of the numbers of 𝖡, 𝖲𝗂𝗀𝗆𝖺, and 𝖯𝗂 nodes in the two inputs. Every recursive call compares proper component signatures, so this measure decreases. Constructor normalization and all leaf decisions terminate by proposition 14.1.
For soundness, induct on the returned trace. A basic trace contains exactly the two premises of B-Match. A hierarchy trace contains the first component derivation and the continuation derivation under 𝑋 :𝜎1, exactly as required by Sigma-Match. A functor trace records the reversed domain derivation and covariant codomain derivation required by Pi-Match. The normalization records are constructor and signature conversions, so Sig-Convert transports the structural derivation back to the input signatures. ◻
For a fixed element constructor 𝑎 ::𝖳𝗒, let 𝖲𝖤𝖳[𝑎]:=𝖡(𝑟::𝖳𝗒;𝑟×(𝑎→𝑟→𝑟)×(𝑎→𝑟→𝟐)). The shared hierarchy signature is 𝖮𝖱𝖣𝖲𝖤𝖳:=𝖲𝗂𝗀𝗆𝖺(𝑋:𝖮𝖱𝖣𝖤𝖱𝖤𝖣).𝖲𝖤𝖳[𝑋.𝑠]. Suppose 𝑝𝑂 :𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ] and 𝑝𝑆 :𝖲𝖤𝖳[ℕ] are projectible values. Their explicit pair is first checked at the nondependent signature 𝖲𝗂𝗀𝗆𝖺(:𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ]).𝖲𝖤𝖳[ℕ]. Matching the first component to 𝑋 :𝖮𝖱𝖣𝖤𝖱𝖤𝖣 makes 𝑋.𝑠 ≡ℕ while the second is checked, so the pair also matches 𝖮𝖱𝖣𝖲𝖤𝖳. The equality was transported by the hierarchy; it was not reconstructed from dynamic operations.
The algorithmic trace has three nodes. At the root, the two signatures are 𝖲𝗂𝗀𝗆𝖺-signatures. Their first components match by B-Match: 𝖲𝗂𝗇𝗀(ℕ) ⪯𝗄𝖳𝗒, and expanding the dynamic comparison type replaces its carrier by ℕ. For the second recursive call the context is 𝑋 :𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ], whose static projection contributes the manifest equation 𝑋.𝑠 ↦ℕ. Expansion therefore changes 𝖲𝖤𝖳[𝑋.𝑠] to 𝖲𝖤𝖳[ℕ], and the basic-signature comparison succeeds reflexively. The returned root is Sigma-Match with exactly these two subderivations.
Here is the complete derivation in the selected rules. Let 𝜏𝑆(𝑎,𝑟):=𝑟 ×(𝑎 →𝑟 →𝑟) ×(𝑎 →𝑟 →𝟐), and suppose 𝑣𝑆 :𝜏𝑆(ℕ,𝖫𝗂𝗌𝗍 ℕ). Rule Basic, followed by B-Match and Sub, gives 𝖫𝗂𝗌𝗍ℕ::𝖳𝗒𝑣𝑆:𝜏𝑆(ℕ,𝖫𝗂𝗌𝗍ℕ)⟨𝖫𝗂𝗌𝗍ℕ;𝑣𝑆⟩:𝖡(𝑟::𝖲𝗂𝗇𝗀(𝖫𝗂𝗌𝗍ℕ);𝜏𝑆(ℕ,𝑟))Basic𝖡(𝑟::𝖲𝗂𝗇𝗀(𝖫𝗂𝗌𝗍ℕ);𝜏𝑆(ℕ,𝑟))⪯𝗌𝖲𝖤𝖳[ℕ]𝑝𝑆:𝖲𝖤𝖳[ℕ]Sub. Together with 𝑝𝑂 :𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ], Hierarchy yields 𝑝𝑂:𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ]𝑝𝑆:𝖲𝖤𝖳[ℕ]⟨𝑝𝑂;𝑝𝑆⟩:𝖲𝗂𝗀𝗆𝖺(:𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ]).𝖲𝖤𝖳[ℕ]Hierarchy. Finally, under 𝑋 :𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ], rule Static and the singleton elimination give 𝑋.𝑠 ≡ℕ. Therefore 𝖲𝖤𝖳[ℕ] ≡𝖲𝖤𝖳[𝑋.𝑠], and the final matching and subsumption are ⟨𝑝𝑂;𝑝𝑆⟩:𝖲𝗂𝗀𝗆𝖺(:𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ]).𝖲𝖤𝖳[ℕ]𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ]⪯𝗌𝖮𝖱𝖣𝖤𝖱𝖤𝖣𝑋:𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ]⊢𝖲𝖤𝖳[ℕ]⪯𝗌𝖲𝖤𝖳[𝑋.𝑠]𝖲𝗂𝗀𝗆𝖺(:𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ]).𝖲𝖤𝖳[ℕ]⪯𝗌𝖮𝖱𝖣𝖲𝖤𝖳Sigma−Match⟨𝑝𝑂;𝑝𝑆⟩:𝖮𝖱𝖣𝖲𝖤𝖳Sub.
Second projection is deliberately restricted. A phrase 𝑀.2 may be typed directly only after the range signature is nondependent. For the pair above, matching first specializes 𝖲𝖤𝖳[𝑋.𝑠] to 𝖲𝖤𝖳[ℕ], and only then is the projection formed. This order prevents a local path 𝑋 from escaping.
Suppose Γ⊢𝑀:𝖲𝗂𝗀𝗆𝖺(𝑋:𝖮𝖱𝖣𝖤𝖱𝖤𝖣).𝖲𝖤𝖳[𝑋.𝑠],Γ⊢𝑀 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾,Γ⊢𝑀.1:𝖮𝖱𝖣𝖤𝖱𝖤𝖣[𝑐]. Then the second projection has signature 𝖲𝖤𝖳[𝑐]. Its insert operation therefore accepts exactly the element type recognized at 𝑀.1.𝑠.
Referenced from 4 locations
Proof of Proposition 12.4 — Sharing preservation
Proof. Rule B-Match gives 𝖮𝖱𝖣𝖤𝖱𝖤𝖣[𝑐] ⪯𝗌𝖮𝖱𝖣𝖤𝖱𝖤𝖣: its static premise is 𝖲𝗂𝗇𝗀(𝑐) ⪯𝗄𝖳𝗒, and its dynamic premise is reflexive after singleton elimination. Rule Self-First, using this match and the last premise of the proposition, derives Γ⊢𝑀:𝖲𝗂𝗀𝗆𝖺(𝑋:𝖮𝖱𝖣𝖤𝖱𝖤𝖣[𝑐]).𝖲𝖤𝖳[𝑋.𝑠]. Under 𝑋 :𝖮𝖱𝖣𝖤𝖱𝖤𝖣[𝑐], rules Static and Self give 𝑋.𝑠 ::𝖲𝗂𝗇𝗀(𝑐), hence 𝑋.𝑠 ≡𝑐 ::𝖳𝗒. By Sigma-Eq, 𝖲𝗂𝗀𝗆𝖺(𝑋:𝖮𝖱𝖣𝖤𝖱𝖤𝖣[𝑐]).𝖲𝖤𝖳[𝑋.𝑠]≡𝖲𝗂𝗀𝗆𝖺(:𝖮𝖱𝖣𝖤𝖱𝖤𝖣[𝑐]).𝖲𝖤𝖳[𝑐]. Rule Second now derives Γ ⊢𝑀.2 :𝖲𝖤𝖳[𝑐]. Its dynamic product contains 𝑐 →𝑟 →𝑟, which is the stated insert type. ◻
★☆☆ Let 𝑝𝑂:𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ]and𝑝𝐵:𝖲𝖤𝖳[𝟐]. Attempt to match ⟨𝑝𝑂;𝑝𝐵⟩ against 𝖮𝖱𝖣𝖲𝖤𝖳. Write the two singleton equations forced while checking the second component and identify the unsatisfied constructor-equivalence judgment.
Referenced from 3 locations
Generative functors
Rule Apply requires a nondependent result. A dependent functor is used by first matching its projectible argument to a manifest signature and reducing the result dependency.
Assume the core list constructor and its usual empty, insertion, and membership operations. In a context 𝑋 :𝖮𝖱𝖣𝖤𝖱𝖤𝖣, let 𝗆𝖾𝗆𝖻𝖾𝗋𝑋 be list membership computed with the comparison in 𝑋.𝑑, and define 𝖫𝗂𝗌𝗍𝖲𝖾𝗍𝑋:=⟨𝖫𝗂𝗌𝗍𝑋.𝑠;⟨𝗇𝗂𝗅,𝖼𝗈𝗇𝗌,𝗆𝖾𝗆𝖻𝖾𝗋𝑋⟩⟩,𝖲𝖾𝗍𝖥𝗇:=𝜆𝑋:𝖮𝖱𝖣𝖤𝖱𝖤𝖣.𝖫𝗂𝗌𝗍𝖲𝖾𝗍𝑋↾𝖲𝖤𝖳[𝑋.𝑠]. The three dynamic fields have types 𝖫𝗂𝗌𝗍 𝑋.𝑠, 𝑋.𝑠 →𝖫𝗂𝗌𝗍 𝑋.𝑠 →𝖫𝗂𝗌𝗍 𝑋.𝑠, and 𝑋.𝑠 →𝖫𝗂𝗌𝗍 𝑋.𝑠 →𝟐. Hence Basic, Seal, and Functor derive 𝖲𝖾𝗍𝖥𝗇:𝖯𝗂(𝑋:𝖮𝖱𝖣𝖤𝖱𝖤𝖣).𝖲𝖤𝖳[𝑋.𝑠]. Given 𝑝𝑂 :𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ], Pi-Match compares the domain contravariantly and specializes the result under the manifest argument; Sub then gives 𝖲𝖾𝗍𝖥𝗇:𝖯𝗂(𝑋:𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ]).𝖲𝖤𝖳[ℕ]. Now Apply derives 𝖲𝖾𝗍𝖥𝗇(𝑝𝑂) :𝖲𝖤𝖳[ℕ].
The application is not projectible. If the body creates an abstract representation, each annotated binding (𝗅𝖾𝗍 𝑆𝑖=𝖲𝖾𝗍𝖥𝗇(𝑝𝑂)↾𝖲𝖤𝖳[ℕ] 𝗂𝗇 𝑀𝑖):𝜎 introduces a fresh abstract representation path for 𝑆𝑖.𝑠. Even with the same functor and argument, 𝑆1.𝑠 and 𝑆2.𝑠 are unrelated unless an outer hierarchy explicitly shares them. This is the principal generative discipline.
★★☆ Assume 𝖲𝖾𝗍𝖥𝗇 represents sets by lists but seals its result at 𝖲𝖤𝖳[𝑋.𝑠]. Bind two applications at the same manifest argument. Determine which element types and representation types are equal across the two results. Construct a hierarchy signature that shares the element type without sharing the representation type.
Referenced from 3 locations
Elaboration of the matched fragment
Dependent paths must be resolved before ordinary existential packages can be a target. We therefore state elaboration only for signatures whose hierarchy and functor dependencies have already been eliminated by matching.
The module reduction relation ⟶D is call by value. Its operational module values, written 𝑉, are 𝑉::=⟨𝑐;𝑣⟩∣⟨𝑉1;𝑉2⟩∣𝜆𝑋:𝜎.𝑀. Unlike the open module-value judgment, this grammar has no variable case. The let and application contractions below use only this operational grammar. In particular a seal is not a value, matching PFPL’s abstraction boundary.
Capture-avoiding substitution must also preserve the path premises carried by a typing derivation. Write 𝗁𝗌𝗎𝖻𝗌𝗍(𝑀;𝑉;𝑋) for hereditary module substitution: first substitute 𝑉 for 𝑋, then contract only hierarchy projections whose receiver was exposed by that substitution. On derivations, a substituted basic value rebuilds Basic; a substituted hierarchy value rebuilds Hierarchy, recursing into the component selected by a former Self-First, Self-Second, or P-Projection premise. It performs no seal, functor, or arbitrary dynamic reduction. This restricted normalization is structural on the original projection spine, so it terminates and agrees with ordinary substitution when no projectible occurrence of 𝑋 is selected.
Referenced from 2 locations
The sorted root contractions are exactly 𝑉↾𝜎⟶D𝑉,(⟨𝑐;𝑣⟩).𝑑⟶𝑣,⟨𝑉1;𝑉2⟩.1⟶𝑉1,⟨𝑉1;𝑉2⟩.2⟶𝑉2,(𝗅𝖾𝗍 𝑋=𝑉 𝗂𝗇 𝑀):𝜎⟶𝗁𝗌𝗎𝖻𝗌𝗍(𝑀;𝑉;𝑋),(𝜆𝑋:𝜎.𝑀)(𝑉)⟶𝗁𝗌𝗎𝖻𝗌𝗍(𝑀;𝑉;𝑋). The seal step is administrative erasure at runtime. Its label retains the matching derivation D ::𝜎0 ⪯𝗌𝜎: the reduct is typed at 𝜎 by Sub, so erasure does not restore a hidden static equation. Static projection computes by constructor equivalence, (⟨𝑐;𝑣⟩).𝑠 ≡𝑐; hierarchy-path projections compute in the same way. They are not dynamic steps.
Module evaluation contexts are module-sorted: E𝑀::=[]∣E𝑀↾𝜎∣(𝗅𝖾𝗍 𝑋=E𝑀 𝗂𝗇 𝑀):𝜎∣⟨E𝑀;𝑀⟩∣⟨𝑉;E𝑀⟩∣E𝑀.1∣E𝑀.2∣E𝑀(𝑀)∣𝑉(E𝑀). Ordinary expression contexts are those of the core. Two cross-sort rules evaluate a module inside a dynamic projection and an expression inside a basic structure. Compatible closure is therefore the following complete family: 𝑅⟶𝑅′E𝑀[𝑅]⟶E𝑀[𝑅′]M−Context. 𝑀⟶𝑀′𝑀.𝑑⟶𝑀′.𝑑D−Context. 𝑒⟶𝑒′⟨𝑐;𝑒⟩⟶⟨𝑐;𝑒′⟩Basic−Context. No reduction crosses a functor body or the body of an annotated let before its binder is discharged. Equations (12.1)–(12.5) and the three context rules are the entire selected module dynamics.
The rules compute rather than merely classify. Let 𝜎 =𝖡(𝑢 ::𝜅;𝜏), let 𝑉 =⟨𝑐;𝑣⟩ match 𝜎, and let 𝑊 be a module value of a functor’s domain. Then (𝗅𝖾𝗍 𝑋=(𝜆𝑌:𝜎0.𝑉)(𝑊)↾𝜎 𝗂𝗇 𝑋.𝑑):𝜏(12.5)⟶(𝗅𝖾𝗍 𝑋=𝑉↾𝜎 𝗂𝗇 𝑋.𝑑):𝜏(12.1)⟶(𝗅𝖾𝗍 𝑋=𝑉 𝗂𝗇 𝑋.𝑑):𝜏(12.4)⟶𝑉.𝑑(12.2)⟶𝑣. By contrast, a functor abstraction is a value, so no rule reduces inside its body before application.
A naive dependent clause would require 𝖯𝖺𝖼𝗄(𝖲𝗂𝗀𝗆𝖺(𝑋:𝜎1).𝜎2)?=𝖯𝖺𝖼𝗄(𝜎1)×𝖯𝖺𝖼𝗄(𝜎2), but 𝑋 is free in the right-hand occurrence of 𝖯𝖺𝖼𝗄(𝜎2) and has no target binder. Resolving that path dependency before translation is therefore necessary. A signature is closed-result when every 𝖲𝗂𝗀𝗆𝖺- or 𝖯𝗂-range is independent of its bound module variable. Define 𝖯𝖺𝖼𝗄(𝖡(𝑢::𝜅;𝜏)):=∃𝑢::𝜅.𝜏,𝖯𝖺𝖼𝗄(𝖲𝗂𝗀𝗆𝖺(:𝜎1).𝜎2):=𝖯𝖺𝖼𝗄(𝜎1)×𝖯𝖺𝖼𝗄(𝜎2),𝖯𝖺𝖼𝗄(𝖯𝗂(:𝜎1).𝜎2):=𝖯𝖺𝖼𝗄(𝜎1)→𝖯𝖺𝖼𝗄(𝜎2). The target is the pure call-by-value existential core of chapter 10, extended by the singleton kinds, subkinding, and constructor conversion displayed in section 12.1, together with call-by-value let, products, ℕ, 𝟐, 𝟏 with ⋆, and 𝖫𝗂𝗌𝗍. These ordinary data formers use their formation, introduction, elimination, congruence, and beta rules from the preceding core chapters. Package and function constructors form values at value arguments; ordinary target type safety is the earlier package proof applied to these conservative static and data extensions.
Referenced from 4 locations
Let D ::𝜎1 ⪯𝗌𝜎2 be a matching derivation between closed-result signatures. Its target coercion 𝗆𝖼𝗈𝖾D :𝖯𝖺𝖼𝗄(𝜎1) →𝖯𝖺𝖼𝗄(𝜎2) is defined by the last rule of D. For B-Match, 𝗆𝖼𝗈𝖾D(𝑧):=𝗎𝗇𝗉𝖺𝖼𝗄[𝑢,𝑥]=𝑧 𝗂𝗇 𝗉𝖺𝖼𝗄[𝑢,𝗆𝖼𝗈𝖾𝜏(𝑥)], where 𝗆𝖼𝗈𝖾𝜏 is the coercion named by the displayed core subtyping premise; kind weakening checks the same witness at the target kind. For the closed-result hierarchy and functor rules, 𝗆𝖼𝗈𝖾D(𝑧):=⟨𝗆𝖼𝗈𝖾D1(𝜋1𝑧),𝗆𝖼𝗈𝖾D2(𝜋2𝑧)⟩,𝗆𝖼𝗈𝖾D(𝑓):=𝜆𝑥.𝗆𝖼𝗈𝖾D2(𝑓(𝗆𝖼𝗈𝖾D1(𝑥))). The functor domain coercion is reversed because Pi-Match is contravariant. Reflexivity gives the identity, transitivity composes coercions, and signature equivalence transports without computation. This definition is deliberately absent for unresolved dependent ranges.
Referenced from 3 locations
A module typing derivation E ::Γ ⊢𝑀 :𝜎 is elaboration-admissible when every signature translated to a target package has a closed result: no result type mentions a module path eliminated by the translation. Require this invariant recursively of contexts, premises, and conclusions. In particular, Dynamic, Second, and Apply must have nondependent result signatures.
Referenced from 3 locations
Package opening is part of the translation environment. For a closed-result signature 𝜎, write 𝖮𝗉𝖾𝗇𝜎(𝑧,𝑋;𝑞) for the target term defined by these three clauses: 𝖮𝗉𝖾𝗇𝖡(𝑢::𝜅;𝜏)(𝑧,𝑋;𝑞):=𝗎𝗇𝗉𝖺𝖼𝗄[𝑢𝑋,𝑥𝑋]=𝑧 𝗂𝗇 𝑞,𝖮𝗉𝖾𝗇𝖲𝗂𝗀𝗆𝖺(:𝜎1).𝜎2(𝑧,𝑋;𝑞):=𝖮𝗉𝖾𝗇𝜎1(𝜋1𝑧,𝑋.1;𝖮𝗉𝖾𝗇𝜎2(𝜋2𝑧,𝑋.2;𝑞)),𝖮𝗉𝖾𝗇𝖯𝗂(:𝜎1).𝜎2(𝑧,𝑋;𝑞):=𝗅𝖾𝗍 𝑓𝑋=𝑧 𝗂𝗇 𝑞. The corresponding context operation is distinct from this term former. Write 𝖮𝗉𝖾𝗇𝖢𝗍𝗑𝜌(Γ) for the telescope obtained by translating constructor and expression assumptions pointwise and replacing each module assumption 𝑋 :𝜎 by a fresh package variable 𝑧𝑋 :𝖯𝖺𝖼𝗄(𝜎) followed by the constructor, expression, and functor binders introduced by 𝖮𝗉𝖾𝗇𝜎(𝑧𝑋,𝑋;𝑞). At the same step, extend 𝜌 with 𝑋 ↦𝑧𝑋 and with the static and dynamic component projections named by those binders. Recursion on 𝜎 fixes the telescope order, so 𝖮𝗉𝖾𝗇𝖢𝗍𝗑 is a context operation rather than an abbreviation for a term.
The environment extension 𝜌 ⊕𝜎(𝑋 ↦𝑧), available under the binders introduced by 𝖮𝗉𝖾𝗇𝜎, records 𝑋.𝑠 ↦𝑢𝑋, 𝑋.𝑑 ↦𝑥𝑋, the component projections obtained by applying these clauses recursively through nested signatures, and 𝑋 ↦𝑧 or 𝑓𝑋 when the whole module is used. The result type of 𝑞 may not contain a freshly opened constructor. This is the avoidance premise enforced by the result annotation on Let and by definition 14.12.
For a projectible path 𝑄, let 𝗌𝗍𝖺𝗍𝜌(𝑄) be the target constructor denoted by 𝑄.𝑠. An opened variable is read from 𝜌, an explicit basic path denotes its written constructor, and hierarchy projections select the corresponding component.
Referenced from 2 locations
The whole existential package does not determine its witness judgmentally: opening the same package variable twice introduces two fresh abstract constructors. Self-recognition therefore uses the components already exposed by the projectible path, not a second unpack. For a derivation E ::Γ ⊢𝑄 :𝖡(𝑢 ::𝜅;𝜏), define its projectible view 𝖵𝗂𝖾𝗐𝜌,E(𝑄)=(𝑐𝑄,𝑒𝑄) simultaneously with the derivation-indexed translation below, by recursion on the projectible syntax and after stripping final Sub, Self, Self-First, and Self-Second rules. For an opened variable use the stored entries 𝜌(𝑄.𝑠) and 𝜌(𝑄.𝑑); for ⟨𝑐;𝑒⟩ use 𝑐 and the translation of 𝑒; for a hierarchy projection recurse into the selected component. A stripped Sub inserts the dynamic coercion selected by its matching derivation. Put 𝖲𝖾𝗅𝖿𝖯𝖺𝖼𝗄𝜌,E(𝑄):=𝗉𝖺𝖼𝗄[𝑐𝑄,𝑒𝑄]where (𝑐𝑄,𝑒𝑄)=𝖵𝗂𝖾𝗐𝜌,E(𝑄).
For an elaboration-admissible derivation E, write T𝜌→E(𝑀) for its translation. The derivation index selects the matching coercion and the subderivation at every recursive call. If E𝑖 are the immediate subderivations, the principal clauses are T𝜌→E𝑋(𝑋):=𝜌(𝑋),T𝜌→E(⟨𝑐;𝑒⟩):=𝗉𝖺𝖼𝗄[𝑐,T𝜌→E1(𝑒)],T𝜌→E(𝑀↾𝜎):=𝗆𝖼𝗈𝖾D(T𝜌→E1(𝑀)),T𝜌→E(⟨𝑀1;𝑀2⟩):=⟨T𝜌→E1(𝑀1),T𝜌→E2(𝑀2)⟩. T𝜌→E(𝑀.1):=𝜋1(T𝜌→E1(𝑀)),T𝜌→E(𝑀.2):=𝜋2(T𝜌→E1(𝑀)),T𝜌→E((⟨𝑐;𝑒⟩).𝑑):=T𝜌→E1(𝑒),T𝜌→E(𝑄.𝑑):=𝜌(𝑄.𝑑)(𝑄 𝖺𝗇 𝗈𝗉𝖾𝗇𝖾𝖽 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾 𝗉𝖺𝗍𝗁),T𝜌→E(𝑀.𝑑):=𝗎𝗇𝗉𝖺𝖼𝗄[𝑢,𝑥]=T𝜌→E1(𝑀) 𝗂𝗇 𝑥(𝑢∉FV(𝜏)). For the three binding forms, the clauses are T𝜌→E((𝗅𝖾𝗍 𝑋=𝑀1 𝗂𝗇 𝑀2):𝜎):=𝗅𝖾𝗍 𝑧=T𝜌→E1(𝑀1) 𝗂𝗇𝖮𝗉𝖾𝗇𝜎1(𝑧,𝑋;T𝜌⊕𝜎1(𝑋↦𝑧)→E2(𝑀2)),T𝜌→E(𝜆𝑋:𝜎.𝑀):=𝜆𝑧:𝖯𝖺𝖼𝗄(𝜎).𝖮𝗉𝖾𝗇𝜎(𝑧,𝑋;T𝜌⊕𝜎(𝑋↦𝑧)→E1(𝑀)),T𝜌→E(𝑀1(𝑀2)):=T𝜌→E1(𝑀1)T𝜌→E2(𝑀2). The three self-recognition clauses are T𝜌→E𝖲𝖾𝗅𝖿(𝑄):=𝖲𝖾𝗅𝖿𝖯𝖺𝖼𝗄𝜌,E0(𝑄),T𝜌→E𝖲𝖾𝗅𝖿𝖥𝗂𝗋𝗌𝗍(𝑄):=⟨T𝜌→E1(𝑄.1),𝜋2(T𝜌→E0(𝑄))⟩,T𝜌→E𝖲𝖾𝗅𝖿𝖲𝖾𝖼𝗈𝗇𝖽(𝑄):=⟨𝜋1(T𝜌→E0(𝑄)),T𝜌→E1(𝑄.2)⟩. Here E0 is the premise typing 𝑄, while E1 types the selected component at its refined signature. The latter is retranslated because the displayed matching premise points from the refined signature to the original one; it cannot coerce an already forgotten package in the opposite direction. Projectibility ensures that retranslating 𝑄 does not allocate a fresh generative witness. Elaboration admissibility requires each hierarchy range to be independent of its bound path, so its translation is an ordinary product and the unchanged component retains the required type. Here D is the matching premise of Seal; transparent subsumption has the same coercion clause without adding a source constructor. In the second dynamic-projection clause, Dynamic’s premise says that the result type omits the existential witness, exactly the side condition for existential elimination. In the first clause the package was already opened by the enclosing module binder, so its witness remains in scope. Thus neither clause returns a term whose type contains an escaping existential witness. The view clauses and translation clauses above form one simultaneous recursive definition. Order calls lexicographically by (ℎ(E),|𝑄|), where ℎ is derivation height and |𝑄| is projectible-path size, taken as zero for a translation call without a distinguished path. Stripping a final Sub, Self, Self-First, or Self-Second rule strictly lowers ℎ at the same path. A hierarchy projection and the translation of the expression in an explicit basic path use strict premise derivations; the former also shortens the selected path. Every ordinary translation clause recurs on an immediate premise, and a self-recognition clause calls 𝖵𝗂𝖾𝗐 on its strict premise derivation. Thus each mutual call lowers the displayed measure; no clause presupposes an operation defined later.
Referenced from 2 locations
Let E ::Γ ⊢𝑄 :𝖡(𝑢 ::𝜅;𝜏) be elaboration-admissible, with 𝑄 projectible, and let 𝖵𝗂𝖾𝗐𝜌,E(𝑄) =(𝑐𝑄,𝑒𝑄). In 𝖮𝗉𝖾𝗇𝖢𝗍𝗑𝜌(Γ), 𝑐𝑄::𝜅,𝑐𝑄≡𝗌𝗍𝖺𝗍𝜌(𝑄)::𝜅,𝑒𝑄:𝜏[𝑐𝑄/𝑢]. Consequently 𝖲𝖾𝗅𝖿𝖯𝖺𝖼𝗄𝜌,E(𝑄) has type ∃𝑢 ::𝖲𝗂𝗇𝗀(𝗌𝗍𝖺𝗍𝜌(𝑄)).𝜏.
Referenced from 4 locations
Proof of Lemma 14.15 — Projectible-witness coherence
Proof. Use the recursion defining 𝖵𝗂𝖾𝗐. For an opened variable, all three judgments are entries installed together by 𝜌 ⊕𝜎(𝑋 ↦𝑧). For an explicit basic path they are the premises of Basic. A projection selects the corresponding recursively typed component. A final Sub preserves the static constructor and applies its displayed dynamic coercion; signature conversion transports the three judgments without computation. The three self rules select or reassemble the same recursively computed view. These cases exhaust the projectible grammar and its possible final typing rules.
The conversion 𝑐𝑄 ≡𝗌𝗍𝖺𝗍𝜌(𝑄) lets singleton checking view 𝑐𝑄 at 𝖲𝗂𝗇𝗀(𝗌𝗍𝖺𝗍𝜌(𝑄)). Existential introduction with the already typed 𝑒𝑄 gives the final package judgment. No equality between two independently unpacked witnesses is used. ◻
If E ::Γ ⊢𝑀 :𝜎 is elaboration-admissible, then 𝖮𝗉𝖾𝗇𝖢𝗍𝗑𝜌(Γ)⊢T𝜌→E(𝑀):𝖯𝖺𝖼𝗄(𝜎), where 𝜌 is the path environment built simultaneously with the displayed context telescope. This theorem does not claim an elaboration for an unresolved dependent signature or matching derivation.
Referenced from 8 locations
Proof of Theorem 12.7 — Supported elaboration
Proof. Induct on E. The Var case uses its corresponding opened component. The Basic case is existential introduction, using 𝑐 ::𝜅 and 𝑒 :𝜏[𝑐/𝑢]. Seal and subsumption use the matching coercion defined above. Hierarchy introduction and projection are product introduction and elimination. The projectible-witness lemma gives the Self case. Each hierarchy-self case uses product introduction, with induction hypotheses for the original hierarchy and its refined component.
Functor cases are function introduction and elimination. The term former 𝖮𝗉𝖾𝗇𝜎 places the argument witness around the translated body. Annotated let uses the same opening operation after one target let has evaluated its definition; its annotated result excludes 𝑋, so existential elimination is well scoped. For Dynamic, if 𝜌(𝑋.𝑑) =𝑒, elaboration returns the already opened field 𝑒; otherwise the nondependent result type permits unpacking the module locally. Basic, hierarchy, functor, seal, let, self, static-projection, and dynamic-projection cases exhaust the selected elaboration forms. ◻
If E𝑉 ::Γ ⊢𝑉 :𝜎 is elaboration-admissible and 𝑉 belongs to the operational module-value grammar, then T𝜌→E𝑉(𝑉) ⟶∗𝑊 for some target value 𝑊.
Referenced from 3 locations
Proof of Lemma 14.17 — Operational values elaborate to target values
Proof. Induct on 𝑉. A basic value translates to a package whose payload is a target value by the inherited expression-value lemma. A hierarchy translates componentwise; reduce each component by the induction hypotheses to obtain a pair of values. A functor abstraction translates to a target abstraction. Final matching adds only the terminating package coercions displayed above; their unpack redexes contract once the induction hypothesis has produced the package value. Self-recognition instead repacks the already exposed projectible view and introduces no fresh unpack redex. ◻
Let E𝑉 ::Γ ⊢𝑉 :𝜎1 and E𝑀 ::Γ,𝑋 :𝜎1 ⊢𝑀 :𝜎2 be elaboration-admissible, where 𝑉 is an operational module value from the displayed grammar, not merely a derivation of the open module-value judgment. Alpha-rename their binders apart. The hereditary source substitution construction replaces each Var leaf for 𝑋 by E𝑉, contracts the finite projection spine exposed at a projectibility premise, and rebuilds every other rule recursively. It alpha-renames a let or functor binder before descending and produces an elaboration-admissible derivation E′:=𝗁𝗌𝗎𝖻𝗌𝗍(E𝑀;E𝑉;𝑋). Put 𝜌𝑧:=𝜌 ⊕𝜎1(𝑋 ↦𝑧). Then 𝗅𝖾𝗍 𝑧=T𝜌→E𝑉(𝑉) 𝗂𝗇 𝖮𝗉𝖾𝗇𝜎1(𝑧,𝑋;T𝜌𝑧→E𝑀(𝑀))⟶∗T𝜌→E′(𝗁𝗌𝗎𝖻𝗌𝗍(𝑀;𝑉;𝑋)).
Referenced from 6 locations
Proof of Lemma 14.18 — Derivation substitution
Proof. By lemma 14.17, the translated 𝑉 reaches a target value, so every package opening below reaches its unpack contraction. Induct on E𝑀. If the last rule is Var for 𝑋, the opening clauses expose exactly the static, dynamic, and whole-module components of 𝑉. A different variable is unchanged. The Basic case is the inherited expression-substitution lemma under existential introduction. Seal and subsumption retain their displayed matching derivation, so the induction hypothesis is closed under the same 𝗆𝖼𝗈𝖾D. Hierarchy formation and both projections use product congruence. In a Self case, hereditary substitution either preserves the projectible path or exposes a basic value and rebuilds Basic; the view recursion of lemma 14.15 gives the same static and dynamic components on both sides. For either hierarchy-self rule, an exposed hierarchy value is decomposed, the selected component is rebuilt recursively, and Hierarchy reassembles the result. Thus a functor in an unselected component causes no false projectibility premise. The two Dynamic cases use respectively the installed field and existential beta-reduction. In annotated let and functor abstraction, alpha-renaming prevents capture and the induction hypothesis applies beneath the new opening. Application uses function congruence. This exhausts the module grammar. ◻
Let E ::Γ ⊢𝑃 :𝜎 be elaboration-admissible. Suppose one selected module or cross-sort expression step gives 𝑃 ⟶𝑃′, and let E′ be the reduct derivation obtained by retaining every Sub and self-recognition rule with its matching premises, and by applying the substitution construction of lemma 14.18 at let or application. Then T𝜌→E(𝑃)⟶∗T𝜌→E′(𝑃′). Consequently, if 𝑃 is closed, its target translation is a value or takes a target step; it cannot get stuck at a package, product, or function elimination.
Referenced from 3 locations
Proof of Theorem 12.8 — Simulation and module safety
Proof. The dynamic projection of an explicit basic module takes zero target steps; a hierarchy projection takes one product step. Let and application use lemma 14.18 after the target let or beta step. For the seal root, the reduct is translated through the retained Sub derivation, so both sides contain the same 𝗆𝖼𝗈𝖾D; zero target steps suffice. If E ends in Self, its reduct derivation retains the rule or rebuilds Basic after hereditary substitution. In both cases the induction hypothesis is closed under the projectible view by lemma 14.15. For either hierarchy-self rule, hereditary substitution decomposes an exposed value as in lemma 14.18; product congruence then applies to the original hierarchy and to the retranslated selected component. The three context rules follow by target compatible closure. Target progress gives the final claim after theorem 12.7; preservation retains its package type. This is a target-safety consequence, not a proof of source progress. ◻
★★★ Let 𝑝𝑂 :𝖮𝖱𝖣𝖤𝖱𝖤𝖣[ℕ], and specialize the displayed definition of 𝖲𝖾𝗍𝖥𝗇 at 𝑝𝑂. For the annotated module 𝐿:=(𝗅𝖾𝗍 𝑆=𝖲𝖾𝗍𝖥𝗇(𝑝𝑂) 𝗂𝗇 ⟨𝟐;𝜋2(𝜋2(𝑆.𝑑))0(𝜋1(𝑆.𝑑))⟩):𝖡(::𝖲𝗂𝗇𝗀(𝟐);𝟐), give the source application beta-step, seal step, let step, dynamic projection in 𝐿.𝑑, and the product projections that select the empty set and membership operation. Give the corresponding package translation and reductions, with the source or target rule on every line. Identify the existential-elimination side condition that would fail if the annotated result type mentioned 𝑆.𝑠.
Referenced from 3 locations
Representation independence at one interface
Let 𝖢𝖮𝖴𝖭𝖳𝖤𝖱:=𝖡(𝑡::𝖳𝗒;𝑡×((𝑡→𝑡)×(𝑡→ℕ))). Consider 𝐶𝑁=⟨ℕ;⟨0,𝗌𝗎𝖼𝖼,𝜆𝑛.𝑛⟩⟩,𝐶𝑃=⟨ℕ×𝟏;⟨⟨0,⋆⟩,𝜆𝑝.⟨𝗌𝗎𝖼𝖼(𝗉𝗋1𝑝),𝗉𝗋2𝑝⟩,𝜆𝑝.𝗉𝗋1𝑝⟩⟩. Relate 𝑛 :ℕ to (𝑚, ⋆) :ℕ ×𝟏 exactly when 𝑛 =𝑚. The initial states are related, the step functions preserve this relation, and the read functions return equal naturals.
Define 𝑅(𝑛,⟨𝑚, ⋆⟩) exactly when 𝑛 =𝑚.
Referenced from 2 locations
The three interface obligations are calculations: 𝑅(0,⟨0,⋆⟩),𝑅(𝑛,⟨𝑚,⋆⟩)⟹𝑛=𝑚⟹𝗌𝗎𝖼𝖼(𝑛)=𝗌𝗎𝖼𝖼(𝑚)⟹𝑅(𝗌𝗎𝖼𝖼(𝑛),⟨𝗌𝗎𝖼𝖼(𝑚),⋆⟩),𝑅(𝑛,⟨𝑚,⋆⟩)⟹𝑛=𝑚. Thus initial states are related, steps preserve 𝑅, and reads of related states agree.
A counter client is a term 𝐾 :ℕ in the simply typed target language with products, arrows, unit, Booleans, and naturals, under exactly the context 𝑧:𝑡,𝗌𝗍𝖾𝗉:𝑡→𝑡,𝗋𝖾𝖺𝖽:𝑡→ℕ. The type 𝑡 is abstract: the term contains no constants, equality, or eliminators specialized to 𝑡. The ordinary closed primitives at ℕ, 𝟐, products, and unit preserve equality. Instantiation substitutes one implementation’s state and operations for these variables and thereby produces a closed term.
Referenced from 4 locations
For the abstract-state relation 𝑅, define a relation 𝑉𝐴 on closed values by recursion on client types: 𝑉𝑡:=𝑅,𝑉ℕ:==ℕ,𝑉𝟐:==𝟐,𝑉𝟏:==𝟏,(𝑎1,𝑎2)𝑉𝐴×𝐵(𝑏1,𝑏2)⟺𝑎1𝑉𝐴𝑏1 ∧ 𝑎2𝑉𝐵𝑏2,𝑓𝑉𝐴→𝐵𝑔⟺∀𝑎,𝑏. 𝑎𝑉𝐴𝑏⟹𝑓𝑎𝐶𝐵𝑔𝑏. Here the computation closure is 𝑒𝐶𝐴𝑒′⟺∃𝑣,𝑣′. 𝑒⟶∗𝑣 ∧ 𝑒′⟶∗𝑣′ ∧ 𝑣𝑉𝐴𝑣′. For a client context Ξ, write 𝜌𝑁𝑉Ξ𝜌𝑃 when both environments map variables to closed values and every 𝑥 :𝐴 in Ξ satisfies 𝜌𝑁(𝑥)𝑉𝐴𝜌𝑃(𝑥).
Referenced from 2 locations
If Ξ ⊢𝑒 :𝐴 and 𝜌𝑁𝑉Ξ𝜌𝑃, then 𝑒[𝜌𝑁]𝐶𝐴𝑒[𝜌𝑃].
Referenced from 4 locations
Proof of Lemma 12.10 — Counter fundamental relation
Proof. First record the compatibility calculation for applications. Assume 𝑓𝐶𝐴→𝐵𝑔and𝑎𝐶𝐴𝑏. Evaluate the four terms to 𝑓0,𝑔0,𝑎0,𝑏0. Their value relations and the arrow clause give 𝑓0𝑎0𝐶𝐵𝑔0𝑏0. Call-by-value compatibility prefixes the four evaluation sequences. Products and projections have the corresponding calculation.
Now induct on the typing derivation. Variables reduce in zero steps to the related values from the environment; constants relate to themselves. Pairing and projection use product compatibility. For abstraction, if 𝑎𝑁𝑉𝐴𝑎𝑃, the body induction hypothesis proves 𝑒[𝜌𝑁,𝑥 ↦𝑎𝑁]𝐶𝐵𝑒[𝜌𝑃,𝑥 ↦𝑎𝑃]. Therefore the two abstraction values satisfy the arrow clause; application uses the compatibility calculation above. The three distinguished variables satisfy their clauses by the initial-state, step-preservation, and observation calculations. No other case inspects a value of abstract type 𝑡. ◻
Seal 𝐶𝑁 and 𝐶𝑃 separately at 𝖢𝖮𝖴𝖭𝖳𝖤𝖱. For every counter client 𝐾, the two instantiated closed terms evaluate to the same natural number. Termination is automatic for the simply typed client language fixed in definition 12.9.
Referenced from 4 locations
Proof of Theorem 12.11 — Counter representation independence
Proof. Opening either translated sealed package introduces exactly the abstract state, initial state, step, and read components named in definition 12.9. Existential elimination keeps the witness out of the result type, so a client in that grammar cannot name it. Apply lemma 12.10 to the environments containing the related states and operations. The resulting computations evaluate to 𝑉ℕ-related values, which are the same numeral. Strong normalization of the simply typed client calculus gives the two values, and determinacy of pure evaluation makes them the stated observations. ◻
★★☆ Define a client that steps three times and reads. Evaluate it against both implementations. Then add hypothetical equality at the abstract type and identify the new relation-preservation hypothesis required by lemma 12.10.
Referenced from 3 locations
Principal matching, exactly where it exists
Opaque seals and generative applications erase or create static identity. Principal recognition is therefore about projectible paths, not arbitrary module phrases.
Assume principal core typing: each closed value 𝑣 has a partial principal type 𝗉𝗍𝗒(𝑣), and every other type of 𝑣 is a supertype. A closed constructor 𝑐 has principal kind 𝖲𝗂𝗇𝗀(𝑐). Core typing has inversion modulo equivalence and subsumption.
For a closed projectible path, define 𝗉𝗌𝗂𝗀(⟨𝑐;𝑣⟩):=𝖡(𝑢::𝖲𝗂𝗇𝗀(𝑐);𝗉𝗍𝗒(𝑣)),𝗉𝗌𝗂𝗀(⟨𝑝1;𝑝2⟩):=𝖲𝗂𝗀𝗆𝖺(:𝗉𝗌𝗂𝗀(𝑝1)).𝗉𝗌𝗂𝗀(𝑝2),𝗉𝗌𝗂𝗀(𝑝.1):=𝜎1,if 𝗉𝗌𝗂𝗀(𝑝)=𝖲𝗂𝗀𝗆𝖺(:𝜎1).𝜎2,𝗉𝗌𝗂𝗀(𝑝.2):=𝜎2,if 𝗉𝗌𝗂𝗀(𝑝)=𝖲𝗂𝗀𝗆𝖺(:𝜎1).𝜎2. The definition is partial when 𝗉𝗍𝗒 is undefined, a projection does not select a hierarchy, or the phrase is not projectible. Principal hierarchies are nondependent; dependent sharing is recovered by Sigma-Match from the singleton equations in their components.
Referenced from 7 locations
Let 𝑝 be closed and projectible. A hierarchy position 𝜄 is a finite word over {1,2}; put 𝑝.𝜖 =𝑝 and read the word from left to right as successive projections. At every hierarchy position 𝜄 for which the selected component path 𝑝.𝜄 and its principal signature are defined, if 𝗉𝗌𝗂𝗀(𝑝.𝜄) =𝖡(𝑢 ::𝜅;𝜏), then 𝜅≡𝖲𝗂𝗇𝗀((𝑝.𝜄).𝑠) 𝗄𝗂𝗇𝖽. The empty position 𝜄 =𝜖 gives the basic-path case.
Referenced from 3 locations
Proof of Lemma 14.26 — Static shape of every principal basic component
Proof. Induct on the derivation that computes the principal-signature tree of 𝑝, with the induction claim quantified over every position in that tree. At a basic leaf ⟨𝑐;𝑣⟩, the first clause of 𝗉𝗌𝗂𝗀 and (⟨𝑐;𝑣⟩).𝑠 ≡𝑐 give the equation. At a hierarchy, a position begins with 1 or 2; apply the corresponding component induction hypothesis to the remaining position. A projection selects exactly that subtree, so the same component hypothesis applies without requiring the whole hierarchy to have a basic principal signature. These are all clauses that compute 𝗉𝗌𝗂𝗀. ◻
Suppose Γ ⊢𝜅1 ⪯𝗄𝜅2. Replacing 𝑢 ::𝜅2 by 𝑢 ::𝜅1 in a well-formed continuation of the context preserves constructor kinding, constructor equality, subkinding, signature formation, subsignature matching, and module typing. Likewise, if Γ ⊢𝜎1 ⪯𝗌𝜎2, replacing 𝑋 :𝜎2 by 𝑋 :𝜎1 preserves those judgments.
Referenced from 3 locations
Proof of Lemma 14.27 — Narrowing
Proof. Prove both statements simultaneously by induction on the affected derivation. Variable cases use the assumed subkind or subsignature and one transitivity step. Binder cases first alpha-rename and apply the induction hypothesis to the extended context. Conversion cases use preservation of constructor equality under the narrower context, established by the simultaneous induction; termination of conversion is irrelevant here. Singleton elimination is the only new case beyond the inherited core. In the dependent Sigma-Match case, first narrow the first-component matching premise; then apply the induction hypothesis to the second-component judgment in the narrowed context and rebuild Sigma-Match. The B-Match and Pi-Match cases follow the variance in their premises. The typing rules use the signature half of the simultaneous statement. ◻
Every derivation Γ⊢𝖡(𝑢::𝜅1;𝜏1)⪯𝗌𝖡(𝑢::𝜅2;𝜏2) can be normalized to one B-Match. Every derivation between two 𝖲𝗂𝗀𝗆𝖺-signatures can be normalized to one Sigma-Match, and every derivation between two 𝖯𝗂-signatures to one Pi-Match, with the premises shown in the defining rules.
Referenced from 3 locations
Proof of Lemma 14.28 — Structural matching inversion
Proof. Induct on the matching derivation. Reflexive and conversion steps disappear. In a transitive composite, apply the induction hypotheses and compose the kind, type, or component premises. The bound context in the second component may change at the middle signature; lemma 14.27 transports that premise before transitivity is applied. Shape preservation of the assumed conversion procedure rules out a basic-to-hierarchy or hierarchy-to-functor conversion. The remaining last rule is the corresponding structural rule. ◻
For well-formed signatures in the reduced grammar, Γ⊢𝜎1⪯𝗌𝜎2⟺𝗆𝖺𝗍𝖼𝗁Γ(𝜎1,𝜎2)=D for some returned derivation D. Thus subsignature matching is decidable on this finite fragment.
Referenced from 2 locations
Proof of Corollary 14.29 — Decision and completeness of structural matching
Proof. The reverse implication is proposition 14.7. For the forward implication, apply lemma 14.28. Its normalized last rule is B-Match, Sigma-Match, or Pi-Match; the corresponding algorithm clause invokes the induction hypothesis on exactly its premises. Signature-conversion steps are absorbed by the initial normalization. Induction on the total signature-node count terminates with the basic case. ◻
Let 𝑝 be closed and projectible with 𝗉𝗌𝗂𝗀(𝑝) defined. Every derivation P ::⊢𝑝 :𝜎 factors as the canonical introduction-and-projection derivation ⊢𝑝 :𝗉𝗌𝗂𝗀(𝑝), followed by a matching derivation DP::⊢𝗉𝗌𝗂𝗀(𝑝)⪯𝗌𝜎.
Referenced from 3 locations
Proof of Lemma 14.30 — Typing factorization for projectible paths
Proof. Induct first on the height of P, using the grammar of 𝑝 in the introduction and projection cases. A final Sub or signature-equivalence conversion composes the induction matching with its displayed match by Sig-Trans or Sig-Convert.
Suppose the final rule is Self. Write 𝗉𝗌𝗂𝗀(𝑝) =𝖡(𝑎 ::𝜅0;𝜏0). The induction hypothesis factors the premise typing through 𝖡(𝑎::𝜅0;𝜏0)⪯𝗌𝖡(𝑢::𝜅;𝜏). After self-recognition the required match is 𝖡(𝑎::𝜅0;𝜏0)⪯𝗌𝖡(𝑢::𝖲𝗂𝗇𝗀(𝑝.𝑠);𝜏), whose premises are 𝜅0 ⪯𝗄𝖲𝗂𝗇𝗀(𝑝.𝑠) and 𝜏0 <:𝜏[𝑎/𝑢]. Structural matching inversion proves the second premise under 𝑎 ::𝜅0. By lemma 14.26, 𝜅0 ≡𝖲𝗂𝗇𝗀(𝑝.𝑠), which proves the first. These premises form a B-Match to the conclusion 𝖡(𝑢 ::𝖲𝗂𝗇𝗀(𝑝.𝑠);𝜏).
Suppose the final rule is Self-First. Normalize the induction match for its hierarchy premise. Its second component gives the required match from the nondependent second component of 𝗉𝗌𝗂𝗀(𝑝) to 𝜎2. The induction hypothesis for the premise 𝑝.1 :𝜎′1 gives 𝗉𝗌𝗂𝗀(𝑝.1) ⪯𝗌𝜎′1. These two premises combine by Sigma-Match. The displayed 𝜎′1 ⪯𝗌𝜎1 premise of Self-First justifies checking the reused range 𝜎2 under its refined binder. The Self-Second case is symmetric: its original hierarchy match proves the first-component premise, and the induction hypothesis for 𝑝.2 :𝜎′2 proves the refined second-component premise; then apply Sigma-Match.
The remaining last rules follow the path grammar. For 𝑝 =⟨𝑐;𝑣⟩, inversion leaves Basic. Core factorization gives 𝖲𝗂𝗇𝗀(𝑐) ⪯𝗄𝜅 and 𝗉𝗍𝗒(𝑣) <:𝜏[𝑐/𝑢]; singleton substitution and B-Match finish. For 𝑝 =⟨𝑝1;𝑝2⟩, inversion leaves Hierarchy, and the component induction hypotheses combine by Sigma-Match. For 𝑝 =𝑞.𝑖, inversion leaves First or Second; normalize the induction match for 𝑞 and select its corresponding component premise. A closed derivation cannot end in Var, and no other typing rule concludes a projectible phrase. ◻
Let 𝑝 be closed and projectible, with 𝗉𝗌𝗂𝗀(𝑝) defined. Then ⊢𝑝 :𝗉𝗌𝗂𝗀(𝑝). For every ⊢𝑝 :𝜎, ⊢𝗉𝗌𝗂𝗀(𝑝)⪯𝗌𝜎. If ⊢𝑝 :𝜎′ and every typing ⊢𝑝 :𝜎 induces ⊢𝜎′ ⪯𝗌𝜎, then ⊢𝗉𝗌𝗂𝗀(𝑝)⪯𝗌𝜎′and⊢𝜎′⪯𝗌𝗉𝗌𝗂𝗀(𝑝). Thus the least signature is unique up to mutual matching. We do not identify mutually matching signatures by judgmental equivalence. No conclusion is claimed for seals, lets, functors, or applications.
Referenced from 6 locations
Proof of Theorem 12.13 — Principal matching for closed projectible values
Proof. The canonical derivation and the displayed match are lemma 14.30. If 𝜎′ has the same universal property, then 𝑝 :𝜎′ gives 𝗉𝗌𝗂𝗀(𝑝) ⪯𝗌𝜎′. Applying the property of 𝜎′ to the canonical typing 𝑝 :𝗉𝗌𝗂𝗀(𝑝) gives the reverse match. No antisymmetry principle is among the selected rules, so mutual matching is the strongest conclusion. ◻
★★☆ Compute 𝗉𝗌𝗂𝗀(𝖭𝖺𝗍𝖮𝗋𝖽𝖾𝗋0) and the principal signature of its pair with a list-based 𝖲𝖤𝖳[ℕ]. Explain which clause of definition 12.12 fails for its opaque seal and for 𝖲𝖾𝗍𝖥𝗇(𝖭𝖺𝗍𝖮𝗋𝖽𝖾𝗋0). Do not look through either boundary. If you propose another least signature for either projectible example, prove both matching directions; do not infer judgmental equivalence.
Referenced from 3 locations
Proof-relevant phase distinction: a backward comparison
The reduced calculus keeps static constructors and dynamic terms in one judgment but restricts dependency to projectible paths. Sterling and Harper instead make the phase boundary an internal proposition, written 𝖻𝗌𝗍: under that assumption dynamic inhabitants of a fixed type are identified, while type and signature components retain their static information. A static-extent signature then classifies modules whose restriction under 𝖻𝗌𝗍 agrees with a specified module. This can constrain a whole nested structure, not only one type projection [SH21].
Here is one concrete nested family on which the distinction matters. This is comparison notation for ModTT, not an extension of the grammar in section 12.1. It uses ModTT’s dependent products over dynamic signatures, not an assumed object-language function type [SH21]. For a closed type 𝑇, put 𝜎(𝑇):=𝖲𝗂𝗀𝗆𝖺(𝑋:𝗍𝗒𝗉𝖾).𝖲𝗂𝗀𝗆𝖺(𝗉𝖺𝖼𝗄:𝖯𝗂(:⟨𝑋⟩).⟨𝑇⟩).𝖯𝗂(:⟨𝑇⟩).⟨𝑋⟩,𝜏(𝑇):=𝖲𝗂𝗀𝗆𝖺(𝑋:𝗍𝗒𝗉𝖾).𝖯𝗂(:⟨𝑇⟩).⟨𝑇⟩. The angle brackets classify dynamic values at the displayed type from the object language, and 𝖯𝗂 classifies a module functor. Thus a value of 𝜎(𝑇) is a nested module 𝑈=[𝑋,[𝗉𝖺𝖼𝗄,𝗎𝗇𝗉𝖺𝖼𝗄]], whose outer static component is 𝑋 and whose inner structure contains the two dynamic maps. Define the closed module functor 𝑉(𝑇,𝑈):=[𝑋,𝜆𝑧:⟨𝑇⟩.𝗉𝖺𝖼𝗄(𝗎𝗇𝗉𝖺𝖼𝗄𝑧)]:𝜏(𝑇). The result preserves the input’s static type component and computes its dynamic round trip.
Fix closed types 𝑇0,𝑇1, modules 𝑈𝑖 =[𝑋𝑖,[𝗉𝖺𝖼𝗄𝑖,𝗎𝗇𝗉𝖺𝖼𝗄𝑖]] :𝜎(𝑇𝑖), and a proof-relevant relation ̃𝑇(𝑡0,𝑡1), an 𝛼-small set of witnesses rather than a truth value, indexed by pairs of closed dynamic values 𝑡𝑖 :𝑇𝑖. An input relation witness consists of an 𝛼-small family of sets ̃𝑋(𝑥0,𝑥1) and maps 𝑤𝗉𝖺𝖼𝗄:̃𝑋(𝑥0,𝑥1)→̃𝑇(𝗉𝖺𝖼𝗄0𝑥0,𝗉𝖺𝖼𝗄1𝑥1),𝑤𝗎𝗇𝗉𝖺𝖼𝗄:̃𝑇(𝑡0,𝑡1)→̃𝑋(𝗎𝗇𝗉𝖺𝖼𝗄0𝑡0,𝗎𝗇𝗉𝖺𝖼𝗄1𝑡1). The nested output witness is calculated, not merely asserted: 𝑤𝗋𝗈𝗎𝗇𝖽(𝑟):=𝑤𝗉𝖺𝖼𝗄(𝑤𝗎𝗇𝗉𝖺𝖼𝗄(𝑟)),𝑤𝗋𝗈𝗎𝗇𝖽(𝑟):̃𝑇(𝗉𝖺𝖼𝗄0(𝗎𝗇𝗉𝖺𝖼𝗄0𝑡0),𝗉𝖺𝖼𝗄1(𝗎𝗇𝗉𝖺𝖼𝗄1𝑡1)). If a fiber of ̃𝑇 or ̃𝑋 has two inhabitants, the construction retains which witness was supplied. Replacing each fiber by a mere proposition would erase that distinction.
The phase sensitivity appears in the two components of this calculation. The map on static components sends the witness family ̃𝑋 for the input type components to the same family for the output type components. The dynamic map sends each witness 𝑟 to 𝑤𝗋𝗈𝗎𝗇𝖽(𝑟). Under 𝖻𝗌𝗍, the dynamic maps are identified and only the tracked static component remains observable. Outside that open phase, the dynamic witness transformation is retained.
Let 𝜎 and 𝜏 be closed signature families of type 𝖵𝖺𝗅(𝗍𝗒𝗉𝖾)→𝖲𝗂𝗀. Let 𝑉 :∏𝑇:𝗍𝗒𝗉𝖾𝜎(𝑇) →𝜏(𝑇) be a closed module functor. For closed 𝑇𝑖 :𝖵𝖺𝗅(𝗍𝗒𝗉𝖾), let 𝑈𝑖 :𝜎(𝑇𝑖) be closed inputs. For every family of 𝛼-small sets ̃𝑇 indexed by pairs of closed values of 𝑇0 and 𝑇1, there is a function of phase-separated sets [[𝜎]](̃𝑇)[𝑈0,𝑈1]⟶[[𝜏]](̃𝑇)[𝑉(𝑇0,𝑈0),𝑉(𝑇1,𝑈1)], tracked by a function between the static components.
Referenced from 5 locations
Proof of Theorem 14.32 — Phase-sensitive transport—imported
Proof. The displayed function of phase-separated sets is Sterling and Harper’s generalized abstraction theorem [SH21]. Unfolding the dependent-sum and dependent-product relational actions specializes its dynamic action to 𝑤𝗋𝗈𝗎𝗇𝖽, while its static action preserves ̃𝑋. The model construction and fundamental theorem that justify the general transport are imported; the two-line calculation is local. Neither is a consequence of principal matching in MLMod0. ◻
★★☆ For the nested modules above, suppose a particular pair (𝑡0,𝑡1) has two distinct witnesses 𝑟1,𝑟2 :̃𝑇(𝑡0,𝑡1). Calculate the two output witnesses. State what remains under 𝖻𝗌𝗍, what is erased by replacing the relation families with propositions, and why theorem 12.11 is not an instance of theorem 14.32 as presented in this chapter.
Referenced from 3 locations
This comparison adds neither ModTT nor its model theory to the principal calculus. In particular, its generalized abstraction theorem does not transfer to Standard ML, the reduced matching judgment, applicative functors, modular implicits, or separate compilation. The local representation theorem above remains proof-irrelevant and tied to one counter interface.
When a generated name must leave scope
The annotation on module let is forced by an extrusion problem. The following is Crary’s comparison-language example, not a phrase of the reduced grammar in definition 12.1: that grammar has neither parameterized type components nor datatypes. In the comparison notation, 𝗂𝗇𝗍 𝑢 means postfix application of the unary type component 𝑢 to the type 𝗂𝗇𝗍, and 𝖽𝖺𝗍𝖺𝗍𝗒𝗉𝖾 𝑣 =𝐷 𝗈𝖿 𝑡 introduces a fresh result type 𝑣 with constructor 𝐷 :𝑡 →𝑣. Consider a local generative declaration of 𝑡, followed by a sealed result with 𝗍𝗒𝗉𝖾 ′𝑎𝑢=𝑡,𝖽𝖺𝗍𝖺𝗍𝗒𝗉𝖾 𝑣=𝐷 𝗈𝖿 𝑡,𝑥:𝗂𝗇𝗍𝑢,𝑦:𝖻𝗈𝗈𝗅𝑢. The local name 𝑡 cannot occur in the exported signature. Replacing it by one visible component is not principal. A signature may reveal ′𝑎 𝑢 =𝑣, or retain different relationships among 𝑢, 𝑣, 𝑥, and 𝑦; here 𝑢 is a unary type component and 𝐷 :𝑡 →𝑣 is the datatype constructor. Two ordinary avoiding signatures can retain all four visible fields while assigning the constructor, respectively, 𝐷:𝗂𝗇𝗍𝑢→𝑣and𝐷:𝖻𝗈𝗈𝗅𝑢→𝑣. The first signature types 𝐷 𝑥 but not 𝐷 𝑦; the second types 𝐷 𝑦 but not 𝐷 𝑥. Each therefore exposes a typing fact absent from the other, so neither signature subsigns the other. This incomparability does not by itself exclude a third ordinary signature below both. It does show that the two visible candidates do not determine a unique answer, and the reduced algorithm specified here has no least-avoidance construction. It therefore rejects the phrase or requests an annotation.
Focused avoidance.
Crary extends the signature language with existential signatures. In his calculus an existential signature is the least avoiding supersignature of the dependent body; consequently it lies below every admissible ordinary avoiding answer in the subsignature order. For user modules in synthesis contexts, focused synthesis is sound and complete for the declarative system, with subsignature completeness restricted to synthesis signatures on the left and analysis signatures on the right [Cra21]. Our reduced PFPL calculus has neither existential signatures nor that algorithm. We use the counterexample to justify annotations; no avoidance theorem is imported into theorem 12.13.
★★☆ Give the constructor 𝐷 type 𝗂𝗇𝗍 𝑢 →𝑣 in one ordinary avoiding signature and 𝖻𝗈𝗈𝗅 𝑢 →𝑣 in another, retaining 𝑥 :𝗂𝗇𝗍 𝑢 and 𝑦 :𝖻𝗈𝗈𝗅 𝑢. Check that the first types 𝐷 𝑥 but not 𝐷 𝑦, while the second does the reverse; conclude that neither signature subsumes the other. Then write Crary’s existential answer ∃𝑡. 𝜎(𝑡), where 𝜎(𝑡) contains the unary type component 𝑢 with ′𝖺 𝑢 =𝑡, the datatype 𝑣 with constructor 𝐷 :𝑡 →𝑣, and the fields 𝑥 :𝗂𝗇𝗍 𝑢 and 𝑦 :𝖻𝗈𝗈𝗅 𝑢; identify the existential binder that prevents 𝑡 from escaping. This last signature belongs to Crary’s comparison calculus, not to the reduced grammar of definition 12.1.
Referenced from 3 locations
Generativity and the applicative alternative
Applicative functors.
PFPL’s alternative adds exactly Γ⊢𝐹 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾Γ⊢𝐴 𝗏𝖺𝗅Γ⊢𝐹(𝐴) 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾App−P,Γ⊢𝑄 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾Γ⊢𝑄↾𝜎 𝗉𝗋𝗈𝗃𝖾𝖼𝗍𝗂𝖻𝗅𝖾Seal−P. The first premise asserts that the functor expression is a stable path; the argument need only be a value. The second rule is required because an applicative functor body may seal its result. The price is a new equivalence problem: equality of result paths depends on equality of the functor, argument, and sealed module expressions, which may expose executable code to static comparison. A runtime conditional module therefore has no stable path. This is the complete boundary developed in PFPL Section 45.4, rules 45.7–45.8. We add neither rule to the principal calculus, and none of the generativity, elaboration, or principality results above should be reread applicatively.
The main calculus therefore follows a Standard-ML-style generative policy: each functor application may allocate fresh abstract identities. A common OCaml-style applicative policy instead equates repeated applications 𝐹(𝑃).𝑠 only when the argument is a stable module path 𝑃; generativity can then be requested by applying a unit functor. PFPL’s displayed App-P is broader because its argument premise admits any value. These are three distinct policies, and the companion’s optional applicative mode is an experiment rather than a claim that they coincide.
Generated interfaces and incremental compilation.
Crary’s algorithm writes synthesized interfaces that may contain existential signatures. A downstream unit may compile against such a generated synthesis interface because it occurs in the context, while programmer-written modules and annotations remain existential-free user syntax. The right side of each subsignature query is therefore an analysis signature, exactly the condition used by completeness. This supports the incremental-compilation scenario of [Cra21]; it is not a separate-compilation theorem for Standard ML, MixML, or the reduced calculus of this chapter.
Recursive mixin linking.
MixML unifies structures and signatures as mixins with specified and defined components. Its published system supports recursive, higher-order, and first-class linking, proves soundness and completeness of a three-pass checker, and elaborates to an internal language with single-assignment references, recursive type generativity, and linear definedness [RD13]. This language is richer than our acyclic 𝖲𝗂𝗀𝗆𝖺/𝖯𝗂 fragment. Its theorems are source-gated facts about MixML, not missing cases of theorem 12.7, theorem 12.13.
Cardelli and Wegner’s classification of universal, existential, inclusion, and ad-hoc polymorphism orients the package boundary [CW85]; it does not supply path, sharing, or matching theorems. The load-bearing module rules and projectibility boundary are the reduced PFPL system. The avoidance, applicative, and MixML paragraphs mark separate proof boundaries where a reader might otherwise conflate them.
None of the following problems is a prerequisite for a later chapter.
Suggested first pass.
Begin with exercise 12.9, exercise 12.10. They test the sharing calculation and the exact domain of elaboration. Then implement exercise 12.11; the final problem changes the functor policy explicitly.
★★☆ Design a hierarchy containing an ordered element module, a set module, and a map module. Require both collection key types to share the ordered module’s static component while their representations remain distinct. Give one natural-number match and one near miss rejected by a singleton equation.
Referenced from 4 locations
★★☆ Choose a closed-result hierarchy containing two counters. Elaborate it to packages and products and trace one dynamic projection. Make the second component depend on the first path. Perform the manifest matching required before translation, or explain why the unresolved phrase lies outside theorem 12.7.
Referenced from 4 locations
★★★ Practical project.ml-module-checker Build a Kappa checker and elaborator for finite ordered, set, hierarchy, and functor signatures. Represent singleton identities by nominal stamps. Implement transparent matching, opaque sealing with fresh stamps, hierarchy sharing, and generative application. Print accepted and rejected cases, including a wrong-element set and two applications whose representation stamps differ. Only after the generative corpus passes, add an explicit applicative mode and document the equality it changes. The companion is artifacts/ch14-ml-modules/corpus.kp; its inline output oracle is the acceptance criterion. Record kappa check, kappa test, kappa run, and kappa audit, plus three independently replayed, typechecking semantic mutations. Maintain the invariant that a transparent path preserves its stamp, whereas every opaque seal and every generative functor application allocates a fresh stamp; matching may equate stamps only through an explicit sharing path. The exact successful output is:
PASS transparent preserves Nat
PASS dependent hierarchy sharing accepted
PASS wrong sharing rejected
PASS opaque seals allocate fresh names
PASS generative applications allocate fresh names
PASS applicative repeated application equal
PASS applicative arguments distinguished
PASS applicative functors distinguished
PASS hierarchy elaborates to pair
All 9 ML-modules corpus cases passed.
Referenced from 5 locations
★★☆ Temporarily add App-P and Seal-P. Explain why extending 𝗉𝗌𝗂𝗀 to 𝐹(𝐴) requires an equality test on both 𝐹 and the value 𝐴, rather than the four structural clauses of definition 12.12. Now suppose the syntax is extended by 𝗂𝖿 𝑏 𝗍𝗁𝖾𝗇 𝑀1 𝖾𝗅𝗌𝖾 𝑀2, with runtime Boolean 𝑏. Show that neither new projectibility rule derives a stable path for this conditional, even when both branches have the same signature.
Referenced from 3 locations