Lectures onType Theory
Chapter 19
Chapter 19Optional

Algebraic Subtyping and Principal Inference

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

One variable needs an upper and a lower face

Subsumption breaks the equality equations used by Algorithm W. For apply:=λf.λx.fx equality-based inference identifies the type expected by f with the type produced by x. Subtyping needs only a directed constraint αxaαf. Replacing that constraint by equality forgets valid programs; retaining an external constraint set loses the compact principal type promised by ML inference.

Suppose first that αaInt occurs in αα. Replacing both occurrences by αInt gives (αInt)(αInt). The result is needlessly restricted. The upper bound constrains values accepted by the function, not values returned by it. The compact solution is (αInt)α. The two occurrences of α therefore require different substitutions.

Definition 19.1 — The frozen MLsub fragment MLsub_0

Let b range over the rigid base atoms Unit,Bool,Int,String. The exact term and type grammars are e::=xx^()truefalseλx.eeelet x^=e in eif e then e else e,T::=bαTTTTTTμα.T,P::=b+α+PPNPμα.P,N::=bαNNPNμα.N. In a recursive type, α is covariant and every occurrence of it is guarded by an arrow. The P,N grammars are the polar sublanguages of the ambient local algebra T. A polar type records whether each variable occurrence is in an output position (+) or an input position (). Crossing an arrow reverses polarity in its domain and preserves polarity in its codomain. A polar scheme has the form [Δ]P+, where every entry Δ(x) is a negative type. When an atom’s polarity is determined by its grammar position, its superscript is omitted. Distinct atoms are distinct rigid heads. The variable x is lambda-bound; x^ is let-bound. Bound variables are renamed apart before inference.

The superscripts are sorts, not variance assertions about arbitrary type expressions. In particular, this grammar is not a complemented Boolean type algebra.

Definition 19.2 — Algebraic subtype laws

Let A,B,C range over ambient types T. The relation a is the least preorder on those types, compatible with arrows and the lattice laws aA,Aa,AiaA1A2,(A1aC  A2aC)A1A2aC,A1A2aAi,(CaA1  CaA2)CaA1A2,A2aA1  B1aB2(A1B1)a(A2B2). Guarded μ-types are identified with their unfoldings. For every base atom b, reflexivity gives bab; there is no primitive comparison between two distinct base atoms. Head inversion gives b1ab2 only when b1=b2. The four atoms form a free finite set of nullary heads, rather than an encoding by record labels.

The record encoding is tempting and wrong. In full MLsub, the join of two records retains only their common labels. Hence {unit:bool}{int:bool}={}, whereas UnitInt is not in MLsub0. The local calculus therefore receives its own declarative and algorithmic proof below; no record embedding transports the MLsub theorem.

Definition 19.3 — Lambda-lifted declarative typing

A scheme is [Δ]T, where Δ is a finite map from lambda-bound term variables to ambient types. All type variables in a scheme are implicitly generalized. Let ρ range over type substitutions. Define scheme subsumption by [Δ]T[Δ]T{dom(Δ)dom(Δ),Δ(x)aρ(Δ(x))for every xdom(Δ),ρ(T)aT for some ρ. Write Δ1Δ2 for the finite map on the union of their domains that takes the meet where both maps are defined and the sole entry otherwise. Write Δx for deletion of x, and set Δ(x)= when xdom(Δ).

Let Π map let-bound variables to schemes. The judgment Π0e:[Δ]T is generated by

Π(x^)=S
Π0x^:S
Var-Let
αFV(Π)
Π0x:[x:α]α
Var-Lam
Π0e:[Δ]T
Π0λx.e:[Δx](Δ(x)T)
Abs
Π0e1:[Δ](T1T2)Π0e2:[Δ]T1
Π0e1e2:[Δ]T2
App
Π0e1:[Δ1]T1Π,x^:[Δ1]T10e2:[Δ2]T2
Π0let x^=e1 in e2:[Δ1Δ2]T2
Let
Π0():[]Unit
Unit
q{true,false}
Π0q:[]Bool
Bool
Π0e0:[Δ]BoolΠ0e1:[Δ]TΠ0e2:[Δ]T
Π0if e0 then e1 else e2:[Δ]T
If
Π0e:SSS
Π0e:S
Sub

A polar scheme is a derivable scheme [Δ]P+ whose environment entries are negative and whose result is positive.

For apply, let the two faces of the argument variable be α,α+, and let the result faces be β,β+. Application compares the positive type supplied by x with the negative domain demanded by f. After eliminating that constraint, the closed polar scheme is [](α+β)(αβ+). The outer domain α+β is a negative arrow, while the result αβ+ is a positive arrow. The shared names record the two faces connected by biunification; an environment entry, when present during the derivation, is always negative.

Exercise 19.1 — Polarity calculation

★☆☆ Mark every occurrence of α in (αBool)(Unitα). Then state which occurrences an upper-bound elimination may change.

Biunification eliminates a directed constraint

Definition 19.4 — Bisubstitution

A bisubstitution ξ assigns a positive image ξ+(α) and a negative image ξ(α) to each type variable. Its action on rigid heads, joins, meets, and guarded binders is homomorphic; its action on an arrow exchanges the actions in the domain: ξ+(NP)=ξ(N)ξ+(P),ξ(PN)=ξ+(P)ξ(N). It acts pointwise on a constraint set or sequence: ξC={ξ+(P)aξ(N)(PaN)C}, and the same convention defines ξH. The identity has id±(α)=α, and composition is defined on variable faces by (ζξ)+(α)=ζ+(ξ+(α)),(ζξ)(α)=ζ(ξ(α)). It is stable when ξ(α)aξ+(α) for every α and ξξ=ξ.

The ordering in stability says that the negative requirement is below the positive offer after the action, while idempotence makes reapplication inert.

Definition 19.5 — Atomic elimination

If αFV(N), eliminate an upper bound α+aN with θαaN:=[Nα/α, α/α+]. If P+aα and αFV(P), use θPaα:=[α/α, Pα/α+]. When the variable occurs in its bound, the exact guarded actions are θαaN=[μβ.(αN[β/α])/α, α/α+],θPaα=[α/α, μβ.(αP[β/α+])/α+], where β is fresh. Substitution across an arrow domain exchanges the positive and negative actions as in definition 19.4; the input guardedness condition ensures that the new recursive occurrence is guarded.

Lemma 19.6 — Nonrecursive atomic elimination preserves instances

For a finite constraint set C, define Inst(SC):={ρ(S)ρ(P)aρ(N) for every (PaN)C}, where upward closure uses . Let αFV(N) and αFV(P). For every polar scheme S, Inst(S{αaN})=Inst(θαaN(S)),Inst(S{Paα})=Inst(θPaα(S)).

Proof of Lemma 19.6 — Nonrecursive atomic elimination preserves instances

Proof. Fix a substitution ρ. Suppose first that ρ(α)aρ(N). Meet introduction and elimination give ρ(α)aρ(N)ρ(α)aρ(α). Replacing a negative occurrence of α by Nα therefore preserves the scheme up to mutual subtyping. Structural induction on S, with the comparison reversed in every arrow domain, puts the constrained instance in the right-hand upward closure. At a guarded μ-binder, unfold once and close the same comparison by guarded coinduction; the recurrence has crossed an arrow.

Conversely, let T=ρ(α) be the image used for an arbitrary instance of the eliminated scheme. Define ρ(α)=Tρ(N), and let ρ agree with ρ on every other variable. Since αFV(N), ρ(α)aρ(N). At each negative occurrence the two instances contain the same meet. At each positive occurrence, meet elimination gives ρ(α)aT. Induction on the polar scheme gives ρ(S)ρ(θαaN(S)). Upward closure therefore gives the reverse inclusion in (19.4).

The lower-bound equality is dual. Under a satisfying instance ρ(P)aρ(α), join introduction and elimination make ρ(P)ρ(α) mutually subtype ρ(α). Conversely, for an arbitrary eliminated image T, set ρ(α)=ρ(P)T. The freshness assumption makes ρ(P)=ρ(P), so the lower bound holds. Structural induction, reversed in arrow domains and closed by guarded coinduction at a μ-back edge, gives the second equality. ◻

Lemma 19.7 — Guarded recursive atomic elimination preserves instances

Suppose every occurrence of α in N, respectively in P+, is guarded by an arrow. For every polar scheme S, the recursive upper action, respectively lower action, of (19.3) satisfies Inst(S{αaN})=Inst(θαaN(S)),Inst(S{Paα})=Inst(θPaα(S)).

Proof of Lemma 19.7 — Guarded recursive atomic elimination preserves instances

Proof. Represent the guarded types by their finite polar automata. For the upper action, merge the negative face of α with a meet state containing the old face and the root of N; for the lower action, merge the positive face with the corresponding join state for P. These are exactly the two finite graphs denoted by (19.3).

For each finite head-and-edge path, induction on its length gives the same two inclusions as the nonrecursive proof: meet introduction and elimination handle an upper return, while join introduction and elimination handle a lower return. A path that returns to the merged face has crossed an arrow by guardedness, so the induction hypothesis applies after that constructor. Equality on all finite paths yields mutual subtyping of the regular unfoldings by guarded coinduction. Applying the argument at every occurrence in S, and reversing it in arrow domains, gives both displayed equalities after upward closure. ◻

Exercise 19.2 — Lower-bound elimination

★★☆ Reconstruct the lower-bound half of lemma 19.6 without citing order duality. State the two instantiations explicitly and identify where PT is used.

Definition 19.8 — Biunification work list

Constraints have the one sorted form c=P+aN. The partial decomposer subB0 is subB0((N1P1)a(P2N2))={P2aN1, P1aN2},subB0(b+ab)=,subB0((P1P2)aN)={P1aN, P2aN},subB0(Pa(N1N2))={PaN1, PaN2},subB0(aN)=,subB0(Pa)=,subB0((μα.P)aN)={P[μα.P/α]aN},subB0(Paμα.N)={PaN[μα.N/α]}. It is undefined for unequal rigid atoms and for every other head mismatch. In particular, arrow decomposition compares the positive domain P2 with the negative domain N1, and the positive codomain P1 with the negative codomain N2.

Let C be a finite work sequence and H a finite set of visited constraints; commas concatenate work sequences. The syntactic algorithm B0 is the following partial recursive function, where an omitted side condition falls through to the next equation: B0(H;)=id,B0(H;c,C)=B0(H;C)cH,B0(H;α+aα,C)=B0(H;C),B0(H;α+aN,C)=B0(θH;θC)θθ=θαaN,B0(H;Paα,C)=B0(θH;θC)θθ=θPaα,B0(H;c,C)=B0(H{c};subB0(c),C)subB0(c) is defined. If no equation applies, B0 fails. This syntax-tree presentation is partial: visited pairs stop direct recursive unfolding, but substitutions can still grow syntax. The terminating implementation below runs the same transitions on finite type automata.

For example, the work list {(αβ+)a(Int+Bool)} first becomes {Int+aα, β+aBool}. Lower-bound elimination changes only positive uses of α; upper-bound elimination changes only negative uses of β.

Lemma 19.9 — One work-list step is equisatisfiable

Every successful decomposition step preserves the solution set. Every atomic-elimination step preserves the upward-closed instance set of every attached polar scheme.

Proof of Lemma 19.9 — One work-list step is equisatisfiable

Proof. Arrow inversion gives (N1P1)a(P2N2)P2aN1  P1aN2. The lattice universal properties give the join-left and meet-right cases. Top and bottom cases follow from their bounds. Equal rigid heads discharge; unequal rigid heads have no solution in this frozen grammar. Nonrecursive atomic cases are lemma 19.6. Guarded recursive atomic cases are lemma 19.7. ◻

Inference, termination, and principality

Definition 19.10 — Finite polar type automata

A local polar type automaton is a finite directed graph with a positive or negative polarity on each state, a finite head set at each state, and domain and range edges. The head alphabet is H0={Unit,Bool,Int,String,arr}. An arrow state has one domain edge, which reverses polarity, and one range edge, which preserves it. A positive join and a negative meet take the union of the corresponding head sets and transitions. A guarded μ-binder adds a back edge; guardedness ensures that every cycle crosses an arrow edge. Variables are distinguished states until an atomic elimination merges a variable face with a bound graph.

The procedure B^0 starts from the automata for a finite constraint set and keeps a table of visited positive–negative state pairs. On an unvisited pair it performs exactly the transitions of (19.5)(19.6): it follows reversed domain edges and aligned range edges, distributes a positive join or negative meet, discharges equal rigid heads, fails on unequal rigid heads, and realizes an atomic action by graph merging. A graph merge changes edges but creates no state. The returned quotient graph determines an idempotent bisubstitution. This finite graph procedure, not the partial syntax-tree recursion, is the total local solver.

Theorem 19.11 — Local biunification

Let C be a finite set of sorted MLsub0 constraints, and let its automata have n states and m transitions.

  1. B^0(C) terminates after visiting at most n2 positive–negative state pairs, with worst-case work O((n+m)2).

  2. If it returns ξ, then ξ is stable and, for every polar scheme S, Inst(SC)=Inst(ξ(S)).

  3. It fails if and only if no substitution satisfies every constraint in C.

Proof of Theorem 19.11 — Local biunification

Proof. First compare a type with its graph. Induction on an acyclic unfolding shows that equal head languages give mutual subtyping: equal rigid letters use reflexivity; arrow letters use contravariance on domain edges and covariance on range edges; union at a positive state and union at a negative state use the join and meet universal properties, respectively. For a back edge, apply the same argument to one guarded unfolding. Every recurrence crosses an arrow, so guarded coinduction closes the comparison. Conversely, head inversion shows that mutual subtyping cannot change a rigid letter or exchange an arrow head with a rigid head. Thus two same-polarity local types mutually subtype exactly when their automata accept the same head-and-edge language.

Maintain the invariant that the unvisited state pairs are precisely the remaining positive-to-negative constraints. Arrow, join, meet, top, bottom, and rigid-head transitions preserve their solution set by lemma 19.9. An atomic graph merge applies (19.3). Thus lemma 19.6, lemma 19.7 preserve the instance set. Composition preserves (19.7); quotienting merged variable states makes the final action idempotent, and the merge orientation gives ξ(α)aξ+(α).

A failed transition exposes two unequal rigid heads or an arrow/rigid head mismatch. Head inversion makes either constraint unsatisfiable under every substitution. If no failure is exposed, the quotient action satisfies every visited pair by the invariant, so it is a solution. This proves both directions of clause 3. Finally, a merge creates no state and each recursive call marks a fresh pair. There are at most n2 pairs; iterating over their incident transitions gives the stated quadratic bound. This is the finite-head instance of the automaton argument in [DM17]; the rigid-letter cases above are local and require no record encoding. ◻

Definition 19.12 — Polar inference

Before combining subterms, rename their generalized type variables apart. A use of x^ takes a fresh copy of Π(x^). The local partial algorithm P0(Π;e) has the following equations: P0(Π;x^)=fresh(Π(x^)),P0(Π;x)=[x:α]α+,αFV(Π),P0(Π;())=[]Unit+,P0(Π;q)=[]Bool+,q{true,false}. If P0(Π;e)=[Δ]P+, then P0(Π;λx.e)=[Δx](Δ(x)P)+. where Δ(x)= when x is absent. Let inference is P0(Π;e1)=S1=[Δ1]P1+,P0(Π,x^:S1;e2)=[Δ2]P2+,P0(Π;let x^=e1 in e2)=[Δ1Δ2]P2+. For application, choose β fresh for both subterm schemes and compute P0(Π;ei)=[Δi]Pi+(i=1,2),ξ=B^0({P1+a(P2+β)}),P0(Π;e1e2)=ξ([Δ1Δ2]β+). For a conditional, infer [Δi]Pi+ for the condition and two branches, with index i=0,1,2, and compute ξ=B^0({P0+aBool}),P0(Π;if e0 then e1 else e2)=ξ([Δ0Δ1Δ2](P1+P2+)). If a solver call fails, the corresponding inference equation is undefined. Language-preserving automaton minimization may follow a successful call.

The lambda-bound dependency matters. In λf.λu.λv.let g^=λx.if fx then x else x in if true then g^u else g^v, the type of g^ depends on the type assigned to f. Generalizing that dependency would allow the two uses of g^ to assume unrelated domains and would invalidate the enclosing typing.

Theorem 19.13 — Principal inference for MLsub_0

For every finite Π and term e, P0(Π;e) terminates. It fails exactly when no scheme S satisfies Π0e:S. If it returns S0, then Π0e:SS0S. Thus S0 is sound, complete, and principal up to mutual scheme subsumption, not literal equality of type syntax.

Proof of Theorem 19.13 — Principal inference for MLsub_0

Proof. Proceed by structural induction on e. A lambda-bound variable introduces one fresh pair of faces, and a let-bound variable takes a renamed copy of its stored scheme, so (19.13) is exactly Var-Lam or Var-Let followed by Sub. Unit and Boolean constants use their corresponding rules.

For abstraction, the induction hypothesis factors every body typing through [Δ]P+. Deleting x and placing Δ(x) in the arrow domain turns the environment comparison in (19.1) into arrow contravariance. This is exactly the premise and conclusion of Abs; the convention Δ(x)= handles an unused parameter.

For application, the two induction hypotheses factor the function and argument typings through their inferred schemes. Such instances form an App premise exactly when they satisfy P1+a(P2+β) for some result face β. By theorem 19.11, applying ξ in (19.11) replaces that constrained instance set by the equal unconstrained instance set. The pointwise meet records both lambda-bound environments. Hence the result is sound and every declarative application factors through it.

For a conditional, the same solver argument converts the condition constraint to an unconstrained scheme. Join is the least common result supertype, and the three-way environment meet records all dependencies, proving both directions of (19.13). For let, the induction hypothesis for e1 gives the scheme stored for x^; the hypothesis for e2 then factors every use of that fresh scheme. Rule Let combines exactly the two negative environments. These cases cover the term grammar. Each recursive inference call is on a proper subterm, and every solver call terminates by theorem 19.11, so P0 terminates. Solver failure is unsatisfiability, which proves the failure clause. ◻

Theorem 19.14 — Richer MLsub inference boundary; exact import

For the MLsub calculus, polar schemes, guarded equi-recursive types, and biunification algorithm of Dolan–Mycroft:

  1. a returned bisubstitution is stable and solves the input constraints (Theorem 8), while failure implies unsatisfiability (Theorem 9);

  2. the automaton implementation terminates; for n states and m transitions its worst-case work is O((n+m)2);

  3. polar inference is sound, complete, and principal for that MLsub signature; and

  4. equality of same-polarity types is equality of the languages accepted by their type automata (Theorem 10), so language-preserving minimization retains the inferred scheme’s instances.

Proof of Theorem 19.14 — Richer MLsub inference boundary; exact import

Proof. Items 1, 2, and 4 are imported from [DM17]. The principality construction is the paper’s Section 4 inference development, with the complete principality statement and preorder equivalence given in [Dol17]. Its mechanism uses stable atomic actions on the two polar faces. The full source proof, not the local one-step lemma, establishes their most-generality and the induction that factors a declarative typing through the returned polar scheme. The let case retains the negative-environment dependencies named in definition 19.12. Termination is proved only after types are finite automata: every recursive call marks a previously unvisited pair of states, and there are at most n2 pairs. ◻

Guardedness is substantive. Without it, a recursive type can contain an unguarded self-loop that contributes no constructor transition, so the finite-state descent used by both the semantic interpretation and the algorithm is not the stated one. Polarity is also substantive: replacing a variable on both faces reproduces the over-restricted type at the chapter’s opening.

Exercise 19.3 — A compact principal type

★★☆ Infer a polar scheme for λb.λx.λy.if b then x else y. Show where the join occurs, and give two incomparable ordinary ML arrow types that are instances of the result.

MLstruct is a separate Boolean system

Adding complement changes the semantic problem. A complement is not a negative face of an MLsub variable: it denotes the values outside a type. The 2022 MLstruct calculus has its own structural records, class tags, unions, intersections, complement, and inference judgment. Its soundness, completeness, and principality claims belong only to that frozen signature [PC22]; they are not instances of theorem 19.14.

Definition 19.15 — Boolean-algebraic comparison signature

The comparison calculus BAS0 has T::=01αTTTT¬TTTμα.T. Subtyping is semantic inclusion in the paper’s tagged-value model, and equi-recursive types satisfy the paper’s contractiveness condition. This is the MLstruct+ signature of Chau–Parreaux, not MLsub0, the 2022 MLstruct calculus, or Simple-sub.

In BAS0, T¬T denotes 0 and T¬T denotes 1. Neither equation exists in MLsub0, whose meets and joins are polarity-indexed constructors rather than a single complemented Boolean algebra.

Theorem 19.16 — Boolean comparison boundary; exact import

For the contractive MLstruct+ signature of definition 19.15, characteristic Boolean homomorphisms give the paper’s semantic-soundness characterization and terminating subtyping decision procedure. The theorem makes no claim about MLsub, the 2022 MLstruct calculus, or Simple-sub.

Proof of Theorem 19.16 — Boolean comparison boundary; exact import

Proof. Import the characterization, soundness theorem, and decision procedure from [CP26]. Their domain, recursive-type contractiveness, and characteristic homomorphisms are hypotheses of this statement. No translation from MLsub polar schemes to that model has been given, so there is no premise by which theorem 19.14 could be transported. ◻

Simple-sub gives a shorter graph propagation algorithm and valuable implementation examples. Its randomized agreement tests are evidence about its implementation, not a proof that its calculus and MLsub have identical principal schemes [Par20].

Exercise 19.4 — Do not transfer the theorem

★☆☆ Classify each phrase as belonging to MLsub0, BAS0, both, or neither: polar bisubstitution; Boolean complement; guarded equi-recursion; principal polar scheme; characteristic Boolean homomorphism. For every “both” answer, state the different role in each signature.

Suggested first pass.

None of these problems is a prerequisite for a later chapter. Begin with exercise 19.5, then implement exercise 19.7.

Exercise 19.5 — Biunification trace

★★☆ Trace B0 on (αβ+)a((IntBool)+(Stringγ)). List the work set after arrow decomposition and give the positive and negative images of each variable after atomic elimination.

Exercise 19.6 — Why equality loses programs

★★☆ Give one satisfying assignment of the directed constraints from exercise 19.5 that ordinary equality unification rejects. Then give one equality solution and show that it is a special instance of the biunification result.

Exercise 19.7 — Finite polar constraint solver

★★★ Practical project.polar-biunification Implement the nonrecursive finite polar constraint fragment in Kappa: variables, top, bottom, arrows, joins, meets, constraint decomposition, and occurs-checking atomic elimination. Preserve the invariant that every queued constraint has positive left and negative right polarity. The finished program must solve an upper bound, solve a lower bound, decompose an arrow, reject a rigid mismatch, and reject a self-occurrence that this nonrecursive executable fragment does not solve with a guarded μ-action. Its decidable acceptance test also rejects a constraint between distinct variables instead of silently discarding it. The exact five-case output is in appendix E; Kappa audit must return an empty list.

Exercise 19.8 — A Boolean non-translation

★★★ Assume a translation t sends MLsub joins and meets to Boolean joins and meets. Prove that extending it by the equation t(¬T)=¬t(T) is not yet a translation of typing schemes: identify the missing operation on negative environments and the missing preservation theorem for instantiation. Give a concrete Boolean equation whose source counterpart is not formed in MLsub0.

Search the book

Type to search the local edition.