Lectures onType Theory
ch:simple-types: ch:simple-types
appendix sectionsolutions

ch:simple-types: ch:simple-types

Exercise 2.1.

The inserted conditional has free variable y, so rename the displayed binder to a fresh u before substituting: (λy:2.if(x;y;x))[if(y;tt;ff)/x]=α(λu:2.if(x;u;x))[if(y;tt;ff)/x]=λu:2.if(if(y;tt;ff);u;if(y;tt;ff)). The two displayed occurrences of y, one in each inserted copy, are free; the binder binds only u.

For the second term, the binder shadows the substitution variable. The stopping equation for substitution therefore gives (λx:2.x)[tt/x]=λx:2.x, not λx:2.tt. Substitution replaces free occurrences only.

Exercise 2.2.

Let Γ=x:2,y:2. The full derivation for or is (x:2)ΓΓx:2VarXΓtt:2True(y:2)ΓΓy:2VarΓif(x;tt;y):2Ifx:2λy:2.if(x;tt;y):22Lamor:222Lam.

Take xor:=λx:2.λy:2.if(x;if(y;ff;tt);y). Its body derivation is the complete tree X=(x:2)ΓΓx:2Var(y:2)ΓΓy:2VarXΓff:2FalseXΓtt:2TrueΓif(y;ff;tt):2If(y:2)ΓΓy:2VarΓif(x;if(y;ff;tt);y):2If. The two abstraction nodes complete the typing derivation: Xx:2λy:2.if(x;if(y;ff;tt);y):22Lamxor:222Lam.

Exercise 2.3.

Any typing of if(λx:2.x;tt;ff) must end in If. Its guard premise would require Γλx:2.x:2. But the only final rule for an abstraction is Lam, whose result type is an arrow, here 22, never 2. Thus the guard premise fails.

Any typing of ff(λx:2.x) must end in App. Its function premise requires Γff:AC for some A,C. The only final rule for ff is False, which assigns 2, not an arrow. Hence that premise fails in every context.

Exercise 2.4.

Renaming the three variable leaves and rebuilding the conditional gives (y:2)y:2y:2y:2Var(y:2)y:2y:2y:2VarXy:2ff:2Falsey:2if(y;y;ff):2If. Every node is the image of the corresponding node in the original tree.

The premise in example 2.6 is displayed under x:2. Renaming x to fresh u gives u:2u:2u:2u:2VarXu:2ff:2FalseXu:2tt:2Trueu:2if(u;ff;tt):2If. Applying Lam produces λu:2.if(u;ff;tt), which is alpha-equivalent to the original λx:2.if(x;ff;tt).

Exercise 2.5.

Let a=if(tt;ff;tt). The two premise derivations for typed substitution are x:2x:2,y:2x:2,y:2x:2Vary:2x:2,y:2x:2,y:2y:2VarXx:2,y:2ff:2Falsex:2,y:2if(x;y;ff):2Ifx:2λy:2.if(x;y;ff):22Lam, and Xtt:2TrueXff:2FalseXtt:2Truea:2If. Weakening the second tree inserts y:2, giving the same If tree with all three constant conclusions under y:2; call it Ay:y:2a:2. Substitution replaces the first guard leaf, while the y-leaf and false branch remain: Ayy:2y:2y:2y:2VarXy:2ff:2Falsey:2if(a;y;ff):2Ifλy:2.if(a;y;ff):22Lam. The first premise of the rebuilt If is precisely the weakened inserted derivation.

Exercise 2.6.

For guard congruence, typing inversion and the induction hypothesis transform the tree as follows: Γe:2Γe1:CΓe2:CΓif(e;e1;e2):CIf When ee, the induction hypothesis changes the first premise and the rebuilt tree is Γe:2Γe1:CΓe2:CΓif(e;e1;e2):CIf. All three premises of the rebuilt rule are displayed.

For the two root contractions, inversion already contains the selected branch: Γtt:2Γe1:CΓe2:CΓif(tt;e1;e2):CIfΓe1:C, Γff:2Γe1:CΓe2:CΓif(ff;e1;e2):CIfΓe2:C. Both arrows are metalevel transformations of derivation trees, not term steps. Thus every conditional rule preserves the result type C.

Exercise 2.7.

The complete derivation is the zero-premise introduction instance Xx:A:1UnitI. If a closed value v has type 1, inspect its value form and invert its typing. A lambda has an arrow type, a Boolean has type 2, a pair has a product type, and an injection has a sum type. Disjointness of type constructors excludes all four possibilities, leaving v=.

Exercise 2.8.

For A type, the required derivation is (x:0)(x:0,y:A)x:0,y:Ax:0VarA typeX2 typeTyBoolA×2 typeTyProdx:0,y:AabortA×2(x):A×2EmptyE. Abort is not a value form. Its only evaluation rule is E-Abort, whose premise would require a step from the variable x; no evaluation rule has a variable source. Hence this open neutral term has no root or congruence step.

Exercise 2.7.

Recall Color=1+(1+1), with red the outer left injection, amber the outer-right/inner-left injection, and green the outer-right/inner-right injection. Abbreviate K(u):=case(u;a.red;g.amber),L(c):=case(c;r.green;u.K(u)), and define next:=λc:Color.L(c). For any context Θ, let RΘ, AΘ, and GΘ be the following complete constructor derivations. Here U is the axiom 1 type, while S is Ty-Sum applied to two copies of U, deriving 1+1 type: RΘ=XΘ:1UnitISΘred:ColorInl, AΘ=UXΘ:1UnitIUΘinl():1+1InlΘamber:ColorInr, and GΘ=UUXΘ:1UnitIΘinr():1+1InrΘgreen:ColorInr. Put Γ=c:Color and Δ=Γ,u:1+1. These constructor trees make every premise in the typing derivation explicit: (c:Color)ΓΓc:ColorVarGΓ,r:1(u:1+1)ΔΔu:1+1VarRΔ,a:1AΔ,g:1ΔK(u):ColorCaseΓL(c):ColorCasenext:ColorColorLam.

The reductions are nextredL(red)green,nextamberL(amber)K(inl())red,nextgreenL(green)K(inr())amber. The first step of each line is beta; the remaining steps are the appropriate case contractions.

exercise 2.8.

For the right contraction, inversion of the typing derivation before the step gives Γinr(v):A+B,Γ,x:Ae1:C,Γ,y:Be2:C. Inverting the injection premise gives Γv:B. The source of the complete derivation transformation is A typeΓv:BΓinr(v):A+BInrΓ,x:Ae1:CΓ,y:Be2:CΓcase(inr(v);x.e1;y.e2):CCase. Its target is Γ,y:Be2:CΓv:BΓe2[v/y]:CSubstitution. This is a metalevel transformation of derivation trees, not a term evaluation step. For scrutinee congruence, inversion gives Γe:A+B and the same two branch premises. The induction hypothesis changes the first premise to Γe:A+B; reapplying Case yields Γcase(e;x.e1;y.e2):C.

Exercise 2.9.

Let a=(λy.y)tt. Call by value evaluates the argument first: (λx.xx)av(λx.xx)ttvtttt. The endpoint is stuck because its function is a boolean value rather than an abstraction.

Call by name substitutes the unevaluated argument twice and then evaluates the function position: (λx.xx)anaantta. This endpoint is stuck; call by name has no context that evaluates the argument after a nonlambda function has become final.

If x:X typed xx:C, App would require the function occurrence to have DC and the argument occurrence to have D. Both occurrences refer to the same declaration, so uniqueness of types gives X=DC and X=D, hence D=DC. No finite type tree is equal to a proper arrow tree containing itself as a subtree, so no simple type solves these equations.

exercise 2.10.

Put F=AB, G=BC, T=FG(AC), and Δ=f:F,g:G,x:A. The complete natural-deduction tree is g:GΔΔNGHypf:FΔΔNFHypx:AΔΔNAHypΔNBΔNCf:F,g:GNACf:FNG(AC)NT. Decorating the three Hyp leaves by variables, the two elimination nodes by App, and the three discharge nodes by Lam gives the complete typing tree for λf:AB.λg:BC.λx:A.g(fx). Every node in this arrow-only example has the corresponding typing node and there are no extra formation premises. Skeleton erasure therefore recovers the displayed natural-deduction tree node for node.

Exercise 2.11.

Let F be the proof term from example 2.35. The injection inl(a) has type A+B because a:A and B is a formed type. Write p0=(f,g). Compatible proof reduction gives Fp0inl(a)prootbeta(λs:A+B.case(s;x.fst(p0)x;y.snd(p0)y))inl(a)prootbetacase(inl(a);x.fst(p0)x;y.snd(p0)y)prootcaseLfst(p0)aprootfstfa. The first beta step occurs compatibly in function position of the outer application. The second is the outer application itself. Subject reduction assigns type C to every displayed line: f:AC, g:BC, and a:A are unchanged throughout.

exercise 2.12.

Suppose eRA×B and epe. By definition, fst(e)RA and snd(e)RB. The proof contexts fst([]) and snd([]) give fst(e)pfst(e),snd(e)psnd(e). Reduction closure at A and B gives both defining conditions for eRA×B.

Now let aRA and bRB. Saturation clause 1 makes both strongly normalizing. The root contractions fst((a,b))pa,snd((a,b))pb have reducible contracta and strongly normalizing proper arguments. Principal expansion makes the two projections reducible, and the product clause gives (a,b)RA×B.

Exercise 2.13.

The two identity derivations are (x:2)x:2x:2x:2Varid2:22Lam, and (x:1)x:1x:1x:1Varid1:11Lam. One term using each twice is ((id2tt,id2ff),(id1,id1)), of type (2×2)×(1×1).

If one simply typed variable i replaced both definitions, its boolean uses would require i:22, while its unit uses would require i:11. Uniqueness of typing for a variable in a fixed context would identify these two arrow types, and arrow injectivity would then give 2=1, impossible. A single monomorphic declaration cannot serve both uses.

Exercise 2.14.

Extend the old evaluation contexts by E::=(E,e)(v,E)fst(E)snd(E)inl(E)inr(E)case(E;x.e1;y.e2)abortA(E). The side metavariable v ranges over values. The new basic redexes are the two projections of a value pair and the two case expressions whose scrutinee is a value injection.

We prove the value/redex/stuck trichotomy by structural induction on a closed term, without assuming that it is typed. A variable case is impossible by closedness; a Boolean, lambda, or the Unit constructor is a value. In an application, first apply the induction hypothesis to the function. Its step or stuck outcome lifts to the application. If it is a value, apply the hypothesis to the argument; an argument step or stuck outcome lifts, while two values form a beta redex exactly when the function is a lambda and otherwise form a stuck application. In a conditional, the guard’s step or stuck outcome lifts; a true or false guard determines its unique root contraction, and any other value guard makes the conditional stuck.

For a pair, decompose the left component first; only when it is a value decompose the right. If both are values, the pair is a value. In a projection, decompose the scrutinee. A value pair has the corresponding projection redex; every other value scrutinee makes the projection stuck. In an injection, decompose its payload; the injection becomes a value exactly when the payload does. In a case, decompose the scrutinee. A value left or right injection determines the corresponding contraction, while every other value scrutinee makes the case stuck. Abort decomposes its scrutinee; any value scrutinee makes the abort stuck. These clauses also propagate a stuck selected subterm to a stuck whole term.

For uniqueness, structural induction compares two proposed decompositions. The Unit constructor has no decomposition because it is already a value. In an application, the argument frame requires a value function, whereas the function frame contains a reducible function; a value has no step. The induction hypotheses make the selected function or argument decomposition unique, and a beta root has both subterms values, so it cannot overlap either nonempty frame. A conditional root has a Boolean value guard and cannot overlap its guard frame. In a pair, the right frame requires the left component to be a value, whereas the left frame requires that component to decompose; no value steps. A projection, injection, case, or abort has only the displayed frame for its outer constructor, and the induction hypothesis makes the selected child decomposition unique. At the empty context, projection and case roots are separated by their outer constructors, and the two case roots are separated because an injection cannot be both left and right. The outer constructor is disjoint from every redex and from every nonempty frame. A root redex cannot also have a nonempty decomposition: every subterm at an earlier selected position is a value, while plugging a basic redex into a context produces a step and no value steps.

These cases exhaust the grammar and establish exactly one of value, unique context-and-redex decomposition, or stuckness. If ee1 and ee2, both derivations therefore expose the same context and basic redex. Every basic redex has one contractum, and filling the common context yields e1=e2.

Exercise 2.15.

The substituend (x,y) has both x and y free. Freshen the left branch binder x to u, and the right branch binder y to v: case(z;x.(x,w);y.(w,y))[(x,y)/w]=αcase(z;u.(u,w);v.(w,v))[(x,y)/w]=case(z;u.(u,(x,y));v.((x,y),v)). The occurrences of x,y inside both inserted pairs are free, as is the scrutinee variable z; u,v are bound in their respective branches. Retaining the original left binder would bind the inserted x in that branch. Retaining the original right binder would similarly bind the inserted y. Both freshening steps are therefore necessary.

Exercise 2.16.

Define N:=λh:(A+B)0.(λa:A.hinl(a),λb:B.hinr(b)). Put H=h:(A+B)0, ΓA=H,a:A, and ΓB=H,b:B. The two component derivations are DA=(h:(A+B)0)ΓAΓAh:(A+B)0Var(a:A)ΓAΓAa:AVarB typeΓAinl(a):A+BInlΓAhinl(a):0Apph:(A+B)0λa:A.hinl(a):A0Lam. The right component is not left implicit: DB=(h:(A+B)0)ΓBΓBh:(A+B)0VarA type(b:B)ΓBΓBb:BVarΓBinr(b):A+BInrΓBhinr(b):0AppHλb:B.hinr(b):B0Lam. The remaining Pair and Lam nodes give the complete outer tree: DADBH(λa:A.hinl(a),λb:B.hinr(b)):(A0)×(B0)PairN:((A+B)0)((A0)×(B0))Lam.

For the converse define M:=λp:(A0)×(B0).λs:A+B.case(s;a.fst(p)a;b.snd(p)b). Let P=p:(A0)×(B0), Σ=P,s:A+B, ΣA=Σ,a:A, and ΣB=Σ,b:B. The complete branch trees are EA=PΣAΣAp:(A0)×(B0)VarΣAfst(p):A0Fst(a:A)ΣAΣAa:AVarΣAfst(p)a:0App, and EB=PΣBΣBp:(A0)×(B0)VarΣBsnd(p):B0Snd(b:B)ΣBΣBb:BVarΣBsnd(p)b:0App. Thus the case and abstraction nodes are E=(s:A+B)ΣΣs:A+BVarEAEBΣcase(s;a.fst(p)a;b.snd(p)b):0Case, EPλs:A+B.case(s;a.fst(p)a;b.snd(p)b):(A+B)0LamM:((A0)×(B0))((A+B)0)Lam.

On constructor inputs, with f:A0 and g:B0, put p0=(f,g). Then Mp0inl(a)prootbeta(λs.case(s;a.fst(p0)a;b.snd(p0)b))inl(a)prootbetacase(inl(a);a.fst(p0)a;b.snd(p0)b)prootcaseLfst(p0)aprootfstfa, while the other injection has its own complete trace Mp0inr(b)prootbeta(λs.case(s;a.fst(p0)a;b.snd(p0)b))inr(b)prootbetacase(inr(b);a.fst(p0)a;b.snd(p0)b)prootcaseRsnd(p0)bprootsndgb.

Exercise 2.17.

Define d:=λp:A×(B+C).case(snd(p);b.inl((fst(p),b));c.inr((fst(p),c))). In the other direction, define uB(q):=(fst(q),inl(snd(q))),uC(r):=(fst(r),inr(snd(r))). Then u:=λs:(A×B)+(A×C).case(s;q.uB(q);r.uC(r)). Product inversion gives fst(p):A and snd(p):B+C; the two branches of d have the common type (A×B)+(A×C). Conversely, each branch of u has type A×(B+C). The Case, Pair, projection, and injection rules therefore give the two advertised arrow typings.

Put pB=(a,inl(b)),qB=(a,b),pC=(a,inr(c)),qC=(a,c). For a fixed product term p, abbreviate the fully displayed case context by Dp(t):=case(t;b.inl((fst(p),b));c.inr((fst(p),c))), and put U(t):=case(t;q.uB(q);r.uC(r)). All contractions needed by both composites are the following four calculations: dpBpDpB(snd(pB))(root beta)pDpB(inl(b))(P-Ctx, K=DpB([]))pinl((fst(pB),b))(root caseL)pinl(qB)(P-Ctx, K=inl(([],b))),uinl(qB)pU(inl(qB))(root beta)p(fst(qB),inl(snd(qB)))(root caseL)p(a,inl(snd(qB)))(P-Ctx, K=([],inl(snd(qB))))ppB(P-Ctx, K=(a,inl([]))). For the right constructors: dpCpDpC(snd(pC))(root beta)pDpC(inr(c))(P-Ctx, K=DpC([]))pinr((fst(pC),c))(root caseR)pinr(qC)(P-Ctx, K=inr(([],c))),uinr(qC)pU(inr(qC))(root beta)p(fst(qC),inr(snd(qC)))(root caseR)p(a,inr(snd(qC)))(P-Ctx, K=([],inr(snd(qC))))ppC(P-Ctx, K=(a,inr([]))). Thus u(d(pB)) and u(d(pC)) concatenate respectively the first and second chains in each display and return pB,pC. Conversely, d(u(inl(qB))) and d(u(inr(qC))) concatenate the same chains in the opposite order and return inl(qB),inr(qC). Every step is beta, projection, or case contraction; no eta law has been used.

Exercise 2.18.

We reconstruct, rather than cite, neutral expansion. For each type A, let N(A) assert: if n is neutral and every immediate reduct of n lies in RA, then nRA. We prove N(A) by structural induction on A, using only normalization and reduction closure at proper component types.

At P,2,1,0, every immediate reduct is strongly normalizing. There are finitely many, so adjoining the root n produces no infinite branch. Hence SN(n) and the base candidate contains n.

Let A=BC and fix aRB. Normalization at B gives ν(a). By induction on ν(a) we show naRC. Its immediate reducts have exactly two forms. If npn, the premise of N(A) gives nRBC, and the arrow clause gives naRC. If apa, reduction closure at B gives aRB and the height induction gives naRC. The outer induction hypothesis N(C) now admits na. Since a was arbitrary, the arrow clause admits n.

Let A=B×C. The term fst(n) is neutral, and each of its immediate reducts is fst(n) for an immediate n of n. The premise gives nRB×C, hence fst(n)RB. The outer induction hypothesis N(B) admits fst(n). Replacing B,fst by C,snd proves the second projection condition, so the product clause admits n.

Let A=B+C. Every immediate n is reducible and therefore strongly normalizing; finite branching makes n strongly normalizing. A reduction from neutral n to inl(b) has positive length and factors through an immediate nRB+C, whose canonical-reduct condition gives bRB. A reduction to inr(c) factors the same way and the right condition of n gives cRC. Thus the sum clause admits n.

This completes the proof of N(A) without invoking saturation clause 3. A variable x is neutral and has no immediate reducts, so the premise of N(A) is vacuous and xRA for every type A.

Exercise 2.19.

Let eR2 and b,cRC. Saturation normalization gives finite heights ν(e),ν(b),ν(c). Induct on their sum. The conditional is neutral. Its complete list of immediate reducts is if(e;b;c)epe,if(e;b;c)bpb,if(e;b;c)cpc,be=tt,ce=ff. In the first three cases, saturation reduction closure keeps the changed component in its candidate, and its reduction height strictly decreases. The induction hypothesis therefore places the resulting conditional in RC. In the last two cases the reduct is respectively b or c, reducible by assumption. Thus every immediate reduct is in RC; saturation neutral expansion gives if(e;b;c)RC.

Finally, R2={eSN(e)}. Neither tt nor ff has an immediate proof reduct, hence neither begins an infinite reduction. Therefore tt,ffR2 directly from the base definition.

Practical route.

The checker and evaluator requested by exercise 2.22 are built in appendix F; the exact executable record is in appendix E.

Search the book

Type to search the local edition.