Lectures onType Theory
Chapter 13
Chapter 13Optional

Qualified Types, Type Classes, and Coherent Dictionary Elaboration

Prerequisites. Direct starred prerequisites: none. No later core chapter depends on this route.

A class names a collection of operations indexed by a type; its operations are its methods. An instance implements those operations at a particular type constructor. At run time the implementation is carried by a dictionary, an ordinary record of method values. A superclass edge requires every dictionary for the subclass to carry a dictionary for the superclass. These meanings govern the motivating example as well as the calculus below.

The term same:=λx.eqxx is the smallest obstruction. Hindley–Milner can assign A.ABool when eq is itself assigned the scheme A.AABool. Parametricity then makes that assignment too strong: a parametric function at the latter scheme is constant. Given (a1,a2)A2 and (b1,b2)B2, use the relation R={(a1,b1),(a2,b2)}; parametricity relates the two Boolean results by Boolean equality. Since both pairs were arbitrary, all results agree. Real equality is not constant. Conversely, if a caller may silently choose either the usual integer equality dictionary or a dictionary that always returns false, same 0 has two answers. A useful account of overloading must therefore say both where an operation comes from and why its choice is stable.

One finite qualified-type calculus

Typing same generates a class request Eqα; entailment constructs the dictionary passed to eq. These class requests are distinct from the row lacks predicates of chapter 4.

For example, a superclass edge from Ord to Eq requires every Ord dictionary to contain an Eq dictionary. Thus an OrdInt instance determines both integer order and integer equality; the projections below make that containment explicit.

Call the calculus QTC0. Its monotypes, predicates, and schemes are τ::=αIntBoolStringListτττ,p::=Kτ,P,Q::={p1,,pn},σ::=α¯.Pτ. Class names are unary. Predicate sets are finite, not multisets. A class environment C=(S,I) contains

  1. a finite acyclic superclass graph S; and

  2. finitely many primitive instance clauses PK(Cτ¯), where C is a type constructor, every premise is headed by a proper subterm of Cτ¯, and no two instance heads for the same class unify.

Without superclass closure, substitution can change which dictionary should be selected. If Ord has superclass Eq and the only primitive clauses are OrdInt,OrdαOrd(Listα), then substituting α:=Int turns an Eq(Listα) request into a projection from a constructible Ord dictionary, although the unclosed table has no matching Eq clause. The missing derived projection is the reason for closing the table before resolution.

Resolution uses the finite effective table I. Fix a total order on class names and, at each class, on its outgoing superclass edges. Paths are ordered first by length and then lexicographically by those edge orders. For every primitive clause i:PK(Cτ¯) and every superclass K reachable from K, including K itself, choose the fixed shortest class/path-order path and add iK:PK(Cτ¯). Its evidence builder is the primitive constructor followed by the path projection, made explicit below. The empty path is the identity. After this closure, no two effective result heads for the same requested class may unify. Checking nonoverlap only in the primitive table is insufficient: a direct EqInt clause would overlap the derived projection of an OrdInt clause. Rejecting that pair, rather than choosing between possibly different dictionaries, is what makes normalization substitution-stable without assuming class laws. Superclass closure is finite because the class graph and primitive table are finite.

There are no variable-headed instances, uncontrolled overlap, local instances, or class defaults. These restrictions are a termination and coherence policy: for one source program, every selected elaboration constructs the same evidence up to alpha-equivalence. This is not a claim about production Haskell. Our running environment C0 is Ord has superclass Eq,OrdInt,EqαEq(Listα),ShowInt. In particular, it has no ShowBool instance. The two source methods have the schemes eq:α.EqαααBool,show:α.ShowααString.

Entailment constructs evidence

For each class, fix an ordinary target dictionary type. The examples use EqD(A):=AABool,OrdD(A):=EqD(A)×(AABool),ShowD(A):=AString. For the running table, fix target constants ordInt:OrdD(Int),eqList:A.EqD(A)EqD(ListA). If primitive instance i has constructor ci and the chosen path runs from subclass K to superclass K, write πK,K:KD(A)KD(A) for its dictionary projection. The effective candidate’s builder is biKd¯=πK,K(cid¯). For the empty path, πK,K is the identity. For the displayed product representation of OrdD, the abstract projection πEq,Ord is the ordinary first projection π1. Thus π1ordInt and eqList(π1ordInt) are not additional resolution oracles: they are the two instance builders just declared.

Definition 13.1 — Resolution selectors and evidence stores

An evidence telescope ΔP maps each predicate in P to one target variable. More generally, an evidence store Ψ maps distinct predicates to well-typed target evidence terms; a telescope induces the store store(ΔP) which maps each key to its bound variable. The resolution selector bestΨ(Kτ) is the partial function that returns the exact Kτ entry when it exists; otherwise it returns the projection along the shortest superclass path from a local Kτ entry; equal-length candidates and paths are broken by the fixed class/path order; otherwise it is undefined. Separately, pickC(Kτ)=(P,b) freshens and one-way-matches the unique effective candidate, when one exists, and returns its premises and evidence builder b:ΔPeKD(τ). Resolution constructs target evidence d for a predicate p from the candidate table and current evidence store; it is recorded by the judgment resolveC,Ψ(p)=d. Resolution first uses the selected local evidence bestΨ(Kτ)=d. If none exists, it chooses the unique least effective-table clause and applies its builder to recursively resolved premise evidence. The two cases are bestΨ(Kτ)=dresolveC,Ψ(Kτ)=dELocal bestΨ(Kτ)pickC(Kτ)=(P,b)resolveC,Ψ(p)=dp (pP)resolveC,Ψ(Kτ)=bd¯pEInstance. Here a premise-free instance constructor is a constant. The premise pick in E-Instance means: choose the unique matching member of I, freshen its primitive scheme, compute the one-way matcher τ0[θ]=τ, and put P=P0[θ]. It is not symmetric unification. All uses of entailment below use this relation. Priority is only exact-local before superclass-local before the unique global candidate; the canonical superclass path was already fixed when the table was closed. Immediately, if do:OrdD(Int)Ψ, then bestΨ(EqInt)=π1doresolveC0,Ψ(EqInt)=π1doELocal. This example is a lookup in a general evidence store, such as the store built internally by normalization; it is not claiming that the canonical telescope ΔP contains a constructor-headed predicate. With no local evidence, instance resolution instead derives best(Eq(ListInt))pickC0(Eq(ListInt))=({EqInt},eqList)best(EqInt)pickC0(EqInt)=(,π1ordInt){resolveC0,(p)=dpp}=resolveC0,(EqInt)=π1ordIntEInstanceresolveC0,(Eq(ListInt))=eqList(π1ordInt)EInstance. For sets, write C;PQ when selected resolution constructs evidence for every qQ under fresh dictionary variables for P.

Lemma 11.1 — Resolution terminates and is functional

For an admissible C, resolution terminates. For fixed C,Ψ,p, it returns at most one evidence term up to alpha-renaming, and that term has target type pD.

Proof of Lemma 11.1 — Resolution terminates and is functional

Proof. Every recursive resolution call is an effective-instance-premise call. Its type is a proper subterm of the matched head because superclass closure changes only the result class and evidence builder, never the primitive premises. Type size therefore decreases strictly. The selector bestΨ computes a superclass path by a finite scan of the finite acyclic hierarchy; it does not make a recursive resolution call. Hence neither phase admits an infinite call chain.

For functionality, bestΨ is a partial function: exact lookup is unique because Ψ has distinct keys, and the fixed length/class/path order selects one superclass projection. Its definedness also makes E-Local and E-Instance mutually exclusive. Otherwise pickC is a partial function because the fully closed effective heads do not unify. One-way matching is preserved by type substitution. The induction hypotheses uniquely determine all premise evidence. Evidence typing follows in the same induction: a projection has the declared superclass dictionary type, and each effective builder is a well-typed projection of a primitive instance constructor consuming exactly its premise dictionaries. ◻

Exercise 11.1 — *

★★☆ Derive evidence for Eq(List(ListInt)). Then show why allowing both EqαEq(Listα) and a second unifiable effective head violates admission. Explain why a primitive EqInt clause and the derived projection of OrdInt are therefore rejected together.

Canonical predicates, generalization, and ambiguity

Definition 13.3 — Canonical predicate normalization

Canonical predicate normalization is the deterministic admission procedure that processes ready class requests in a fixed priority order and records their evidence, not an unspecified rewrite system. For a class K, let depth(K) be the length of a longest path from K to a root of the finite superclass DAG; thus a subclass has greater depth than its superclass. Fix a total order on class names and a lexicographic order on types obtained from a fixed constructor order, with bound variables compared by de Bruijn index. The request priority first decreases depth, then uses those two orders.

The agenda is one finite priority queue of ready requests plus suspended constructor frames. Premises from every frame enter the same queue as unrelated requests; a frame contributes no evidence to the store until all its premises have returned evidence. To normalize a finite set P, put its requests on this agenda and start with an empty evidence store Ψ. Repeatedly remove the first request p and perform exactly one of these actions:

  1. if bestΨ(p)=d, record d for this occurrence;

  2. if p=Kα and the selector is undefined, allocate one fresh hole dp:pD, add it to Ψ, and record dp;

  3. if p=K(Cτ¯) and the selector is undefined, compute pickC(p)=(R,b). Put R on the same agenda, together with a pending constructor frame. Once those premises have evidence, assemble bd¯, add that evidence for p to Ψ, and discharge the frame; or

  4. if the last case has no effective candidate, return reject(p).

The printed order of an instance orders siblings in its frame; the fixed priority orders every ready request. Duplicate requests share the first recorded evidence. In particular, processing OrdInt constructs and installs its dictionary before EqInt is considered, so the latter uses its superclass projection rather than demanding an independent construction. When the agenda empties, repeatedly remove a hole projected from a retained subclass hole and substitute that projection throughout the recorded evidence. Each cleanup pass removes at least one hole, so iteration reaches a fixed point. Then sort the remaining holes by the fixed syntax order. This defines the total result nfC(P){reject(p)}{ok(Q,η)}. The evidence template η maps every request in P to a dictionary term over fresh holes for Q. Evidence installed internally by a completed constructor frame is available to later requests, but a source predicate set never contributes a constructor-headed local assumption: such predicates are agenda goals. For example, nfC0({Eq(Listα),Eqα,Ordα})=ok({Ordα},η), and η reconstructs the first two dictionaries using eqList(π1do) and π1do.

Definition 13.4 — Replay of a normalization trace

Let F be the completed, ordered frame forest recorded by one successful run of definition 13.3. For a substitution S, replayF[S](p[S]) is the evidence obtained by rerunning the same agenda on the substituted requests, with the fixed request priority and the first-recorded duplicate policy of definition 13.3, while selecting local projections and effective clauses afresh. A former variable-headed hole that becomes constructor-headed is therefore expanded by the selected effective clause; two holes identified by S reuse one store entry. Replay is partial exactly when this rerun reaches a constructor-headed request having no effective candidate.

Definition 13.5 — Ground solvability and equivalence

Write SolC(P) when the closed set P has a joint evidence construction: process it in decreasing superclass depth and fixed syntax order, resolving through the selected effective table and extending the local context after each success. Thus an Ord dictionary constructed first may provide the Eq dictionary required by the same set. Two open requirement sets are ground-equivalent when every grounding substitution θ satisfies SolC(P[θ])SolC(Q[θ]).

Convention 13.6 — Canonical local evidence

A source predicate set contributes only variable-headed holes. A constructor-headed request must be decomposed through the selected effective instance; it may not be assumed as local evidence. This is the canonical-local-evidence policy enforced by canonicalization and resolution.

Lemma 11.2 — Canonicalization

For every finite P, nfC(P) returns exactly one result. If it returns ok(Q,η), then Q is variable-headed and canonical, C;QP, P and Q are ground-equivalent, and no proper subset of Q entails Q. More precisely, for every type substitution S, nfC(P[S]) and nfC(Q[S]) either reject together or return the same canonical set R; on success the template for P[S] is alpha-equivalent to the composite of the template for Q[S] with η[S]. If normalization returns reject(p), the displayed constructor-headed request has no selected derivation under the effective table and the canonical-local-evidence policy.

Proof of Lemma 11.2 — Canonicalization

Proof. Termination and determinism. Every premise placed below a constructor frame has a proper-subterm type, so frame depth is bounded by the size of its root request. The initial set and every premise list are finite; consequently the agenda is finite. Nonunifiability of the fully closed effective heads gives one candidate and matcher. The fixed agenda and sibling orders remove every remaining choice. Thus the procedure returns one success or the first fixed-priority rejection.

Replay soundness. Induct on the height of the finite completed-frame tree, visiting children before their parent. If a completed frame F has retained holes QF, the induction property is: for every request p in the subtree rooted at F there is a selected term ΔQFηF(p):pD,ηF(p)[S][d¯/QF[S]]=αreplayF[S](p[S]). Applying S and replacing each substituted hole by its recorded evidence therefore gives exactly the replayed evidence. The property is simultaneous for all recorded requests. A fresh variable-headed hole is its own evidence. A completed constructor frame is derivable from its recorded premise evidence; installing it in Ψ merely shares that derivation with later goals. In the superclass case, suppose the selected effective clause comes from i:PK(Cτ¯) and path projection πK,K. For premise evidence d¯, both direct replay and replay after substitution construct πK,K(id¯):KD(Cτ¯). Effective nonoverlap is stable under substitution, so replay cannot change the selected clause. Duplicate sharing preserves the conjunction, and superclass-hole removal preserves it because a retained subclass dictionary projects to the removed superclass dictionary. Composing the recorded builders and projections gives η and proves C;QP.

Naturality. For naturality, induct simultaneously on the two replay trees for P[S] and Q[S], using the maximum remaining height. A substituted variable-headed hole either remains a hole or becomes a constructor request; in the latter case both runs select the same effective clause. A constructor frame replays that clause and applies the induction hypotheses to its proper-subterm premises. If substitution merges two formerly distinct holes, duplicate sharing maps both occurrences to the first recorded evidence, so no lockstep bijection between old holes is required. Finally, if one substituted hole becomes a superclass consequence of another, the fixed projection replaces it on both runs. When the subclass dictionary is id¯, both runs record πK,K(id¯) from the same primitive premises. These cases also show that a missing constructor candidate occurs on both sides. Hence both runs reject together or finish with the same ordered holes R, and their evidence templates commute as stated. With a grounding substitution and empty evidence context, this is ground equivalence.

Irredundancy and rejection. At the end, distinct members of Q are variable-headed and no member is a superclass consequence of the others. Effective instances cannot match a variable-headed request. Therefore removing any member leaves that request underivable from the remainder. In the rejection case, the absence of a selected effective constructor-headed candidate leaves neither a global derivation nor an admissible constructor-headed local assumption. ◻

Lemma 13.8 — Canonical factorization

Suppose nfC(P)=ok(Q,η). For every type substitution S and canonical predicate set R0, C;R0P[S]C;R0Q[S].

Proof of Lemma 13.8 — Canonical factorization

Proof. Fix selected entailment derivations of every root request in P[S] from R0. Descend each completed frame tree from its root toward its retained holes, inducting on the maximum remaining frame height. At a constructor frame, the root request cannot be discharged by an exact entry of the canonical set R0, whose entries are variable headed. If it were discharged by a superclass projection from such an entry, its head would still be variable headed. Its selected derivation must therefore use an effective instance clause. Nonoverlap forces that clause to be the one recorded in the frame; invert the selected derivation to obtain selected derivations of the proper-subterm premises, and continue downward. At a retained hole, the selected derivation reached by this inversion is evidence for the corresponding member of Q[S]. If S identifies two holes, duplicate sharing keeps the first selected derivation and directs both occurrences to it. Every retained hole is therefore entailed by R0, which is the displayed entailment. ◻

Without superclass closure, naturality and canonical factorization are false. Let Ord have superclass Eq and take only the primitive instances OrdInt,OrdαOrd(Listα). Normalizing {Ord(Listα),Eqβ} without the derived projected clause retains {Ordα,Eqβ}. After α:=Int and β:=ListInt, the original set is jointly solvable by constructing Ord(ListInt) and projecting, while the retained set is not. In I the derived clause OrdαEq(Listα) builds the missing projection, so both sides succeed.

Let ftv denote free type variables. Given Γ, P, and τ, first compute nfC(P). If it rejects, generalization rejects at the same request; in particular, ShowBool cannot become a silent residual. Otherwise let the result be ok(P0,η) and put A=ftv(P0,τ)ftv(Γ). Every member of P0 has the form Kα, so place it in Pg when αA and in Pr otherwise. This gives the disjoint, exhaustive split P0=PgPr. Define nfC(Pg)=ok(Q,ηg),GenC(Γ;P;τ)=(Pr, A.Qτ,ζ). Because Pg is a subset of the already canonical variable-headed set P0, this second normalization returns Q=Pg and the identity template. It is retained deliberately so every generalization boundary calls the same checked interface, rather than relying on an unchecked invariant in an implementation. Here ζ composes the two normalization templates and witnesses C;Pr,QP. The residual Pr remains at the enclosing binding. A scheme is unambiguous when ftv(Q)ftv(τ). Thus the first scheme below is rejected because its result does not determine A; the second is unambiguous: A.ShowAString,A.EqAABool. The final step of GenC checks this inclusion and rejects the binding when it fails.

Exercise 11.2

★☆☆ Explain why explicit type application could run the ambiguous scheme above, but implicit use cannot select it coherently. Give two distinct target values of type ShowD(Int), such as decimal and hexadecimal printers, that expose the difference; they need not be admissible source instances in C0.

Canonicality is checked when a binding enters an environment; it is not a claim that raw textual substitution preserves a predicate list. We use the global postfix action τ[S] and left-to-right composition S;T, characterized by τ[S;T]=τ[S][T]. Define the canonical action SΓ pointwise. Freshen a binding x:a¯.Pτ away from S, apply S only to its free variables, and compute nfC(P[S])=ok(Q,κx). The resulting binding is x:a¯.Qτ[S], annotated by the transport κx:ΔQeΔP[S]. The action is undefined if normalization or the ambiguity check rejects. For example, specializing x:EqααBool at α:=Int removes the predicate and records the global Eq Int evidence projected from Ord Int; it does not leave a noncanonical ground predicate in the environment. One wants TSΓ and S;TΓ the same intended composite, but determinism alone does not prove that claim. We use SΓ only when this action succeeds. Its target translation (SΓ)D retains the substituted prior interface P[S]τ[S] for each free target variable; κx converts evidence for the canonical source view Q to that interface at each use.

Lemma 13.9 — Canonical environment actions compose

Whenever the displayed actions are defined, TSΓ=S;TΓ up to fresh binders. The accumulated evidence annotation on the left is alpha-equivalent to the transport recorded on the right.

Proof of Lemma 13.9 — Canonical environment actions compose

Proof. Work bindingwise after one common freshening of its quantified variables. If normalizing P[S] yields Q with transport κ, the substitution clause of lemma 11.2 says that normalizing Q[T] and normalizing P[S;T] return the same canonical predicate set. Its commuting template clause equates the sequential transport with the direct transport. Ordinary type components agree because substitution composes. Repeating this argument over the finite environment proves the result; the ambiguity checks inspect the same final scheme and therefore agree as well. ◻

Qualified typing and inference

The source term grammar is the HM grammar. Its declarative judgment is C;P;Γe:τ. It is formed only when nfC(P)=ok(P,id) and each scheme was admitted canonically and unambiguously when its binding entered Γ. Subsequent type substitution acts through SΓ, not by raw substitution, using convention 13.6. The structural rules for variables, abstractions, applications, and let are as follows. x:σΓσ(Qτ)C;PQC;P;Γx:τQVar C;P;Γ,x:τ1e:τ2C;P;Γλx.e:τ1τ2QLam C;P1;Γe1:τ1τ2C;P2;Γe2:τ1nfC(P1P2)=ok(P,η)C;P;Γe1e2:τ2QApp C;P1;Γe1:τ1GenC(Γ;P1;τ1)=(Pr,σ,ζ)C;P2;Γ,x:σe2:τ2nfC(PrP2)=ok(P,η)C;P;Γlet x=e1 in e2:τ2QLet. In Q-Var, σ(Qτ) means instantiate the quantified variables and then discharge the instantiated scheme predicates from Q. Thus this chapter-local occurrence has a qualified type on the right, unlike the HM monotype-instance relation of chapter 3. The three-place occurrence C;PQ is likewise the class-environment-indexed evidence relation defined above, not the two-place row entailment. For a concrete derivation, take Γ0(eq)=α.EqαααBool. Identify a monotype α in Γ with the scheme .α. Then the first new judgment is exercised in full: Γ0(eq)=β.EqβββBool(EqβββBool)[α/β]=EqαααBoolC0;{Eqα}{Eqα}C0;{Eqα};Γ0,x:αeq:ααBoolQVarx:(α)Γ0,x:αC0;C0;;Γ0,x:αx:αQVarC0;{Eqα};Γ0,x:αeqx:αBoolQAppx:(α)Γ0,x:αC0;C0;;Γ0,x:αx:αQVarC0;{Eqα};Γ0,x:αeqxx:BoolQAppC0;{Eqα};Γ0λx.eqxx:αBoolQLam.

Qualified Algorithm W

Qualified inference returns predicates as well as an HM substitution and type: WC(Γ,e)=(P,S,τ). It uses the same most-general unifier as chapter 3. Its clauses use the postfix action and left-to-right composition fixed above. The brackets A[B/α] still denote one capture-avoiding substitution. Write cnfC(P)=Q when nfC(P)=ok(Q,η) for the uniquely determined η; if normalization rejects, W rejects at that clause. The mathematical W triple discards η; its derivation records the normalization call, and the elaborator below recomputes the unique template.

  1. For x, fresh-instantiate Γ(x)=α¯.Qτ to (Q,τ) and return (cnfC(Q),id,τ).

  2. For λx.e, choose fresh a, compute WC(Γ,x:a,e)=(P,S,τ), and return (P,S,a[S]τ).

  3. For e1e2, compute (P1,S1,τ1) for e1, then (P2,S2,τ2) for e2 in S1Γ. With fresh a, let U=mgu(τ1[S2],τ2a) and return (cnfC((P1[S2]P2)[U]),S1;S2;U,a[U]).

  4. For let x=e1 in e2, compute (P1,S1,τ1), then GenC(S1Γ;P1;τ1)=(Pr,σ,ζ), and (P2,S2,τ2) for e2 in S1Γ,x:σ. Return (cnfC(Pr[S2]P2),S1;S2,τ2).

The earlier example follows the first three clauses: eq contributes EqaaaBool; each occurrence of x unifies with a; canonicalization leaves {Eqa}; abstraction returns EqaaBool.

Lemma 11.3 — The generalization split is maximal

When GenC(Γ;P;τ) succeeds, every normalized residual predicate whose variable is not fixed by Γ lies in Pg; every other predicate lies in Pr.

Proof of Lemma 11.3 — The generalization split is maximal

Proof. The set A contains exactly the variables not fixed by Γ. Successful normalization leaves only variable-headed requirements, removing the empty-variable case. Hence every residual is exactly Kα, with αA or αftv(Γ). The two comprehensions are therefore disjoint, exhaustive, and forced. ◻

Lemma 13.11 — Declarative typing is stable under canonical substitution

Suppose C;P;Γe:τ, the canonical environment action SΓ is defined, and nfC(P[S])=ok(Q,η). Then C;Q;SΓe:τ[S].

Proof of Lemma 13.11 — Declarative typing is stable under canonical substitution

Proof. Induct on the displayed typing derivation. In Q-Var, substitute the scheme instance and its selected entailment. Naturality of lemma 11.2 and lemma 13.8 replace the substituted predicate lists by their canonical forms. The abstraction case extends the canonical action by x:τ1[S]. In Q-App, apply the induction hypotheses to both premises and normalize the union; naturality identifies this result with Q. In Q-Let, apply the first induction hypothesis, then canonicalize and factor its generalized predicate list to rebuild the substituted scheme. Apply the second induction hypothesis under that scheme, canonicalize the residual list, and use naturality to identify the combined normal form with Q; Q-Let then rebuilds the conclusion. Freshening the quantified variables away from S preserves the free-variable side condition. These are all four rules. ◻

Theorem 11.4 — Inference soundness

If WC(Γ,e)=(P,S,τ), then C;P;SΓe:τ.

Proof of Theorem 11.4 — Inference soundness

Proof. By induction on e. For a variable, fresh instantiation and canonicalization give exactly Q-Var. For an abstraction, the induction hypothesis types the body under SΓ,x:a[S]; Q-Lam discharges x. For an application, apply lemma 13.11 with U to both induction hypotheses. The MGU equation τ1[S2][U]=(τ2a)[U] says both operands have the common domain τ2[U]; Q-App combines the transported predicates. For let, the induction hypothesis for e1 and lemma 11.3 justify the exact scheme and residual predicates used by Q-Let; the second induction hypothesis types e2, and final canonicalization combines Pr[S2] with P2. ◻

Say that Qρ is a qualified instance of Pτ when some substitution T satisfies τ[T]=ρ and C;QP[T].

Theorem 11.5 — Success and principality for QTC_0

Suppose every canonical environment action, normalization, and ambiguity check succeeds. If C;Q;RΓe:ρ, then W succeeds with (P,S,τ), and there is a T such that τ[T]=ρ,TSΓ=RΓ,C;QP[T]. Consequently the unambiguous closed scheme obtained by generalizing W’s answer is principal among the schemes admitted by QTC0.

Proof of Theorem 11.5 — Success and principality for QTC_0

Proof. Induct on the declarative typing derivation, generalized over the base environment Γ and its action R. The induction claim includes success: W terminates at the corresponding syntax and returns (P,S,τ); there is then a substitution T satisfying all three displayed conclusions. Thus an induction hypothesis licenses the next recursive call rather than assuming that call has returned.

Canonicalization needs a direction not carried by its output template. If W normalizes an input predicate set Pin to P, the template gives PPin. Principality instead needs to derive P[T] from a declarative entailment of Pin[T]. Every use below of a final normalization therefore invokes lemma 13.8.

Variable. Fresh instantiation always returns. Rename its variables away from the declarative instance. The substitution witnessing the declarative instance factors through that fresh renaming; canonical factorization proves the returned predicate entailment. Its restriction to the environment variables is R, so the canonical environments agree.

Abstraction. The premise induction hypothesis makes the body call succeed. Extend its factor by sending W’s fresh argument variable to the declarative domain. This gives the arrow equality, leaves the predicate entailment unchanged, and the extended canonical-environment equation discharges the bound variable.

Application. Inversion gives premise types Bρ and B. The two induction hypotheses make W’s calls return (P1,S1,τ1) and (P2,S2,τ2). The ordinary HM factorization-extension calculation of lemma 4.45 aligns their residual substitutions on the variables inherited from Γ. Extend the aligned substitution to W’s fresh result variable a by aρ; call the result V. Then τ1[S2][V]=(τ2a)[V]=Bρ. Hence W’s unification call succeeds. Most-generality gives a T such that, on every variable in this equation and in the inherited environment, V=U;T,a[U][T]=ρ,TS1;S2;UΓ=RΓ. The two premise entailments, transported through this equality, give C;Q(P1[S2]P2)[U][T]. Canonical factorization for W’s final normalization gives C;QP[T].

Let. The first induction hypothesis makes the right-hand-side call return (P1,S1,τ1). Write its deterministic split as X=ftv(P1,τ1)ftv(S1Γ),P1=P1gP1r,σ=X.P1gτ1. By lemma 11.3, the declarative generalized scheme factors through σ, while P1r remains an outer requirement. After extending both equal canonical environments by the factored scheme, the body induction hypothesis makes the second call return (P2,S2,τ2). The HM factorization-extension lemma extends the body factor on variables generalized at the first call; let T be the resulting common factor. Then τ2[T]=ρ,TS1;S2Γ=RΓ,C;Q(P1r[S2]P2)[T]. Canonical factorization for the last normalization yields C;QP[T].

Every recursive and unification call has now been shown to succeed. A normalization rejection contradicts the corresponding declarative entailment by canonical factorization. For a closed term, generalization quantifies every free result variable, and the factorization just proved is qualified-scheme generality. ◻

The theorem does not cover ambiguous schemes, overlapping effective heads, higher-rank annotations, or defaulting. It also assumes the usual completeness and most-generality theorem for the HM unifier rather than reproving it.

Exercise 11.3 — *

★★☆ Run W on λx.eq(consxnil)(consxnil), using the usual polymorphic list constructor schemes. Record the instance decomposition that turns Eq(Lista) into Eqa. Then give a let right-hand side whose normalization reaches the missing ground request ShowBool and is therefore rejected.

Dictionary elaboration and execution

Definition 13.14 — Evidence target

The evidence target U extends the Church-style constructor and term core of definition 7.6. The inherited fragment has type, term, and let abstraction/application, products, and the declared base types. Its terms and the dictionary delta are u::=xλx:T.uu1u2let x=u1 in u2Λα.uu[T]λ{d:D}.uu{δ}ciπK,Ku. The inherited typing rules are exactly those of that core, extended homomorphically by let and products. The new typing rules are

Γ,d:Du:T
Γλ{d:D}.u:DT
U-DictLam
Γu:DTΓδ:D
Γu{δ}:T
U-DictApp

Each ci and πK,K has the closed polymorphic type declared below.

Values are base values, ordinary and type abstractions, dictionary abstractions, product pairs of values, and saturated dictionary constructors whose arguments are values. Evaluation contexts are generated by E::=[]EuvElet x=E in uE[T]E{u}v{E}πK,KE, together with the left-to-right product and declared base-operation contexts. The root contractions are (λx:T.u)vu[v/x],(Λα.u)[T]u[T/α],let x=v in uu[v/x],(λ{d:D}.u){δ}u[δ/d]. A target signature may additionally declare a finite set of deterministic root equations for saturated base and dictionary constructors. Every such equation is checked once as Γl:T and Γr:T with the same free variables; superclass projection is one such equation. This well-typed-equation condition is part of the admitted class environment and is the only premise about primitive computation used by target preservation. Thus dictionary constructors and projections are not left to an implicit collection of “standard” rules.

Write τD for source-type translation, ΓD for pointwise context translation, and DictTel(Q) for the ordered dictionary telescope. The map erase(u) erases dictionary braces from a target term and applies the corresponding erasure to every context or telescope entry.

The target signature is part of the admitted class environment. Each superclass edge and instance declaration contributes, respectively, πK,K:α.KD(α)KD(α),ci:α¯.(p1)D(pm)DKD(Cτ¯)for p1,,pmK(Cτ¯). An effective candidate contributes no new primitive constant: its builder is the displayed primitive ci followed by its declared superclass projection. The method interface is explicit as well: eq:α.EqD(α)ααBool,eq:=Λα.λ{d:EqD(α)}.d.

For canonical P, let ΔP be the ordered telescope dp:pD. If an evidence template η has domain R, write ηu for simultaneous replacement of the holes dr in u. A type substitution also acts on core type annotations, type applications, dictionary types, and evidence templates; write this action Sv. Holes are keyed by their predicates, and Sdp=dp[S]. The image telescope contains one binder for each distinct predicate in P[S], in canonical order. Thus if p[S]=p[S], the two occurrences become references to the same binder rather than two colliding declarations. The following normalizer template then replaces those image holes by evidence over the canonical result telescope. The annotation on a binding in SΓ remembers the template that converts dictionaries for its canonical predicates to dictionaries expected by the binding’s previous target interface. These annotations compose when composes.

Lemma 13.15 — Target substitution is scoped under merging

If ΓD,ΔPu:T, then SΓD,ΔP[S]Su:ST, where ΔP[S] coalesces equal predicate keys. If normalization of P[S] returns ok(Q,η), then ηSu is scoped under ΔQ.

Proof of Lemma 13.15 — Target substitution is scoped under merging

Proof. Induct on the target typing derivation. The hole case uses the key equation above; coalescing changes two declarations into repeated uses of their one common declaration. All type and term constructors are homomorphic. The second claim is simultaneous evidence substitution, using the typing of the normalizer template from lemma 11.2. ◻

Elaboration is indexed by the successful W derivation W: C;ΔP;ΓDWe:τu. Here Γ is W’s input environment. The derivation W records W’s semantic result (P,S,τ): S transports the input environment, P is the residual predicate set, and τ is the inferred source type. The conclusion adds the elaborated target term u, typed under SΓ and ΔP. The elaboration judgment has cases for variables, abstractions, applications, and lets. A variable occurrence uses exactly the instantiation θ recorded by W. Its κx is the binding’s accumulated canonical-environment transport; it is the identity for a binding that has not been transported. For a template η and a subset R of its domain, η|R is the simultaneous evidence substitution restricted to holes whose keys lie in R. x:(α¯.Qτ0;κx)ΓresolveC,store(ΔP)(q[θ])=δq (qQ)C;ΔP;ΓDWx:τ0[θ]x[α¯[θ]]{(θκx)(δ¯q)}DVar a freshWC(Γ,x:a,e)=(P,S,τ)C;ΔP;Γ,x:aDW0e:τuC;ΔP;ΓDWλx.e:a[S]τλx:(a[S])D.uDLam WC(Γ,e1)=(P1,S1,τ1)C;ΔP1;ΓDW1e1:τ1u1WC(S1Γ,e2)=(P2,S2,τ2)C;ΔP2;S1ΓDW2e2:τ2u2U=mgu(τ1[S2],τ2a)nfC((P1[S2]P2)[U])=ok(P,η)C;ΔP;ΓDWe1e2:a[U](η|P1[S2][U]US2u1)(η|P2[U]Uu2)DApp For let, generalization records a template ζ:ΔPr,ΔQeΔP1 reconstructing the right-hand side requirements. After S2, if η:ΔPeΔPr[S2],ΔP2 is the final normalization template, write ηr,η2 for its restrictions and put ulet:=let x=Λa¯.λ{d¯Q:DictTel(Q)}.((ηridQ)S2ζ)S2u1 in η2u2. WC(Γ,e1)=(P1,S1,τ1)C;ΔP1;ΓDW1e1:τ1u1GenC(S1Γ;P1;τ1)=(Pr,a¯.Qτ1,ζ)WC(S1Γ,x:a¯.Qτ1,e2)=(P2,S2,τ2)C;ΔP2;S1Γ,x:a¯.Qτ1DW2e2:τ2u2nfC(Pr[S2]P2)=ok(P,η)C;ΔP;ΓDWlet x=e1 in e2:τ2uletDLet For a nonidentity let transport, take let f=λxs.eqxsxs in fnilInt. The right-hand side initially requests P1={Eq(Lista)}. Generalization retains Q={Eqa} and records the nonidentity template ζ(da)=eqList(da):EqD(Lista). Consequently D-Let emits the generalized binding let f=Λa.λ{da}.λxs.eq[Lista]{eqList(da)}xsxsinf[Int]{π1ordInt}nilInt. Here ζ performs the instance decomposition and the body occurrence of f uses the nontrivial instantiation recorded by D-Var.

Here DictTel(Q) is the ordered telescope just defined. The mathematical W answer remains (P,S,τ); W stores its choices, while the unique η and ζ are recomputed by the total normalizer. In the application rule, S2 and U act on P1,u1, U acts on P2,u2, and S1 acts on the argument environment. In the let rule, S2 acts on Pr,ζ,u1 before final canonicalization.

Top-level closure is a separate, deterministic operation. If WC(,e)=(P,S,τ),GenC(;P;τ)=(,a¯.Qτ,ζ),C;ΔP;DWe:τu, then closeC(e)=Λa¯.λ{d¯Q:DictTel(Q)}.ζu. The empty residual is forced at the empty source environment; missing ground evidence or ambiguity makes closure reject. A bar over type or dictionary application denotes the corresponding repeated unary forms in canonical order.

For example, the complete evidence-directed elaboration of the opening term is as follows. Here Γ0 binds the source name eq to the target constant eq with its displayed qualified scheme. At both applications, S2, U, the normalizer template η, and every accumulated environment transport are identities. To keep the proof tree legible, its internal nodes suppress the unchanged indices C0;d:EqD(α);Γ0 and their types; each node is an instance of the indexed judgment just defined. eqeq[α]{d}xxeqxeq[α]{d}xDAppxxeqxxeq[α]{d}xxDAppC0;d:EqD(α);Γ0DWλx.eqxx:αBoolλx:α.eq[α]{d}xxDLam. Generalizing closes it as Λα.λ{d:EqD(α)}.λx:α.eq[α]{d}xx.

Theorem 11.6 — Target type preservation

If the elaboration judgment above holds, then (SΓ)D,ΔPu:τD,erase((SΓ)D),erase(ΔP)erase(u):τD. where S is the substitution returned by its index W. Closing a generalized source judgment produces the corresponding sequence of target type abstractions and dictionary arrows.

Proof of Theorem 11.6 — Target type preservation

Proof. Induct on D-Var, D-Lam, D-App, and D-Let. Variable evidence has the required dictionary type by lemma 11.1; target type and dictionary applications therefore instantiate its translated scheme. More precisely, θκx:ΔQ[θ]eΔQ0[θ], where Q0 is the predicate interface stored with x. Applying this transport to the selected δ¯q gives the dictionary arguments expected by x[α¯[θ]]. For abstraction the body induction hypothesis is under SΓ,x:a, so its ordinary binder has type a[S]D. At application, S2 and U transport both induction hypotheses by lemma 13.15 to US2S1Γ; the MGU gives the common domain. Applying η to both normalized predicate sets gives the same dictionary telescope, so source and target applications use the same dictionary parameters. At let, the generalization split determines exactly the type and dictionary abstractions; S2ζ transports the right-hand side, while residual dictionaries remain in ΔP. Canonicalization evidence is well typed by lemma 11.2, so every reconstructed dictionary application typechecks. For erasure, the dictionary-abstraction case sends λ{d:D}.u to λd:D.erase(u) and uses the body induction hypothesis. The dictionary-application case sends u{δ} to erase(u)erase(δ) and uses ordinary application. All remaining constructors use their homomorphic System F rule. ◻

Erase dictionary braces from U to System F by erase(λ{d:D}.u)=λd:D.erase(u),erase(u{δ})=erase(u)erase(δ). All other clauses are homomorphic. Instance constants and superclass projections retain their displayed signatures. Define surface evaluation by evidence insertion and top-level closure: eCwiffcloseC(e)=uand uw. Thus an implicit surface program executes through its unique evidence core; there is no second raw reduction relation that guesses dictionaries.

Lemma 13.17 — Core–target step correspondence

For well-typed closed u:

  1. if uu, then erase(u)erase(u); and

  2. if erase(u)E, then some u satisfies uu and E=erase(u).

Consequently a core reduction erases to a target reduction, and every target reduction from an erased core term lifts to at least one core reduction with the displayed erased endpoint.

Proof of Lemma 13.17 — Core–target step correspondence

Proof. Inspect the root rule. Ordinary beta, type beta, let beta, products, base operations, instance constructors, and superclass projections are homomorphic. Dictionary beta maps to ordinary target beta. Conversely, a target root and the typed outer constructor of the given u select a corresponding core root; evaluation contexts lift structurally. The lift need not be unique because brace erasure is not injective: for example, an ordinary lambda and a dictionary lambda may erase to the same System F lambda. Induction on a step sequence gives forward simulation and existential reverse lifting for reflexive-transitive closure. ◻

Lemma 13.18 — Core dynamic preservation and value reflection

For the admitted target signature:

  1. if Γu:T and uu, then Γu:T; and

  2. a closed core term u is a core value if and only if erase(u) is a value of the erased target.

Proof of Lemma 13.18 — Core dynamic preservation and value reflection

Proof. For clause 1, inspect the root contraction and close the result under the evaluation contexts. Ordinary beta, type beta, let beta, and dictionary beta use the corresponding substitution lemma. A primitive equation preserves the type because its two sides were checked at the same type in the same free-variable context; substituting its value arguments preserves that typing. For clause 2, inspect the two value grammars. Erasure changes a dictionary abstraction into an ordinary abstraction and otherwise preserves the outer constructor. Conversely, a core term whose erasure has a value outer constructor is an ordinary abstraction, type abstraction, dictionary abstraction, value pair, base value, or saturated dictionary constructor, so it is a core value. ◻

Theorem 11.7 — Forward operational simulation

If closed e has closeC(e)=u and E=erase(u), then

  1. eCw implies Eerase(w); and

  2. if EV and V is a target value, then some core value w satisfies eCw and V=erase(w).

This includes generalized let: D-Let inserts its type and dictionary abstractions, while D-Var inserts every instantiation and discharge.

Proof of Theorem 11.7 — Forward operational simulation

Proof. Resolution, normalization, W, and the four elaboration rules are functional, so u is unique up to renaming. Unfold the definition of eCw. Forward simulation gives the first clause. Repeated reverse lifting gives a core endpoint w erasing to V. Value reflection in lemma 13.18 makes that endpoint a core value, giving the second clause. The endpoint is existential rather than fixed because erasure forgets the brace distinction. In particular, the displayed D-Let accounts for type/dictionary administrative redexes; the proof never identifies generalized surface let substitution with one homomorphic target step. ◻

For instance, erasing braces from the preceding core term gives the System F calculation (Λα.λd.λx.eq[α]dxx)[Int](π1ordInt)0(π1ordInt)00true.

Theorem 11.8 — Algorithmic coherence

For the deterministic resolver of definition 13.1 and the W-indexed elaboration relation in this section, two successful elaborations of the same QTC0 W derivation produce alpha-equivalent evidence cores. Their System F erasures are therefore alpha-equivalent and contextually equivalent. This conclusion concerns the selected algorithm, not arbitrary declarative derivations or class laws.

Proof of Theorem 11.8 — Algorithmic coherence

Proof. Fresh type variables and dictionary binders may differ only by renaming. The HM MGU is unique up to such renaming; canonical predicate order is fixed; and lemma 11.1 proves that each request has at most one selected evidence term. An induction over D-Var, D-Lam, D-App, and D-Let therefore determines every core constructor and subterm. Homomorphic erasure preserves alpha-equivalence, and alpha-equivalent System F terms are contextually equivalent. ◻

Thus the result is determinism of the selected algorithm, not a coherence theorem for the declarative system.

The annotated ground compatibility slice

For the explicitly typed ground exercises in appendix A, use the distinct Church-Boolean dictionary notation EqD,F(A):=AABoolF,s::=eq[A](s1,s2)(KAs)sK,A. These are annotations on QTC0 elaboration: bind, use, and discharge one displayed dictionary. They are not a second inference calculus. The symbols BoolF,trueF,falseF are the Church encoding from definition 5.15; they are recalled here because the following dictionary returns that encoding rather than the primitive Bool used above. Let andF:=λp.λq.p[BoolF]qfalseF,eqBool:=λp.λq.p[BoolF]q(q[BoolF]falseFtrueF),allSame3:=ΛA.λd:EqD,F(A).λx:A.λy:A.λz:A.andF(dxy)(dyz).

Proposition 13.21 — Ground-table specialization

Suppose:

  1. a finite ground table has at most one entry for each normalized class/type key;

  2. source type applications and constraint binders are explicit and canonically ordered;

  3. no active evidence context repeats a key; and

  4. lookup uses local evidence before the table.

Then ground lookup is a partial function, and successful annotated elaboration is unique up to alpha-renaming.

Proof of Proposition 13.21 — Ground-table specialization

Proof. Type normalization fixes the lookup key. The local map contains at most one entry; if it contains none, the table contains at most one. Structural induction on the annotated term then forces the elaboration clause and all subterms. The proposition is also the premise-free closed-type specialization of theorem 11.8. ◻

Exercise 13.4

★★☆ Derive the type of allSame3 and reduce allSame3[BoolF]eqBooltrueFtrueFfalseF. Then give an overlapping ground table and a duplicated local evidence key, and identify the failed hypothesis of proposition 13.21 in each case.

Associated type synonyms: one bounded extension

The principal calculus above resolves a predicate but never lets that resolution determine a type. Collections expose the missing dependency: class Collects c wheretype Elem c;empty:c;insert:Elemccc;toList:cList(Elemc). The class predicate says that the operations exist. The associated synonym Elemc says which element type those operations share. It is a partial, saturated type-level function: the application is admitted only when Collectsc is entailed.

This section is a bounded import, called ATS0. It does not strengthen the principality theorem for QTC0. Extend the predicate and instance environments by η::=Sτ¯(a saturated associated synonym),π::=Kτη=τ,θ::=α¯.PKτα¯.η=τ. Class declarations give an arity and kind to S. An instance gives both a class clause and an equality scheme. For example, instance EqaCollects(Lista) wheretype Elem(Lista)=a; contributes a.EqaCollects(Lista),a.Elem(Lista)=a. The equality scheme itself is unqualified, but its left side is well formed only where the associated class predicate is entailed. The instance checker verifies the right-hand side using the superclass environment and the instance premises, while the paired class clause supplies those premises whenever the reduction is applicable. This pairing prevents synonym reduction from exposing a type whose class precondition was never established.

Write Θπ for entailment by class and equality schemes. In addition to specialization and modus ponens, equality has reflexivity, symmetry, transitivity, and congruence. The two distinctive typing rules are ΘCollectsτΘElemτ typeATWFΘΓe:τ1Θτ1=τ2ΘΓe:τ2ATConv. Thus Elemc is not well formed merely because c is a type. For instance, the annotation Elemcc must carry a premise Collectsc.

Evidence and type passing.

The source paper says that its typing rules admit the conventional type-directed evidence translation, but deliberately omits those extended rules [CKPJ05]. The following ground instance is therefore a local target sketch, not an imported elaboration theorem. Class predicates elaborate to ordinary dictionaries, the associated type is an explicit target type parameter, and equality solving chooses and normalizes that parameter at compile time. For the running class, use CollectsD(C,E):=C×(ECC)×(CListE). The method and list instance have target types insert:C.E.CollectsD(C,E)ECC,collectsList:A.EqD(A)CollectsD(ListA,A). Consequently the ground source call at ListInt elaborates to insert[ListInt][Int](collectsList[Int]eqInt). The equation Elem(ListInt)=Int justifies the second type argument. It contributes no run-time proof object to this System-F-style target. An open pending equality remains in the source constraint set until later instantiation makes a rewrite possible.

Definition 13.22 — Inference with pending equality constraints

The judgment Θ,UTΓWe:τ returns class constraints Θ, pending equalities U, a substitution T, and a monotype τ. Application unifies the operator’s inferred domain with the operand type after both substitutions. Repeated unification steps reduce saturated associated synonyms using the instance equations, decompose applications, perform ordinary first-order variable elimination, and leave irreducible equalities in U. For example, (Int,a)=(Elemc,Bool) returns [Bool/a] and the pending equation Int=Elemc. If later c=ListInt, synonym reduction discharges it.

Well-formed programs require constructor-headed, specific, nonoverlapping instance heads; decreasing instance contexts; saturated associated applications; and a confluent, terminating synonym rewrite system. Programmer-written equality constraints have a variable in the designated class-index position. Define the fixed variables by Fixv(T)=,Fixv(a)={a},Fixv(τ1τ2)=Fixv(τ1)Fixv(τ2),Fixv(η)=,Fixv((η=τ)ρ)=Fixv(τ)Fixv(ρ),Fixv((Kτ)ρ)=Fixv(ρ),Fixv(a.σ)=Fixv(σ){a}. Thus variables beneath an associated application do not count as fixed, whereas variables in the ordinary right-hand side of an equality constraint do. If a¯.Pτ is a method signature in class Kβ, require βFV(P)andβFixv(a¯.Pτ). Every annotation e::a¯.ρ also requires a¯FV(ρ)Fixv(ρ). These are the source’s admission conditions, not conclusions of inference.

Theorem 13.23 — Soundness of associated-type inference—imported

Let ΘP, Γ, and e be well formed in ATS0. If Θ,UTΓWe:τ, then the declarative judgment (ΘP,Θ,U)TΓe:τ holds.

Proof of Theorem 13.23 — Soundness of associated-type inference—imported

Proof. This is exactly Chakravarty, Keller, and Peyton Jones’s Theorem 2, under the well-formed-program hypotheses and judgment roles fixed above [CKPJ05]. Their proof factors through a syntax-directed declarative system; soundness of type reduction, one-step unification, its closure, and subsumption discharge the non-syntactic equality cases. Those lemmas are imported with the theorem, not reproved for QTC0. ◻

Exercise 13.5

★★☆ Infer the substitution and pending equality produced by (Int,a)=(Elemc,Bool). Then instantiate c first with ListInt and then with ListBool. For each case, normalize the equality, decide whether inference can succeed, and write the target dictionary and type arguments for the corresponding use of insert.

The imported source states completeness and principality only as beliefs [CKPJ05]. This chapter therefore imports neither. It also makes no claim for open type families, overlap, injectivity annotations, roles, dependent equality, or unrestricted modern GHC instance programs.

Source boundary.

The class examples and dictionary translation are from [WB89]; that paper’s larger principal-typing statement is explicitly conjectural [WB89]. The separation of qualified typing from evidence translation follows [HHPJW96], whose metatheorems are only outlined there and are not imported as proofs. Predicate entailment, context reduction, generalization, and ambiguity follow the executable specification in [Jon99]; that source is an implementation specification, not a mechanized metatheory. The finite superclass-closed effective table, full effective-head nonoverlap policy, normalization naturality, and factorization lemma are the book’s explicit bounded repair; they are not attributed to those larger systems. The proofs in this chapter are therefore for the explicitly restricted QTC0 above. They do not claim principality for Haskell’s full class system.

Stable and coherent implicits

COCHIS begins from a smaller failure than a large type-class program. Its contexts grow to the right, so the final implicit below is nearest: Δ=β, ?β:x, α, ?α:y. Before substituting β for α, the query ?β skips ?α and returns x. After substitution, the nearer assumption has type ?β and the same query returns y. Equivalently, type application changes the evidence selected by λ?β.(Λα.λ?α.?β)β when compared with its type-beta reduct. Resolution that is merely deterministic is therefore not necessarily stable under substitution.

The comparison uses the paper’s exact predicative syntax. From here through the end of the comparison, σ ranges over COCHIS monotypes, not the qualified schemes of QTC0, and Δ is COCHIS’s full typing context, not the evidence-only context used above: ρ::=αρ1ρ2α.ρρ1ρ2,σ::=ασ1σ2,e::=xλ(x:ρ).ee1e2Λα.eeσ?ρλ?ρ.ee1 with e2,Δ::=Δ,x:ρΔ,αΔ,?ρ:x. Only monotypes σ may instantiate . Besides typing Δe:ρ, the deterministic specification has these judgment signatures: ΔrρE,A;Δf[ρ]E,A;Δ;[Δ]lτE,Δ;[ρ];xmρ¯;z¯;τE,stable(A;Δ;ρ;x;τ). These are, respectively, main resolution, focusing, nearest-first lookup, matching with returned goals and evidence placeholders, and permission to skip one candidate. The main rule sets A=tyvars(Δ); focusing strips and rule premises until a simple head remains; lookup scans Δ from right to left. It commits to the first match and may skip a candidate only when the displayed stability judgment holds. Concretely, stable(A;Δ;ρ;x;τ) means that no substitution valid for A;Δ makes the candidate ρ match the query τ; validity and matching are defined immediately after the rules.

Here is the load-bearing fragment of that resolution, including the recursive evidence plumbing. Write A;Δf[ρ¯]E¯ for the pointwise resolution of a sequence of goals. Matching a candidate returns both recursive goals ρ¯ and fresh placeholders z¯; the lookup rule resolves those goals in the full environment and substitutes the resulting evidence into the candidate evidence. The notation |ρ| in this imported fragment is its own source-to-target type translation; it is unrelated to DictTel, ()D, and erase() above.

tyvars(Δ);Δf[ρ]E
ΔrρE
C-R-Main
A;Δ,?ρ1:zf[ρ2]Ez fresh
A;Δf[ρ1ρ2]λz:|ρ1|.E
C-R-IAbs
A;Δ;[Δ]lτE
A;Δf[τ]E
C-R-Simp
Δ;[ρ];xmρ¯;z¯;τEA;Δf[ρ¯]E¯
A;Δ;[Δ,?ρ:x]lτE[E¯/z¯]
C-L-Match
stable(A;Δ;ρ;x;τ)A;Δ;[Δ]lτE
A;Δ;[Δ,?ρ:x]lτE
C-L-NoMatch
Δ;[τ];xm;;τx
C-M-Simp
Δ,?ρ1:z;[ρ2];xzmρ¯;z¯;τEz fresh
Δ;[ρ1ρ2];xmρ1,ρ¯;z,z¯;τE
C-M-IApp
ΔσΔ;[ρ[σ/α]];x[σ]mρ¯;z¯;τE
Δ;[α.ρ];xmρ¯;z¯;τE
C-M-TApp

The simplest lookup uses four of the rules immediately. For either θ=id or θ=[Int/β], XΔ;[β[θ]];xm;;β[θ]xCMSimpA;Δf[]A;Δ;[?β[θ]:x]lβ[θ]xCLMatchA;Δf[β[θ]]xCRSimpΔrβ[θ]xCRMain. Thus the same lookup derivation selects x before and after the ground substitution. The complete source typing and valid-substitution systems are Figs. 2 and 6 of [SdSOWM19]; its resolution, algorithm, unification, and termination systems are Figs. 7–10 on pp. 30–35.

Unambiguity is the inductive predicate UA(A;ρ): UA(A;τ)iffAftv(τ),UA(A;α.ρ)iffUA(A{α};ρ),UA(A;ρ1ρ2)iffUA(A;ρ1) and UA(A;ρ2). Write unamb(ρ) for UA(;ρ); implicit binders and queries require it.

The valid-substitution judgment is valid(A;Δ;θ). The empty substitution is valid. Its only extension clause admits [σ/α]θ when αA, the environment splits as Δ0,α,Δ1, the monotype σ is well scoped in the prefix Δ0, and valid(A{α};[σ/α](Δ0,Δ1);θ). Finally, stable(A;Δ;ρ;x;τ) says that there is no such valid θ under which the skipped θρ matches the query θτ. This is the exact side condition that rejects the witness above; ordinary deterministic lookup alone would accept it.

Recursive rules are admitted only when each premise head is structurally smaller than the result head and every type variable occurs no more often in the premise than in the result. This is the comparison’s one selected mechanism: stable implicit resolution, not a second extension of QTC0.

Theorem 11.10 — Imported COCHIS boundary

For the COCHIS calculi and side conditions just named:

  1. translation to System F preserves types;

  2. deterministic resolution is sound, though incomplete with respect to ambiguous declarative resolution;

  3. in unambiguous environments, resolution is deterministic and selected evidence is syntactically equal;

  4. valid monotype substitution preserves resolution, so type-application beta reduction is contextually sound;

  5. the resolution algorithm is partially correct when it terminates, and the stated structural condition implies termination; and

  6. well-typed closed programs evaluate, via the System F translation, to values.

Proof of Theorem 11.10 — Imported COCHIS boundary

Imported proof. Source. Items 1–6 import Theorems 5.1–5.6 and Lemmas 5.1–5.3 of [SdSOWM19] for exactly the calculus and side conditions frozen above. The paper’s mutual inductions provide the weakening, substitution, resolution, and translation lemmas; its structural measure proves termination of recursive resolution. System F strong normalization and the operational simulation give item 6. No COCHIS principality theorem, result for arbitrary lexical implicits, or result for QTC0 is imported. ◻

The contrast is now precise. QTC0 obtains coherence by an admissible superclass-closed instance environment with fixed candidate priority, canonical constraints, and functional evidence construction. COCHIS admits lexical implicit evidence, so it needs unambiguity and valid substitutions to make resolution stable as types change.

Exercise 11.5 — *

★☆☆ Write both evidence terms selected by the instability witness. Then remove the nearer ?α assumption and explain why lookup no longer skips a candidate, so the stability side condition is not invoked at all.

Suggested first pass.

Begin with exercise 13.7, then continue to exercise 11.7.

Exercise 13.7

★★☆ Trace the preceding counterexample twice: first without the derived clause and then with it. Next start from {Ordγ,Eqβ} and apply S=[Listα/γ] followed by T=[Listα/β]. Verify that without closure the sequential action rejects although the direct (S;T) action succeeds, whereas the two actions compose in the superclass-closed table.

Exercise 11.6 — *

★★★ Suppose a let right-hand side makes W return P1={Eqα,Showβ} and τ1=βBool, while ftv(Γ)={α}. Compute the generalized and residual predicate sets and the resulting scheme. Then explain which environment equation lets the body factorization reuse that scheme, and exhibit the failure if Eqα is generalized instead of retained.

Exercise 11.7 — *

★★☆ Choose one restriction excluded from QTC0. Use an overlapping effective head, a variable-headed instance, or an ambiguous generalized scheme. Give the smallest program that violates the corresponding proof step; do not propose an informal repair without a replacement invariant.

Exercise 11.8 — *

★★★ Practical project.qualified-resolver

Complete the practical project qualified-resolver. The executable must validate nonoverlap after superclass closure and proper-subterm instance descent; resolve exact local evidence before a superclass projection and before global instances, fall back from a missing direct instance to the selected superclass-derived instance, and print an explicit evidence tree.

Its first oracle line is PASS standard accepted. The next three are EqList(EqFromOrd(OrdInt)),EqFromOrd(dOrd),EqFromOrd(OrdList(OrdInt)). The final three case lines carry the corresponding PASS prefix before ambiguous, cycle, and missing; the declared summary line follows.

Run kappa check, kappa test, kappa run, and kappa audit; then demonstrate four typechecking semantic mutations: reversing declaration validation, disabling the descent check, erasing local evidence, and disabling superclass-derived instance fallback. The companion directory is

artifacts/ch13-qualified-resolver/.

Search the book

Type to search the local edition.