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

ch:existential-types: ch:existential-types

Exercise 7.6.

Let M(c):=a::Ty.b::Ty.(ab)cacb. The kinding calculation in the context c::TyTy,a::Ty,b::Ty gives ca,cb::Ty by K-App; K-Arr forms the three arrows, and two uses of K-All give c::TyTyM(c)::Ty. Thus the existential body has precisely the kind required by T-Pack. The complete final rule is P::TyTyc::TyTyM(c)::Ty;dmap:M(P);pack[P,dmap] as c::TyTy.M(c):MapperTPack. The third premise is the previously derived typing dmap:MapP, since M(P)=MapP after unfolding the abbreviation.

If the witness is replaced by N, the first premise would have to be N::TyTy. Kinding instead uniquely gives N::Ty. The first premise therefore fails before a payload is considered: N is a type, whereas this package hides a unary type constructor that can be applied to a and b.

exercise 7.7.

Define reseal:=λc:Counter.unpack[X,z]=c in pack[X,z] as Counter. In the unpacking body, X::Ty;z:X×((XX)×(XN)). Rule T-Pack uses witness X and the variable premise for z, producing the outer type Counter. That result type is formed in the empty kind context: X occurs only beneath the existential binder of Counter. Hence T-Unpack discharges the local X, and T-Lam gives reseal:CounterCounter.

Exercise 7.8.

Inversion of the unpacking judgment supplies a kind κ, a body constructor A, and the three premises Δ;Γ,y:Dp:u::κ.A,Δ,u::κ;Γ,y:D,x:Ae:B,ΔB::Ty. The binders have been chosen fresh for d. Term substitution in the scrutinee gives the first required transformed premise (1)Δ;Γp[d/y]:u::κ.A. To substitute in the body, first use constructor-context weakening on the given derivation of d: (2)Δ,u::κ;Γd:D. This is the exact use of weakening under the hidden constructor. Applying term substitution to the body derivation, with x:A in its trailing context, gives the second transformed premise (3)Δ,u::κ;Γ,x:Ae[d/y]:B. Equivalently, one may weaken (2) through x:A inside the variable case of that substitution induction. Neither A nor B changes because term substitution does not act on constructors.

The old no-escape premise still forms B outside u. Reassembling (1), (3), and that premise gives Δ;Γp[d/y]:u::κ.AΔ,u::κ;Γ,x:Ae[d/y]:BΔB::TyΔ;Γunpack[u,x]=p[d/y] in e[d/y]:BTUnpack. Capture-avoiding substitution identifies the subject in the conclusion with (unpack[u,x]=p in e)[d/y].

Exercise 7.9.

Put qN+2:=(0,(sN+2,rN)),CN+2:=pack[N,qN+2] as Counter. Here sN+2=λn:N.suc(suc(n)), so the ordinary product and arrow rules type the payload at N×((NN)×(NN)); T-Pack gives CN+2:Counter.

Write q=qN+2, s=sN+2, and r=rN. Expanding every projection, the complete call-by-value contraction sequence is tick2CN+2unpack[X,z]=CN+2 in rz(sz(sziz))rq(sq(sqiq))=pr2(pr2q)(sq(sqiq))pr2((s,r))(sq(sqiq))r(sq(sqiq))=r(pr1(pr2q)(sqiq))r(pr1((s,r))(sqiq))r(s(sqiq))=r(s(pr1(pr2q)iq))r(s(pr1((s,r))iq))r(s(siq))=r(s(s(pr1q)))r(s(s0))r(s(suc(suc(0))))r(suc(suc(suc(suc(0)))))suc(suc(suc(suc(0)))). The first step is the outer term beta contraction, the second opens the package, the next projection steps expose r, the two copies of s, and 0, the next two term-beta steps advance by two each, and the final term-beta step applies the identity observer. The result is the normal numeral four. The same typed client applied to CN has the normal result two; constructor injectivity makes the two numeral normal forms distinct. Thus the common existential type enforces opacity but does not equate these two implementations.

Exercise 7.10.

Constructor reduction gives CompPP=βλa::Ty.P(Pa). Apply the abstraction/action clause to Q=(A0,A1,R). It first yields [[P(Pa)]]aQ. The outer application clause applies the action of P to the relational object denoted by Pa. By a second application clause, followed by the product clause, [[Pa]]aQ=[[P]](A0,A1,R)=R×R. The endpoints of that intermediate object are A0×A0 and A1×A1. Applying the outer P action and unfolding its product body once more gives [[CompPP]](A0,A1,R)=(R×R)×(R×R). This relation has endpoint types (A0×A0)×(A0×A0),(A1×A1)×(A1×A1), exactly the two constructor endpoints of CompPP applied to A0 and A1. For the nonconstant action, [[D]](A0,A1,R)=[[aa]]a(A0,A1,R)=RR. Changing R while keeping A0,A1 fixed changes which function pairs the arrow lifting relates. Thus an arrow-kind relational object must carry an action on the relation argument, not only a pair of endpoint constructors.

exercise 7.11.

The initial states satisfy iP+=(0,suc(0)), so [iN]R+[iP+]. If [n]R+[p], then p=β(n,suc(n)), whence sP+p=β(suc(n),suc(suc(n))). This is exactly the witness for [sNn]R+[sP+p]. The observer calculation is rP+p=βn=βrNn. Thus the three payload components are related at R+×((R+R+)×(R+EqN)). Existential lifting relates CN and CP+. The single use of self-parametricity relates a closed k:CounterN to itself at [[Counter]]EqN; applying it to the packages gives kCN=βkCP+.

exercise 7.20.

The unknown-remainder display requires a row kind Row, a row extension constructor {:Aξ}, and a lacks judgment ξ\; none belongs to the fixed-record extension.

Rules Rec-E and T-Lam give portOf:{port:N}N, while Rec-I gives server:{port:N,secure:BoolF}. At their application, T-App demands the smaller record type for the argument. The two sorted record types are distinct normal constructors, so T-Conv cannot supply it. Adding Width and Sub derives X{port:N,secure:BoolF}<:{port:N}Width and then server:{port:N,secure:BoolF}{port:N,secure:BoolF}<:{port:N}server:{port:N}Sub. Now T-App gives portOfserver:N from the displayed domain and argument judgments. Width and Sub add no row kind, extension constructor, or lacks predicate, so the first display remains unformed.

Exercise 7.13.

Let A(X):=X×((XX)×(XN)). The Church encoding of CN is cCN:=ΛR::Ty.λk:X::Ty.A(X)R.k[N]qN. The witness premise N::Ty and the payload typing qN:A(N) show cCN:SomeTy(X.A(X)).

Use the continuation K:=ΛX::Ty.λz:A(X).rz(sz(sziz)). Under X::Ty;z:A(X), the projections synthesize iz:X, sz:XX, and rz:XN. The two step applications have type X and the observation has type N. Hence K:X::Ty.A(X)N. Opening the package with this continuation reproduces the four administrative contractions without abbreviation: cCN[N]K=(ΛR.λk.k[N]qN)[N]K(λk.k[N]qN)KK[N]qN(λz:A(N).rz(sz(sziz)))qNrqN(sqN(sqNiqN)). The remaining projection and counter contractions are the native calculation and end in suc(suc(0)).

At result type N, the continuation arrow in the package instance is (X::Ty.A(X)N)N. When A(X) and N contain no nested universal quantifiers, the underlined continuation has rank one. Placing that polymorphic type to the left of the enclosing arrow raises the enclosing arrow to rank two. The kind of X is only Ty; the rank increase is caused by arrow position, not by a higher kind.

Exercise 7.14.

In the context b:BoolF,m:Counter,n:Counter, the body tree is b:BoolFΓΓb:BoolFTVarCounter::TyΓb[Counter]:CounterCounterCounterTTAppm:CounterΓΓm:CounterTVarΓb[Counter]m:CounterCounterTAppn:CounterΓΓn:CounterTVarΓb[Counter]mn:CounterTApp. Three applications of T-Lam, discharging n,m,b in that order, therefore derive chooseCounter:BoolFCounterCounterCounter.

For the false branch, the three Boolean contractions are visible after the three outer lambda contractions: chooseCounterfalseFCNCPfalseF[Counter]CNCP(λm:Counter.λn:Counter.n)CNCP(λn:Counter.n)CPCP. Consequently the client opens CP. With the states from the chapter, its two counter steps and observation are p0=(0,0),sPp0p1,sPp1p2,rPp2suc(suc(0)).

The selected expression has the existential type Counter. Typing it at the representation type N would reveal that the true branch used witness N and would be false for the pair-state branch, whose witness is P=N×N. No rule projects an existential witness into the surrounding type, and T-Unpack deliberately prevents that witness from escaping. Assigning N would therefore violate the package’s opacity invariant.

Practical route.

The package checker of exercise 12.10 is built in appendix F; its two-representation observation and scope-boundary mutation are recorded in appendix E.

Search the book

Type to search the local edition.