Prerequisites. Direct starred prerequisites: Chapter 11. No later core chapter depends on this route.
Suppose a function accepts every nonzero integer and returns a vector whose length is the absolute value of its argument. A client promises a positive integer and needs only a nonempty vector. Ordinary arrow variance compares the two domains and the two codomains independently. It cannot express the second comparison, because the codomains mention the argument: (𝑥:𝖭𝗈𝗇𝖹𝖾𝗋𝗈)→𝖵𝖾𝖼𝐴(|𝑥|),(𝑥:𝖯𝗈𝗌𝗂𝗍𝗂𝗏𝖾)→{𝑣:𝖵𝖾𝖼𝐴(|𝑥|)∣0<𝗅𝖾𝗇𝗀𝗍𝗁(𝑣)}. The codomain comparison must be made after the client domain has replaced the provider domain. Refinement checking adds a logical entailment to that comparison. Gradual typing instead inserts a run-time cast. These are three different mathematical operations; the rules below never exchange their metatheorems.
Kinds, types, and terms are generated by 𝐾::=U∣Π𝑥:𝐴𝐾,𝐴,𝐵::=𝛼∣Π𝑥:𝐴𝐵∣𝜆𝑥:𝐴.𝐵∣𝐴𝑀,𝑀,𝑁::=𝑥∣𝜆𝑥:𝐴.𝑀∣𝑀𝑁. A context contains term declarations 𝑥:𝐴, kind declarations 𝛼:𝐾, and bounded type declarations 𝛼≤𝐴:𝐾. The four judgments are context formation Γ⊢𝖼𝗍𝗑, kinding Γ⊢𝐴:𝐾, typing Γ⊢𝑀:𝐴, and declarative subtyping Γ⊢𝐴<:𝐵. The symbol <: has the declarative role fixed in chapter 8; it does not denote logical implication or gradual precision.
The rules needed for dependent preconditions and postconditions are
Γ⊢𝐴:UΓ,𝑥:𝐴⊢𝐵:U
Γ⊢Π𝑥:𝐴𝐵:U
Π-F
Γ,𝑥:𝐴⊢𝑀:𝐵
Γ⊢𝜆𝑥:𝐴.𝑀:Π𝑥:𝐴𝐵
Π-I
Γ⊢𝐹:Π𝑥:𝐴𝐵Γ⊢𝑁:𝐴
Γ⊢𝐹𝑁:𝐵[𝑁/𝑥]
Π-E
Γ⊢𝐴2<:𝐴1Γ,𝑥:𝐴2⊢𝐵1<:𝐵2
Γ⊢Π𝑥:𝐴1𝐵1<:Π𝑥:𝐴2𝐵2
Π-Sub
The last rule strengthens the client’s precondition from 𝐴1 to 𝐴2 and weakens the provider’s postcondition from 𝐵1 to 𝐵2 in the context where 𝑥:𝐴2. Reversing the first premise would let a client pass an argument outside the provider’s domain.
Let 𝑃<:𝑁 abbreviate the established subtype 𝖯𝗈𝗌𝗂𝗍𝗂𝗏𝖾<:𝖭𝗈𝗇𝖹𝖾𝗋𝗈. Assume that in 𝑥:𝑃 one has 𝖵𝖾𝖼𝐴(|𝑥|)<:{𝑣:𝖵𝖾𝖼𝐴(|𝑥|)∣0<𝗅𝖾𝗇𝗀𝗍𝗁(𝑣)}. One application of Π-Sub derives the client-facing type Π𝑥:𝑁𝖵𝖾𝖼𝐴(|𝑥|)<:Π𝑥:𝑃{𝑣:𝖵𝖾𝖼𝐴(|𝑥|)∣0<𝗅𝖾𝗇𝗀𝗍𝗁(𝑣)}. The occurrence of 𝑥 in both codomains is checked under 𝑥:𝑃; no capture-avoiding renaming or coercion of indices is implicit in the display.
Proof of Lemma 106.2 — Dependent application through subtyping
Proof. By Π-Sub and subsumption, Γ⊢𝐹:Π𝑥:𝐴2𝐵2. Rule Π-E then gives Γ⊢𝐹𝑁:𝐵2[𝑁/𝑥]. The same substitution [𝑁/𝑥] acts on the codomain used in the subtyping premise and on the application result, so the result contains no untransported occurrence of 𝑥. ◻
★★☆ Let 𝑃<:𝑁<:𝐼. For families 𝑄0,𝑄1,𝑄2 assume 𝑥:𝑃⊢𝑄0(𝑥)<:𝑄1(𝑥)<:𝑄2(𝑥). Derive (𝑥:𝐼)→𝑄0(𝑥)<:(𝑥:𝑃)→𝑄2(𝑥). Write both applications of Π-Sub and the transitivity step. Then reverse only the domain premise and give a client argument showing why the resulting rule is unsafe.
The difficult metatheory is not hidden in the four rules. Conversion and transitivity prevent direct inversion of a derivation of Π𝑥:𝐴𝐵<:Π𝑥:𝐴′𝐵′. The source algorithm repairs this by splitting beta reduction: 𝛽2 exposes the head constructor used by algorithmic subtyping, while 𝛽1 handles the remaining conversions.
For the exact Church-style signature of definition 106.1, the following hold.
If Γ⊢𝐴0<:𝐴, replacing 𝑥:𝐴 by 𝑥:𝐴0 in a derivable suffix preserves every judgment in that suffix.
Capture-avoiding substitution preserves kinding, typing, and subtyping.
If Γ⊢𝐽 and 𝐽 contracts by one 𝛽1- or 𝛽2-step to 𝐽′, then Γ⊢𝐽′.
Algorithmic subtyping on 𝛽2-normal, well-kinded types is sound and complete for declarative subtyping. Formation, kind inference, minimal type inference, and subtyping are decidable on well-formed inputs.
Proof. Prove clauses 1–3 simultaneously by induction on derivations. For narrowing, the variable equal to 𝑥 is retyped by the premise 𝐴0<:𝐴 and subsumption; every other variable is unchanged. Under a term or type binder, alpha-rename the binder outside FV(𝐴0)∪dom(Γ) and apply the induction hypothesis to the suffix. Dependent-product subtyping uses the induction hypothesis contravariantly in its domain and under the narrowed client domain in its codomain. Bound selection uses transitivity with the narrowed bound. These are the variable, binder, product, bound, and structural rule families.
For substitution, the variable equal to the substituted variable uses the substituting typing derivation; a different variable is unchanged. Type and term application use both induction hypotheses. Under each dependent binder, choose a name outside the free variables of the substituting expression and apply the induction hypothesis to the renamed body. Kinding and subtyping rebuild their product and bound rules after the same capture-avoiding substitution. Thus substitution preserves all three judgments. A 𝛽1 or 𝛽2 root is then an instance of substitution; congruence cases use the induction hypothesis under the unique reduction context, and conversion cases use transitivity. This proves clause 3.
For clause 4, first 𝛽2-normalize both well-kinded input types. The algorithm compares equal head variables, decomposes dependent products contravariantly in the domain and covariantly in the codomain, and replaces a bounded variable by its declared upper bound only in the designated bound rule. Its recursive measure is the lexicographic pair consisting of the number of unreduced 𝛽2 roots and the sum of the two normal-form sizes; following a declared bound decreases the derivation height of the input’s kinding proof. Hence every recursive call terminates on well-formed inputs.
Soundness is induction on the algorithmic derivation: reflexivity, product, and bound calls rebuild the corresponding declarative rules, while the two normalization phases use clause 3 and conversion. For completeness, induct on a declarative subtyping derivation after eliminating transitivity: commute a transitivity conclusion upward until either its middle type is a head constructor, where the two neighboring rules compose componentwise, or a bounded variable, where the bound rule absorbs it. The measure is the number of transitivity rules below constructor rules, followed by total derivation height. The resulting syntax-directed derivation is exactly an algorithmic one. Formation and kind inference recurse on syntax; minimal typing recurses on the Church annotations; subtyping uses the terminating procedure just proved. Equality of names and the grade-free syntax are decidable, so the four judgments are decidable on well-formed inputs. ◻
Dropping well-formedness from clause 4 invalidates the termination argument: the algorithm removes kinding premises from recursive subtyping calls and relies on an outer proof that the two inputs have kinds. Feeding an arbitrary raw type is therefore outside the decision theorem rather than a negative answer returned by it.
The refinement ledger
Dependent subtyping compares types by rules internal to 𝜆𝑃≤. An SMT-backed refinement checker instead discharges a first-order implication. Fix the difference-logic fragment and its certificate checker from chapter 10. The following calculus, 𝖣𝖱𝖾𝖿, makes the dependency boundary explicit.
Base shapes are 𝖨𝗇𝗍 and 𝖠𝗋𝗋. Refinement types and dependent function types are 𝑅,𝑆::={𝜈:𝐵∣𝜙}∣Π𝑥:𝑅𝑆, where 𝜙 is a finite conjunction of difference constraints 𝑟1−𝑟2≤𝑘. A vertex 𝑟 is 0, an in-scope integer variable, or 𝗅𝖾𝗇(𝑎) for an in-scope array variable 𝑎. In a refinement of 𝖨𝗇𝗍, the distinguished vertex 𝜈 denotes the refined integer; in a refinement of 𝖠𝗋𝗋, 𝗅𝖾𝗇(𝜈) denotes the refined array’s length. Every other free vertex of 𝜙 must be declared earlier in the context. The bare shape 𝐵 abbreviates {𝜈:𝐵∣⊤}.
For integers 𝑚,𝑚𝑖∈ℤ, terms, values, and A-normal call-by-value evaluation contexts are 𝑒::=𝑣∣𝑒𝑣,𝑣::=𝑥∣𝑚∣⟨𝑚1,…,𝑚𝑘⟩∣𝜆𝑥:𝑅.𝑒,𝐸::=[]∣𝐸𝑣. The root and compatible reduction rules are (𝜆𝑥:𝑅.𝑒)𝑣⟶𝑒[𝑣/𝑥]𝑒⟶𝑒′𝐸[𝑒]⟶𝐸[𝑒′]. For a base value 𝑣, the notation 𝜙[𝑣/𝜈] replaces 𝜈 by an integer variable or literal, or replaces 𝗅𝖾𝗇(𝜈) by an array variable’s length or an array literal’s length. For later synthesis, write [𝑚]𝖨𝗇𝗍:={𝜈:𝖨𝗇𝗍∣𝜈−0≤𝑚∧0−𝜈≤−𝑚},[⟨𝑚1,…,𝑚𝑘⟩]𝖠𝗋𝗋:={𝜈:𝖠𝗋𝗋∣𝗅𝖾𝗇(𝜈)−0≤𝑘∧0−𝗅𝖾𝗇(𝜈)≤−𝑘}. These singleton refinements record the integer itself or the array length; both are expressible as two difference constraints.
The three judgments of the refinement ledger are well-formedness Γ⊢𝖣𝖱𝖾𝖿𝑅𝗍𝗒𝗉𝖾, typing Γ⊢𝖣𝖱𝖾𝖿𝑒:𝑅, and refinement subtyping Γ⊢𝖣𝖱𝖾𝖿𝑅<:𝑆. The macro <: denotes this logical-implication role, not 𝜆𝑃≤ subtyping.
Write Φ(Γ) for the conjunction of the base-refinement assumptions in Γ: a declaration 𝑥:{𝜈:𝐵∣𝜃} contributes 𝜃[𝑥/𝜈], while a dependent-function declaration contributes no difference constraint. The core rules are
fv(𝜙)⊆dom(Γ)∪{𝜈}Γ⊢𝗏𝖾𝗋𝗍𝗂𝖼𝖾𝗌(𝜙)𝗐𝖾𝗅𝗅-𝗌𝗈𝗋𝗍𝖾𝖽
Γ⊢𝖣𝖱𝖾𝖿{𝜈:𝐵∣𝜙}𝗍𝗒𝗉𝖾
R-Base-F
Γ⊢𝖣𝖱𝖾𝖿𝑅𝗍𝗒𝗉𝖾Γ,𝑥:𝑅⊢𝖣𝖱𝖾𝖿𝑆𝗍𝗒𝗉𝖾
Γ⊢𝖣𝖱𝖾𝖿Π𝑥:𝑅𝑆𝗍𝗒𝗉𝖾
R-Π-F
Entails(Φ(Γ)∧𝜙1,𝜙2)
Γ⊢𝖣𝖱𝖾𝖿{𝜈:𝐵∣𝜙1}<:{𝜈:𝐵∣𝜙2}
R-Base-Sub
Γ⊢𝖣𝖱𝖾𝖿𝑅2<:𝑅1Γ,𝑥:𝑅2⊢𝖣𝖱𝖾𝖿𝑆1<:𝑆2
Γ⊢𝖣𝖱𝖾𝖿Π𝑥:𝑅1𝑆1<:Π𝑥:𝑅2𝑆2
R-Π-Sub
Here Entails(Ψ,𝜙) is semantic entailment of the difference constraint 𝜙 by Ψ. The checker does not trust an SMT solver’s Boolean answer: each requested atomic consequence is accompanied by a shortest-path certificate, and the small checker recomputes the path weight. If the antecedent is inconsistent, the certificate is instead a negative cycle whose edge weights sum to a negative integer.
Type equality in 𝖣𝖱𝖾𝖿 is alpha-equivalence for binders together with mutual certified implication for base refinements. Thus predicates with different syntax may define equal types, but neither proof irrelevance nor erasure turns an implication in one direction into equality.
The introduction, elimination, and subsumption rules are
Γ(𝑥)=𝑅
Γ⊢𝖣𝖱𝖾𝖿𝑥:𝑅
R-Var
Γ⊢𝖣𝖱𝖾𝖿{𝜈:𝖨𝗇𝗍∣𝜙}𝗍𝗒𝗉𝖾Entails(Φ(Γ),𝜙[𝑚/𝜈])
Γ⊢𝖣𝖱𝖾𝖿𝑚:{𝜈:𝖨𝗇𝗍∣𝜙}
R-Int
Γ⊢𝖣𝖱𝖾𝖿{𝜈:𝖠𝗋𝗋∣𝜙}𝗍𝗒𝗉𝖾Entails(Φ(Γ),𝜙[⟨𝑚1,…,𝑚𝑘⟩/𝜈])
Γ⊢𝖣𝖱𝖾𝖿⟨𝑚1,…,𝑚𝑘⟩:{𝜈:𝖠𝗋𝗋∣𝜙}
R-Arr
Γ,𝑥:𝑅⊢𝖣𝖱𝖾𝖿𝑒:𝑆
Γ⊢𝖣𝖱𝖾𝖿𝜆𝑥:𝑅.𝑒:Π𝑥:𝑅𝑆
R-Lam
Γ⊢𝖣𝖱𝖾𝖿𝑒:Π𝑥:𝑅𝑆Γ⊢𝖣𝖱𝖾𝖿𝑣:𝑅
Γ⊢𝖣𝖱𝖾𝖿𝑒𝑣:𝑆[𝑣/𝑥]
R-App
Γ⊢𝖣𝖱𝖾𝖿𝑒:𝑅Γ⊢𝖣𝖱𝖾𝖿𝑅<:𝑆
Γ⊢𝖣𝖱𝖾𝖿𝑒:𝑆
R-Sub
A neutral application 𝑓𝑣 is stuck when 𝑓 is a variable; the typing judgment does not invent a lambda body.
The term rule R-Sub makes direct recursion on a declarative derivation nonalgorithmic: a checker would have to guess the type before its final subsumption. Principal synthesis removes that guess.
Write Γ⊢𝖣𝖱𝖾𝖿𝑒⇒𝑅 when 𝑒 synthesizes 𝑅, and Γ⊢𝖣𝖱𝖾𝖿𝑒⇐𝑅 when 𝑒 checks against 𝑅. The rules are
Γ(𝑥)=𝑅
Γ⊢𝖣𝖱𝖾𝖿𝑥⇒𝑅
A-Var
Γ⊢𝖣𝖱𝖾𝖿𝑚⇒[𝑚]𝖨𝗇𝗍
A-Int
Γ⊢𝖣𝖱𝖾𝖿⟨𝑚1,…,𝑚𝑘⟩⇒[⟨𝑚1,…,𝑚𝑘⟩]𝖠𝗋𝗋
A-Arr
Γ⊢𝖣𝖱𝖾𝖿𝑅𝗍𝗒𝗉𝖾Γ,𝑥:𝑅⊢𝖣𝖱𝖾𝖿𝑒⇒𝑆
Γ⊢𝖣𝖱𝖾𝖿𝜆𝑥:𝑅.𝑒⇒Π𝑥:𝑅𝑆
A-Lam
Γ⊢𝖣𝖱𝖾𝖿𝑒⇒Π𝑥:𝑅𝑆Γ⊢𝖣𝖱𝖾𝖿𝑣⇐𝑅
Γ⊢𝖣𝖱𝖾𝖿𝑒𝑣⇒𝑆[𝑣/𝑥]
A-App
Γ⊢𝖣𝖱𝖾𝖿𝑒⇒𝑅Γ⊢𝖣𝖱𝖾𝖿𝑅<:𝑆
Γ⊢𝖣𝖱𝖾𝖿𝑒⇐𝑆
A-Check
Algorithmic subtyping is the structural recursion given by R-Base-Sub and R-Π-Sub; it contains no term subsumption rule. The base case invokes the certified difference-logic decision described after definition 106.4. Thus synthesis chooses a unique outer constructor, and checking performs one final subtype test rather than searching for uses of R-Sub.
Suppose the declaration of 𝑥 contributes the well-sorted assumption 𝜙𝑥 to Φ(Γ,𝑥:𝑅). Let 𝑣 be an integer variable or literal, or an array variable or literal, of the same base shape in Γ. If Entails(Φ(Γ)∧𝜙𝑥,𝜓)andEntails(Φ(Γ),𝜙𝑥[𝑣/𝑥]), then Entails(Φ(Γ),𝜓[𝑣/𝑥]).
Proof. Let 𝜌 be a valuation satisfying Φ(Γ). Extend 𝜌 by mapping 𝑥 to the integer denoted by 𝑣, or by mapping 𝗅𝖾𝗇(𝑥) to the length denoted by the array value 𝑣. Variables are interpreted by 𝜌; literals have their displayed integer or length. The second hypothesis gives 𝜙𝑥[𝑣/𝑥] under 𝜌, so the extended valuation satisfies Φ(Γ),𝜙𝑥. The first hypothesis then gives 𝜓. Evaluating 𝜓 in the extension is the same integer calculation as evaluating 𝜓[𝑣/𝑥] under 𝜌. Since 𝜌 was arbitrary, the required entailment holds. ◻
Proof of Lemma 106.7 — Refinement narrowing and substitution
Proof. For narrowing, induct on the derivation of 𝐽. Variable typing uses reflexivity when the selected declaration is not 𝑥 and uses subsumption from 𝑅′ to 𝑅 when it is 𝑥. In R-Base-Sub, the assumptions contributed by 𝑅′ imply those contributed by 𝑅, so composing implications preserves the entailment premise. The binder cases rename their bound variable to a name outside dom(Γ,Δ)∪{𝑥} and apply the induction hypothesis under the extended context. Formation, application, and subsumption rebuild their displayed rules. These are all rule families.
For substitution, use simultaneous induction on the three derivations. The variable case for 𝑥 is the given derivation of 𝑣:𝑅; every other variable case is unchanged. Rule R-Base-Sub uses lemma 106.6 when 𝑅 is a base refinement. The value grammar and inversion of its typing derivation make 𝑣 an integer or array variable or literal in that case. When 𝑅 is a dependent function type, well-sortedness forbids 𝑥 as a difference-logic vertex, so the entailment is unchanged. In R-Lam and R-Π-F, alpha-rename the binder 𝑦 so that 𝑦∉fv(𝑣)∪dom(Γ,Δ)∪{𝑥}, then apply the induction hypothesis to the body. Rule R-App applies the two induction hypotheses and uses 𝑆[𝑢/𝑦][𝑣/𝑥]=𝑆[𝑣/𝑥][𝑢[𝑣/𝑥]/𝑦], whose freshness premise is the chosen 𝑦∉fv(𝑣). Subsumption applies both induction hypotheses and rebuilds R-Sub. Base formation performs literal normalization of difference constraints after substitution. No other rule binds a variable or changes a predicate. ◻
For well-formed 𝖣𝖱𝖾𝖿 types, certified subtyping is reflexive and transitive. A derivation relates only two base refinements of the same shape or two dependent function types. In particular, Γ⊢𝖣𝖱𝖾𝖿Π𝑥:𝑅1𝑆1<:Π𝑥:𝑅2𝑆2 has premises Γ⊢𝖣𝖱𝖾𝖿𝑅2<:𝑅1 and Γ,𝑥:𝑅2⊢𝖣𝖱𝖾𝖿𝑆1<:𝑆2.
Proof of Lemma 106.8 — Certified subtyping structure
Proof. Outer-form inversion follows because R-Base-Sub and R-Π-Sub are the only subtyping rules. Reflexivity is structural induction on the type. At a base type it is reflexivity of semantic implication. At a dependent function, apply the induction hypotheses to the domain and to the codomain under its binder, then apply R-Π-Sub.
For transitivity, induct on the middle type. At a base type, implication composition gives the required Entails premise. For dependent functions, suppose the two derivations have respective codomain premises Γ,𝑥:𝑅2⊢𝖣𝖱𝖾𝖿𝑆1<:𝑆2,Γ,𝑥:𝑅3⊢𝖣𝖱𝖾𝖿𝑆2<:𝑆3 and domain premises 𝑅2<:𝑅1 and 𝑅3<:𝑅2. The domain induction hypothesis gives 𝑅3<:𝑅1. Narrow the first codomain premise from 𝑥:𝑅2 to 𝑥:𝑅3 using lemma 106.7; the codomain induction hypothesis then gives 𝑆1<:𝑆3 under 𝑥:𝑅3. Rule R-Π-Sub completes the derivation. ◻
Proof of Theorem 106.9 — Correctness and completeness of principal checking
Proof. For clause 1, use simultaneous induction on synthesis and checking, with the auxiliary claim that Γ⊢𝖣𝖱𝖾𝖿𝑒⇐𝑅 implies Γ⊢𝖣𝖱𝖾𝖿𝑒:𝑅. The variable and lambda cases apply R-Var and R-Lam. The exact singleton constraints of A-Int and A-Arr hold after substituting the displayed literal, so R-Int and R-Arr apply. The application case uses the synthesis and checking induction hypotheses before applying R-App. In the auxiliary A-Check case, the synthesis induction hypothesis followed by R-Sub proves the claim.
For clause 2, induct on the declarative typing derivation. Variables synthesize their declarations. In the integer case, any valuation satisfying Φ(Γ) and 𝜈=𝑚 satisfies the requested predicate because the premise of R-Int proves that predicate after substituting 𝑚 for 𝜈. Hence [𝑚]𝖨𝗇𝗍 is a subtype of the requested refinement. The array case uses the same valuation argument with 𝗅𝖾𝗇(𝜈)=𝑘. In the lambda case, the induction hypothesis for the body gives 𝑃<:𝑆; reflexivity on the annotated domain and R-Π-Sub give Π𝑥:𝑅𝑃<:Π𝑥:𝑅𝑆.
In the application case, let the induction hypothesis for the function give Γ⊢𝖣𝖱𝖾𝖿𝑒⇒Π𝑥:𝑅0𝑆0,Γ⊢𝖣𝖱𝖾𝖿Π𝑥:𝑅0𝑆0<:Π𝑥:𝑅𝑆. By lemma 106.8, 𝑅<:𝑅0 and 𝑆0<:𝑆 under 𝑥:𝑅. If 𝑃𝑣 is the synthesized type of 𝑣, the value induction hypothesis gives 𝑃𝑣<:𝑅; transitivity gives 𝑃𝑣<:𝑅0, so A-Check checks 𝑣 against 𝑅0. Rule A-App synthesizes 𝑆0[𝑣/𝑥]. Declarative typing gives 𝑣:𝑅 by clause 1 and subsumption, so substitution in lemma 106.7 gives Γ⊢𝖣𝖱𝖾𝖿𝑆0[𝑣/𝑥]<:𝑆[𝑣/𝑥]. Finally, a declarative R-Sub case composes the subtype supplied by the induction hypothesis with its displayed subtype premise. These are all declarative typing rules.
Each synthesis rule is selected by the outer term constructor, and A-App recurses on the proper function subterm. Thus the synthesized type is unique. Clause 3 follows from clauses 1 and 2 together with A-Check. ◻
Proof of Theorem 106.10 — Preservation and decidability for DRef
Proof. For preservation, induct on the reduction derivation. Consider first the root beta step (𝜆𝑥:𝑅0.𝑒0)𝑣⟶𝑒0[𝑣/𝑥] at a declared result type 𝑇. By theorem 106.9, its unique synthesis derivation ends in A-App and has the form 𝑥:𝑅0⊢𝖣𝖱𝖾𝖿𝑒0⇒𝑆0⋅⊢𝖣𝖱𝖾𝖿𝜆𝑥:𝑅0.𝑒0⇒Π𝑥:𝑅0𝑆0⋅⊢𝖣𝖱𝖾𝖿𝑣⇐𝑅0⋅⊢𝖣𝖱𝖾𝖿(𝜆𝑥:𝑅0.𝑒0)𝑣⇒𝑆0[𝑣/𝑥], together with 𝑆0[𝑣/𝑥]<:𝑇. Soundness of synthesis and checking gives 𝑥:𝑅0⊢𝖣𝖱𝖾𝖿𝑒0:𝑆0 and ⋅⊢𝖣𝖱𝖾𝖿𝑣:𝑅0. Substitution gives ⋅⊢𝖣𝖱𝖾𝖿𝑒0[𝑣/𝑥]:𝑆0[𝑣/𝑥]; one use of R-Sub at 𝑆0[𝑣/𝑥]<:𝑇 restores the declared result type. Thus no inversion through a hidden use of R-Sub is required.
For a compatible step 𝑒0𝑣1⟶𝑒′0𝑣1, principality gives a synthesized function type Π𝑥:𝑅1𝑆1, a check of 𝑣1 against 𝑅1, and a final relation 𝑆1[𝑣1/𝑥]<:𝑇. The induction hypothesis preserves 𝑒0:Π𝑥:𝑅1𝑆1. Rule R-App, followed by the recorded final subtyping relation, types 𝑒′0𝑣1:𝑇. These are all reduction rules.
For decidability, execute the rules of definition 106.5. Synthesis recurses on a proper term subexpression; checking makes one structural subtyping call. Function subtyping recurses on strict type subexpressions. A base call asks finitely many difference-constraint consequences. For an antecedent graph 𝐺, a consequence holds when either 𝐺 has a negative cycle, making the antecedent inconsistent, or 𝐺 has no negative cycle and its shortest-path bound implies the requested inequality. Bellman–Ford terminates on the finite vertex set; the certificate checker validates the returned cycle in the first case and the returned path bound in the second. Alpha-equivalence and well-formedness are structural decisions. The equivalence in theorem 106.9 transfers this decision from algorithmic checking to declarative typing with R-Sub. ◻
A difference constraint 𝑟1−𝑟2≤𝑘 contributes the directed edge 𝑟2𝑘→𝑟1. A path certificate records a vertex sequence whose edges occur in the antecedent graph; its recomputed weight must be at most the goal bound. A negative-cycle certificate records 𝑟0,…,𝑟𝑛 with 𝑟𝑛=𝑟0, checks every edge against the graph, and requires the recomputed sum to be negative.
For a concrete inconsistent antecedent, take 𝑥−0≤0,0−𝑥≤−1. Its graph contains 00→𝑥−1⟶0. The displayed two-edge cycle has total weight −1, so the certificate checker accepts it. The antecedent asserts both 𝑥≤0 and 1≤𝑥; hence R-Base-Sub may derive any requested base refinement from it. This branch is a decision, not a successful shortest-path proof: it records that the context itself is inconsistent.
The well-formedness restriction matters. If a predicate mentions an undeclared array 𝑎, the vertex 𝗅𝖾𝗇(𝑎) has no interpretation in a valuation of Γ. Treating the missing vertex as zero would make the checker prove a different formula.
★★☆ Let 𝑅1={𝜈:𝖨𝗇𝗍∣0≤𝜈} and 𝑅2={𝜈:𝖨𝗇𝗍∣1≤𝜈}. Derive 𝑅2<:𝑅1. Under 𝑥:𝑅1, type a function whose result has refinement 0≤𝜈−𝑥. Narrow the context to 𝑥:𝑅2 and list the graph edges used by the new entailment. Finally remove the premise 𝑅2<:𝑅1 and give the valuation 𝑥=−1 that invalidates the claimed narrowing step.
The following calculation isolates the refinement-ledger obligation in a familiar bounds-checked client. Suppose a host language has integer comparison, conditionals, and an array-selection constant with interface 𝗀𝖾𝗍:Π𝑎:𝖠𝗋𝗋Π𝑖:{𝜈:𝖨𝗇𝗍∣0≤𝜈<𝗅𝖾𝗇(𝑎)}𝖨𝗇𝗍. Suppose its then branch contributes the guard as a logical assumption. The host program is 𝜆𝑎:𝖠𝗋𝗋.𝜆𝑖:{𝜈:𝖨𝗇𝗍∣0≤𝜈}.𝗂𝖿𝑖<𝗅𝖾𝗇(𝑎)𝗍𝗁𝖾𝗇𝗀𝖾𝗍𝑎𝑖𝖾𝗅𝗌𝖾0. The 𝖣𝖱𝖾𝖿-owned calculation begins only after entering the then branch. Its graph has the parameter edge 𝑖0→0, representing 0−𝑖≤0, and the guard edge 𝗅𝖾𝗇(𝑎)−1⟶𝑖, representing 𝑖−𝗅𝖾𝗇(𝑎)≤−1. The second edge is itself a certificate for the strict upper bound required by 𝗀𝖾𝗍; the first certifies the lower bound. The else branch contains no array selection and requests no bounds certificate.
This paragraph proves only those two difference-logic consequences. The conditional, comparison, and selection constructs are outside the term grammar of definition 106.4, so it is not a typing or preservation derivation for an unprinted extension of 𝖣𝖱𝖾𝖿. Nor does it assert which solver, erasure policy, or operational equations are implemented by ATS, Liquid Haskell, or another host language.
The gradual-dependent ledger
Replacing a missing proof by an erased refinement assumption would make the preceding program trust the assertion. Gradual CIC takes another route: a gain of precision becomes an explicit computation that may produce an error.
The source contains universe-indexed unknown terms ?𝐴 and errors 𝖾𝗋𝗋𝐴. When a term 𝑡 known at 𝐴 is checked at a consistent type 𝐵, bidirectional elaboration inserts 𝖼𝖺𝗌𝗍[𝐵⇐𝐴](𝑡). The target is CastCIC. A downcast inspects the value’s constructor or universe tag; a failed inspection reduces to 𝖾𝗋𝗋𝐵.
Write PrecΓ(𝑡,𝑢) for the source’s well-typed precision proposition. This notation is chapter-local prose notation, not the nondependent precision relation of chapter 11. The selected variant below is 𝖦𝖢𝖨𝖢𝐺: it is conservative over CIC and satisfies graduality, but it is not normalizing.
For a static natural 4, the round trip 𝖼𝖺𝗌𝗍[ℕ⇐?](𝖼𝖺𝗌𝗍[?⇐ℕ](4))⟶∗4 is an embedding followed by its projection. Replacing the inner value by a Boolean reaches 𝖾𝗋𝗋ℕ. These reductions are not refinement subtyping derivations: the cast remains at run time and can fail.
For a closed term 𝑒, put 𝖲𝗍𝖾𝗉𝗌≥𝑘(𝑒):=∃𝑒0,…,𝑒𝑘.𝑒=𝑒0∧⋀0≤𝑖<𝑘𝑒𝑖⟶𝑒𝑖+1. A gradual theory has context-wise reduction retraction when the following holds. Let 𝐴 be more precise than 𝐵, let 𝑡:𝐴, and let 𝐶[−] be any well-typed one-hole term context whose hole has type 𝐴. For every 𝑘:𝖭𝖺𝗍, 𝖲𝗍𝖾𝗉𝗌≥𝑘(𝐶[𝑡])⟹𝖲𝗍𝖾𝗉𝗌≥𝑘(𝐶[𝖼𝖺𝗌𝗍[𝐴⇐𝐵](𝖼𝖺𝗌𝗍[𝐵⇐𝐴](𝑡))]).(𝐶𝑅) Thus the round trip may delay the surrounding computation, but it cannot remove a finite reduction prefix obtained from 𝑡. This property is stronger than observational equiprecision, which does not compare reduction lengths.
Proof of Theorem 106.13 — Fire triangle for gradual CIC
Proof. Let 𝛿=𝜆𝑥:?.𝖼𝖺𝗌𝗍[?→?⇐?](𝑥)𝑥,Ω=𝛿𝖼𝖺𝗌𝗍[?⇐?→?](𝛿). Put 𝑈=?→?, 𝑢=𝖼𝖺𝗌𝗍[?⇐𝑈](𝛿), and 𝐶[𝑧]=𝑧𝑢. Clauses 1 and 2 type 𝛿:𝑈, 𝑢:?, and Ω=𝐶[𝛿]:?.
We prove 𝖲𝗍𝖾𝗉𝗌≥𝑘(Ω) by induction on 𝑘:𝖭𝖺𝗍. The empty sequence proves the case 𝑘=0. Suppose 𝖲𝗍𝖾𝗉𝗌≥𝑘(Ω). Since Ω=𝐶[𝛿], clause 3 with 𝐴=𝑈 and 𝐵=? gives 𝖲𝗍𝖾𝗉𝗌≥𝑘(𝐶[𝖼𝖺𝗌𝗍[𝑈⇐?](𝖼𝖺𝗌𝗍[?⇐𝑈](𝛿))]).(1) One beta step gives Ω⟶𝐶[𝖼𝖺𝗌𝗍[𝑈⇐?](𝖼𝖺𝗌𝗍[?⇐𝑈](𝛿))].(2) Prefix the 𝑘 steps from (1) by (2). This proves 𝖲𝗍𝖾𝗉𝗌≥𝑘+1(Ω).
Thus Ω has a reduction prefix of every finite length and cannot be strongly normalizing. ◻
The proof uses the three hypotheses at different points. Conservativity types the simply typed arrow skeleton of 𝛿 and Ω. Universality makes the self-applications typable and gives the precision comparison from 𝑈 to ?. Context-wise reduction retraction preserves the induction hypothesis through the cast round trip. Ordinary embedding–projection equiprecision does not give that finite-step conclusion. Removing any one of the three hypotheses blocks this construction, but this observation is not a countermodel proving logical necessity, and no converse is claimed.
For the CastCIC𝐺 syntax, typing, reduction, and semantic precision fixed in definition 106.11, the following hold.
Cast insertion preserves typing and CastCIC𝐺 has progress and preservation with errors counted as outcomes.
Static CIC terms elaborate conservatively: erasing their inserted casts recovers the CIC term and type.
If PrecΓ(𝑡,𝑢), then every closing Boolean observation of 𝑡 is an error-or-divergence refinement of the corresponding observation of 𝑢.
If 𝐴 is more precise than 𝐵, the upcast from 𝐴 to 𝐵 and the downcast from 𝐵 to 𝐴 form an embedding–projection pair; the downcast after the upcast is equiprecise with the identity on 𝐴.
Proof. For clause 1, induct simultaneously on elaboration and target typing. Variables and static constructors elaborate homomorphically. A consistency check between 𝐴 and 𝐵 inserts 𝖼𝖺𝗌𝗍[𝐵⇐𝐴]; the cast typing rule has exactly the two formation premises produced by the induction hypotheses. Dependent application substitutes the elaborated argument into both the source and target codomain. Inductive elimination substitutes the constructor indices into its motive. These are the binder, conversion, application, constructor, and eliminator families, so cast insertion preserves typing.
Preservation is induction on a CastCIC𝐺 root step. A successful cast between equal head constructors recursively casts their parameters and indices, and the constructor typing rule rebuilds the result. A failed head comparison yields 𝖾𝗋𝗋𝐵:𝐵. Beta, iota, and fixpoint roots use substitution; congruence uses the induction hypothesis. For progress, invert a closed typing derivation. A lambda or constructor is a value; an error is an allowed outcome; application, elimination, and cast forms either contain a reducible subterm or match one of the preceding roots. This proves the target part of clause 1.
For clause 2, induct on a static CIC elaboration. No unknown or error rule can be the last rule. Every inserted cast therefore has equal source and target types and erases to the identity. The binder and inductive cases commute with erasure and substitution, so erasing all inserted casts recovers the original term and type.
For clauses 3–4, interpret every type by a pointed omega-cpo of computations and define an admissible precision relation on that domain. At a universe or inductive type, the relation compares equal head constructors componentwise; on the less precise side it also admits the error point and the least element representing divergence. At a dependent product it relates functions that send related arguments to related results. At an inductive family it also requires the constructor indices to be related. Admissibility closes each clause under limits of increasing computation chains, so a diverging approximation cannot be mistaken for a terminating constructor.
The fundamental lemma is a simultaneous induction on the precision and typing derivations, strengthened to related substitutions. Variables use the substitution relation. Constructors and eliminators use the corresponding domain clauses. Dependent binders apply the induction hypothesis after extending both substitutions by related arguments. The cast case uses the constructor-directed reduction from clause 1; incompatible heads land at the error point, while compatible heads reduce to the component relations. Conversion uses invariance of the interpretation under definitional equality. These cases exhaust the static, binder, inductive, conversion, and cast rule families. Specializing the fundamental lemma to closing Boolean contexts gives exactly the observation refinement of clause 3: a Boolean constructor on the precise side is matched by the same constructor, an error, or divergence on the less precise side.
If 𝐴 is more precise than 𝐵, the upcast maps each related 𝐴-value to its 𝐵 image. The downcast performs the same constructor test in reverse. The type induction shows that downcast after upcast returns the original constructor and recursively satisfies the relation on every field; functions use extensionality at related arguments. Hence the round trip is equiprecise with the identity on 𝐴, proving clause 4. This observational result does not compare finite reduction lengths, so theorem 106.13 still rules out adding strong normalization under context-wise reduction retraction. ◻
Indexed inductives expose the run-time obligation. For vectors, the selected CastCIC extension contains constructor-directed roots including 𝖼𝖺𝗌𝗍[𝖵𝖾𝖼𝐵0⇐𝖵𝖾𝖼𝐴0](𝗇𝗂𝗅𝐴)⟶𝗇𝗂𝗅𝐵,𝖼𝖺𝗌𝗍[𝖵𝖾𝖼𝐵0⇐𝖵𝖾𝖼𝐴(𝗌𝗎𝖼𝑛)](𝖼𝗈𝗇𝗌𝐴𝑎𝑛𝑣)⟶𝖾𝗋𝗋𝖵𝖾𝖼𝐵0. The constructor and index are checked together. The source calculates this vector extension and conjectures a generalization only for inductive families with concretely forceable indices; no theorem here promotes the vector roots to an arbitrary indexed-inductive schema.
★★☆ Calculate the two reductions obtained by first casting 𝗇𝗂𝗅𝐴 and 𝖼𝗈𝗇𝗌𝐴𝑎0(𝗇𝗂𝗅𝐴) to an unknown vector index and then downcasting to index 0. State which constructor test fails. Explain why the successful reduction is an embedding–projection calculation and not proof irrelevance.
Chapter 11 cards a boundary calculus in which a typed and an untyped side exchange values through explicit checks. Return to it with an index-refining client. A list/vector boundary relates two representations; it is neither refinement subtyping nor a GCIC cast. Let 𝖿𝗈𝗋𝗀𝖾𝗍𝑛:𝖵𝖾𝖼𝐴𝑛→𝖫𝗂𝗌𝗍𝐴 erase the index, and let 𝖼𝗁𝖾𝖼𝗄𝑛:𝖫𝗂𝗌𝗍𝐴→𝖮𝗉𝗍𝗂𝗈𝗇(𝖵𝖾𝖼𝐴𝑛) compare the list length with 𝑛.
Proof of Proposition 106.15 — Round trips at the list/vector boundary
Proof. Both directions are structural inductions on 𝑛. For the first, at 𝑛=0 the only vector is 𝗇𝗂𝗅, 𝖿𝗈𝗋𝗀𝖾𝗍0 returns the empty list, and 𝖼𝗁𝖾𝖼𝗄0 accepts it. At 𝗌𝗎𝖼𝑛 write 𝑣=𝖼𝗈𝗇𝗌𝑎𝑣′; 𝖿𝗈𝗋𝗀𝖾𝗍 emits 𝑎 and recurses, and 𝖼𝗁𝖾𝖼𝗄𝗌𝗎𝖼𝑛 strips 𝑎 and recurses, so the induction hypothesis applies to 𝑣′ and the head 𝑎 is returned unchanged. The second direction inducts on the same measure and reads the two recursive equations in the other order. Neither direction makes the pair an equivalence, because 𝖼𝗁𝖾𝖼𝗄𝑛 is partial; exercise 106.7 asks for both inductions in full. ◻
The two round trips are the option-valued shadow of a more structured factorization through the image of 𝖿𝗈𝗋𝗀𝖾𝗍𝑛: 𝗂𝗆𝖿𝗈𝗋𝗀𝖾𝗍𝑛:={𝑙:𝖫𝗂𝗌𝗍𝐴&∃𝑣:𝖵𝖾𝖼𝐴𝑛.𝖿𝗈𝗋𝗀𝖾𝗍𝑛𝑣=𝑙}, observe that 𝖵𝖾𝖼𝐴𝑛 and 𝗂𝗆𝖿𝗈𝗋𝗀𝖾𝗍𝑛 are equivalent types, and place all the partiality in the remaining leg, which relates 𝗂𝗆𝖿𝗈𝗋𝗀𝖾𝗍𝑛 to 𝖫𝗂𝗌𝗍𝐴 and which is a partial connection: a type-theoretic, partial form of a monotone Galois connection. Its two specifications are stated in a monadic order, and the direction from the subset type to the simple type never fails, which is what makes the connection directed. The proposition above is what that factorization yields once the subset type and the equivalence are collapsed into a single 𝖮𝗉𝗍𝗂𝗈𝗇. The collapse loses the intermediate equivalence needed to lift the boundary to higher-order functions.
Translate a vector client ℎ:𝖵𝖾𝖼𝐴(𝗌𝗎𝖼𝑛)→𝐴 to a list boundary by ̂ℎ𝑛(𝑙)=𝗆𝖺𝗍𝖼𝗁𝖼𝗁𝖾𝖼𝗄𝗌𝗎𝖼𝑛(𝑙)𝗐𝗂𝗍𝗁𝗌𝗈𝗆𝖾(𝑣)⇒𝗌𝗈𝗆𝖾(ℎ𝑣)∣𝗇𝗈𝗇𝖾⇒𝗇𝗈𝗇𝖾. Then ̂ℎ𝑛(𝖿𝗈𝗋𝗀𝖾𝗍𝗌𝗎𝖼𝑛(𝑣))=𝗌𝗈𝗆𝖾(ℎ𝑣) by the first clause of proposition 106.15. A list of length 𝑛 produces 𝗇𝗈𝗇𝖾; this is the boundary’s decidable observation.
The counterexample to identification is a failed length check. In the boundary calculus it returns 𝗇𝗈𝗇𝖾 and preserves the original list. In CastCIC it is a reduction to a typed error inside the cast calculus. In 𝖣𝖱𝖾𝖿 there is no run-time check at all: an unproved length entailment prevents typing. The three outcomes differ on the same input.
The chapter’s four trust decisions are as follows.
mechanism
checked evidence
run-time representation
𝜆𝑃≤ subtyping
derivation and conversion
no inserted cast
𝖣𝖱𝖾𝖿 refinement
graph certificate
refinement erased after checking
CastCIC𝐺
type-directed cast
tag, error, and possible divergence
list/vector connection
length decision
option success or failure
Proof irrelevance may identify two proofs after typing; it does not discharge an absent entailment. An inconsistent logical assumption can derive every refinement consequence and is therefore part of the trusted input. It cannot be reclassified as a run-time cast failure.
★☆☆ Reconstruct the derivation in lemma 106.2. Mark the context in which the codomain subtyping premise is checked and the point at which [𝑁/𝑥] is performed.
★★☆ Give two well-formed dependent products for which domain contravariance holds but the codomain premise of Π-Sub fails. Prove failure by a two-element interpretation of the codomain family.
★★☆ For the array client in section 106.2, write the weighted graph in the then branch and a shortest-path certificate for 𝑖−𝗅𝖾𝗇(𝑎)≤−1. Delete the branch assumption and give a valuation refuting the goal.
★★★ Prove both partial-connection laws for 𝖿𝗈𝗋𝗀𝖾𝗍𝑛 and 𝖼𝗁𝖾𝖼𝗄𝑛 by induction on 𝑛. The inductive step must state the head equality and the recursive tail equation separately.
★★★Practical project.dependent-boundary-ledger Implement in Kappa a finite checker with three tagged requests: dependent-function variance, difference-constraint entailment with a supplied path certificate, and vector-index casts. The invariant is that a request is processed only by its tag’s ledger. The program must print the accepted positive/nonzero function comparison, accept the certificate for 0≤𝑖<3, reject the same index claim at 𝑖=3, accept the displayed two-edge negative-cycle certificate as an inconsistent antecedent, reduce the nil round trip to nil, and reduce a cons-to-zero cast to error. Require also the named rejections reversed function domain rejected, nonnegative cycle rejected, forged path weight rejected, disconnected certificate rejected, and cross-ledger routing rejected. The acceptance test checks all eleven outcomes. A mutation that routes refinement entailment through the gradual cast handler must fail the cross-ledger oracle. A second well-typed mutation that trusts the advertised path weight instead of summing the named edges must fail the forged-weight oracle. Identify the ledger-isolation invariant broken by the first mutation and the certificate-validation invariant broken by the second.
Sources. Compagnoni and Aspinall give the 𝜆𝑃≤ algorithm and metatheory [CA96]. Lennon-Bertrand, Maillard, Tabareau, and Tanter give gradual CIC and its fire triangle [LBMTT22]. Dagand, Tabareau, and Tanter’s printed pp. 7–8 give the list/vector factorization collapsed in proposition 106.15[DTT18]. Each source proof package is shorter than ten pages and is proved locally.