Lectures onType Theory
ch:hindley-milner: ch:hindley-milner
appendix sectionsolutions

ch:hindley-milner: ch:hindley-milner

Exercise 3.1.

For (a), first alpha-rename the quantified variables so that all prefixes are disjoint. The substitution [γ/α,γ/β] sends the body αβ to γγ. By lemma 3.9, αβ.αβγ.γγ.

For (b), the relation fails. An instance of αβ.αβ may have unequal domain and codomain, for example NatBool. Every instance of γ.γγ has identical domain and codomain, so no instantiation produces that arrow.

For (c), the free δ is fixed and [δ/α](αδ)=δδ. Hence α.αδδδ.

For (d), alpha-rename the scheme on the right to ϵ.ϵϵ, with ϵ fresh. If the generality relation held, the characterization lemma would give a monotype ρ with ρδ=ϵϵ. Constructor injectivity would force both ρ=ϵ and δ=ϵ. The latter is impossible: δ is free and fixed on the left, whereas ϵ is the freshly bound variable on the right. Thus the relation in (d) fails.

Exercise 3.2.

The arithmetic context has no free type variables. Therefore GenΓ0((αα)αα)=α.(αα)αα,GenΓ0,f:αβ(α(βγ)γ)=γ.α(βγ)γ. In the second line, α and β are free in the context and only γ is generalized.

For (c), ftv(α.αβ)={β},ftv(Γ0,f:α.αβ)={β}. The α in the proposed result type is therefore not fixed by the context, and GenΓ0,f:α.αβ(αβ)=α.αβ.

For the requested instance of lemma 3.15, start from (b) and S=[Nat/α]. Rename the generalized variable γ to a fresh γ before applying S: T=[γ/γ];S. Then T agrees with S on the free variables α,β of the context, Γ[T]=Γ[S]=Γ0,f:Natβ, and GenΓ[S](τ[T])=γ.Nat(βγ)γ. On the other hand, GenΓ(τ)[S]=γ.Nat(βγ)γ. The two schemes are alpha-equivalent, so the required generality relation holds, in fact in both directions.

Exercise 3.3.

For (a), use two monomorphic assumptions and then generalize. Written one rule application per line, the complete derivation is Γ0,x:α,y:βx:α(Var),Γ0,x:αλy.x:βα(Lam),Γ0λx.λy.x:αβα(Lam),Γ0λx.λy.x:αβ.αβα(Gen α,β). Both side conditions hold because Γ0 has no free type variables.

For (b), let σid=α.αα. The bound expression has that scheme by Var, Lam, and Gen. In the body, two independent Inst steps give Γ0,id:σidid:(ββ)(ββ),Γ0,id:σidid:ββ. Rule App combines them: Γ0,id:σididid:ββ. Together with the typing of the bound identity, Let yields Γ0let id=λx.x in idid:ββ. Finally βftv(Γ0), so one Gen step proves part (c): Γ0let id=λx.x in idid:β.ββ.

Exercise 3.4.

Give the lambda-bound variables types αf,αg,αx. Give gx the fresh result type β and f(gx) the fresh result type γ. The two application nodes force exactly αgαxβ,αfβγ. Eliminating αg and αf gives the MGU U=[αxβ/αg,βγ/αf]. The provisional type of the three lambdas is αfαgαxγ; applying U gives (βγ)(αxβ)αxγ. All three remaining variables are absent from Γ0. Renaming αx to α and generalizing gives αβγ.(βγ)(αβ)αγ.

exercise 3.5.

Let E0 be the printed two-equation list. Decomposition and elimination produce the following complete sequence: E0:=((αβ)γ(NatBool)δ,δNat),E1:=UDecomposeontheouterarrows(αβNatBool,γδ,δNat),E2:=UDecomposeonαβ(αNat,βBool,γδ,δNat),R1:=UEliminateforα[Nat/α],E3:=tailofE2[R1](βBool,γδ,δNat),R2:=UEliminateforβ[Bool/β],E4:=tailofE3[R2](γδ,δNat),R3:=UEliminateforγ[δ/γ],E5:=tailofE4[R3](δNat),R4:=UEliminateforδ[Nat/δ],E6:=(). The algorithm returns, in diagrammatic order, R1;R2;R3;R4. It sends α,γ,δ to Nat and β to Bool. If the last initial equation is δδNat, the same two decompositions apply. The factors R1 and R2 do not mention δ, and R3 changes only γ, so that last equation remains δδNat. Since δ occurs properly on its right, U-Eliminate is forbidden and the occurs-check failure clause applies.

exercise 3.6.

Give f the fresh type α and x the fresh type β. The innermost application introduces fresh γ and solves αβγ,S1=[βγ/α]. For the middle application, fresh δ stands for the result. After applying S1, its ordered equation is βγγδ. Left-to-right decomposition produces (βγ,γδ). The first elimination is [γ/β]; it leaves γδ, whose elimination is [δ/γ]. Thus the deterministic composite is S2=[γ/β];[δ/γ]=[δ/β,δ/γ]. Applying S1;S2 to the provisional lambda type αβδ already yields the twice-shaped type. The third, outermost application introduces fresh ϵ and solves α[S1;S2]δϵ,δδδϵ. Decomposition deletes the reflexive domain equation and returns S3=[ϵ/δ]. Applying the full composite to the provisional lambda type αβϵ yields (ϵϵ)ϵϵ. Since ϵ is absent from Γ0, generalization returns ϵ.(ϵϵ)ϵϵ. The third use of f forces only the already-known equality of its input and output type, so the principal scheme is the same as for twice.

Exercise 3.7.

Write the scheme inferred for compose as C=αβγ.(βγ)(αβ)αγ. The let-bound definition is generalized to C. In the body cc, take two disjoint fresh instances: C1=(β1γ1)(α1β1)α1γ1,C2=(β2γ2)(α2β2)α2γ2. If ρ is the fresh result type of the application, W solves C1C2ρ. Arrow decomposition first gives β1γ1C2,ρ(α1β1)α1γ1. Decomposing the first equation gives the MGU components β1β2γ2,γ1(α2β2)α2γ2. Thus the body has monotype (α1β2γ2)α1(α2β2)α2γ2. The four displayed variables are generalized over Γ0.

The corresponding explicitly instantiated core term is let c:C=λ(f:βγ).λ(g:αβ).λ(x:α).f(gx) incα1,β2γ2,(α2β2)α2γ2cα2,β2,γ2. The first static instance is precisely the function type required to accept the second instance as its first argument. Erasing annotations and type arguments returns the source term.

Exercise 3.8.

Work under d:α,xs:β. The list clause chooses fresh γ. The scrutinee call returns (id,β), and the first equation is βList(γ). Its MGU is U=[List(γ)/β]. The nil branch is the variable d, so it returns (id,α). The cons branch is checked under d:α,xs:List(γ),h:γ,t:List(γ). Its body is h, so it returns (id,γ). The final branch equation is αγ, with V=[γ/α]. Hence the list clause returns (U;V,γ),β[U;V]=List(γ),α[U;V]=γ. The two enclosing lambda clauses therefore return γList(γ)γ. Over the empty context, generalization gives γ.γList(γ)γ, which is the scheme in example 3.38, up to renaming.

exercise 3.9.

The allocation expression receives Ref(αα). Since it is not a generalizable form, Let-Mono binds r:Ref(αα) with the same free α. Typing r:=(λx.succx) produces Ref(αα)Ref(NatNat), so unification fixes α=Nat. Dereferencing r therefore returns a function of type NatNat, while the final application to true demands the equation NatBool. Its distinct nullary constructors trigger the clash rule. By contrast, λx.x is a generalizable form, so Let-Gen still assigns it α.αα.

Exercise 3.10.

In the first example, λf.let n=fzero in ftrue, rule Lam puts one monotype for f in the context. The first application requires its domain to be Nat, while the second requires the same domain to be Bool. The rigid mismatch prevents a derivation. In an explicitly typed extension, the binder would be f:α.αα, and the two occurrences would be written fNatzero and fBooltrue. A value supplied for f could be the explicit abstraction Λα.λ(x:α).x.

The second example asks for an arrow whose domain is itself α.αα. The monotype grammar of definition 3.6 has no constructor, so such an arrow is not an HM monotype and cannot annotate a lambda-bound variable. In an extended syntax the binder carries that polymorphic annotation, and each use again contains an explicit type application such as fNatzero.

The third example fails at instantiation. HM’s Inst substitutes monotypes for quantified variables, but α.αα is a scheme rather than a monotype. Hence the identity cannot be instantiated at its own polymorphic type. The displayed extended term places that scheme in an explicit type-application bracket and uses Λ at the two polymorphic values. In all three cases those annotations and applications are part of the extended source program; Algorithm W does not infer them.

Exercise 3.11.

The variable φ is inherited from the declaration of f and is free in the input context. To infer the definition of k, W gives x a fresh type α. The body f has type φ, so λx.f:αφ. Generalization is relative to Γ0,f:φ: ftv(αφ)ftv(Γ0,f:φ)={α,φ}{φ}={α}. Thus the let-bound declaration is k:α.αφ.

At the occurrence kzero, instantiate the prefix by a fresh β, obtaining k:βφ. If γ is the fresh application-result variable, unification solves βφNatγ with the deterministic eliminations [Nat/β] and [γ/φ]. The complete term therefore has result type γ. Up to identity action on the other fresh variables, W’s principal pair is ([Nat/β,γ/φ],γ). Thus the returned substitution renames the inherited context parameter φ to the fresh result parameter γ. This is still principal: the factor [φ/γ] recovers every typing over the original context, exactly as theorem 3.36, corollary 4.49 state. The fresh variables are α for the definition, β for the independent use of its scheme, and γ for the application result.

Exercise 3.12.

Process the equations first in their printed order. Eliminating α, then β, then γ produces the factors R1=[βγ/α],R2=[Nat/β],R3=[δ/γ]. The returned composite U1=R1;R2;R3 acts on the problem variables by α[U1]=Natδ,β[U1]=Nat,γ[U1]=δ,δ[U1]=δ.

Now process (γδ,βNat,αβγ). The factors occur in the different order R1=[δ/γ],R2=[Nat/β],R3=[Natδ/α], and U2=R1;R2;R3. Direct calculation gives the same four images as for U1. Thus U1={α,β,γ,δ}U2;id,U2={α,β,γ,δ}U1;id. Although the lists of elimination factors differ, the two returned substitutions mutually factor on every problem variable. More generally, the MGU theorem gives such factors even when different legal traversals choose different variable representatives, so the solution family does not depend on the work-list order.

Exercise 3.13.

Give the identity value the monotype αα. Allocation then has type ref(λx.x):Ref(αα). The allocation is expansive, so the first binding must use Let-Mono; it introduces r:Ref(αα) with no generalized variable.

The expression bound to s is the variable r, hence it is nonexpansive and the generalized let rule is syntactically available. Nevertheless α occurs free in the surrounding declaration of r, so GenΓ0,r:Ref(αα)(Ref(αα))=Ref(αα). The prefix is empty. Thus the whole term has the same monomorphic reference type.

Operationally the first binding allocates one location containing the identity. The second let reduces by substituting that existing location: let r= in let s=r in s0let s= in s0. No second cell is allocated. Hence r and s are aliases and must share the one monomorphic store type assigned to .

Exercise 3.14.

The only monotype instance of Nat is Nat itself. Instantiating the vacuous prefix in α.Nat also always returns Nat, because α does not occur in the body. Therefore each scheme is at least as general as the other, although they are not alpha-equivalent: alpha-renaming may change a bound name but cannot add or remove a quantifier.

Consequently principality is uniqueness in the preorder of generality, or uniqueness after quotienting by equality of instance sets, not uniqueness of literal printed syntax. A canonical printing convention removes this example by deleting every vacuous quantifier, equivalently by permitting in a prefix only variables that occur free in the scheme body. The definition of Gen already follows that convention.

Exercise 3.15.

The bound application is pure and reduces to the identity, but it is not a generalizable form. Under the conservative restriction it is therefore checked by Let-Mono. Give the resulting identity the single monotype αα and introduce i at that monotype.

The first use, izero, generates ααNatβ, so unification sets α=Nat and β=Nat. The inner binding of n does not change the type of i. The final use itrue then requires NatNatBoolγ, whose domain equation NatBool is a rigid mismatch. That is the exact rejection.

A sound effect analysis could certify that evaluation of (λf.f)(λx.x) neither allocates a reference nor reads, writes, or otherwise mutates shared state. It could then generalize its result to α.αα, allowing the two uses to receive independent Nat and Bool instances. The same analysis must refuse that certificate for Pref: its bound expression performs allocation, and the later assignment mutates the allocated cell. Thus the effect-based relaxation accepts the pure application without reintroducing polymorphic references.

Practical route.

The inferencer requested by exercise 4.16 is built in appendix F; its exact Kappa acceptance oracle is recorded in appendix E.

Search the book

Type to search the local edition.