Lectures onType Theory
ch:intersection-union: ch:intersection-union
appendix sectionsolutions

ch:intersection-union: ch:intersection-union

exercise 9.1.

Let same:=λ(NatNat;BoolBool)x.x. The two body derivations are the variable trees x:Natx:Natx:Natx:NatTVar,x:Boolx:Boolx:Boolx:BoolTVar. Therefore the single abstraction rule gives a derivation D of x:Natx:Natx:Boolx:Boolsame:(NatNat)(BoolBool)TAbs. Let I abbreviate the displayed intersection. Semantic intersection elimination gives INatNat and IBoolBool. Reuse the already constructed derivation D in two subsumption steps, then intersect their conclusions: DINatNatsame:NatNatTSubDIBoolBoolsame:BoolBoolTSubsame:ITInter. No second T-Abs instance and no pair constructor is introduced.

Exercise 9.2.

Use the single annotated abstraction same=λ(NatNat;BoolBool)x.x. The two variable derivations under x:Nat and x:Bool, followed by T-Abs, give same:(NatNat)(BoolBool). It is a lambda value, not a pair. The intersection records two static specifications of this same value; subsumption selects either arrow and the value is applied directly.

Replacing by × changes the type to a product type and therefore changes the canonical value to a pair, for example (λ(NatNat)x.x,λ(BoolBool)x.x). Using it as a function now requires first choosing a component with π1 or π2. Thus product formation packages two values and product elimination selects one; intersection introduction reuses one value and introduces no run-time constructor or projection.

exercise 9.3.

Distribute intersection over the union and use absorption: (AB)A=DA,(AB)¬A=DB¬A. Thus the positive branch receives all of A, including the overlap AB, while the negative branch receives precisely the part of B outside A.

For an empty negative branch, take A=NatBool and B=Bool. Then BA, so B¬A=D0. For a proper refinement, take A=Nat and B=NatBool. Disjointness of the two basic tags gives B¬A=DBoolandBoolNatBool,BoolDNatBool. Both examples use only the basic-tag algebra fixed in the chapter.

Exercise 9.4.

A sum value carries an injection tag: it is explicitly inlv or inrv. The corresponding root reduction inspects that tag, chooses a branch, and substitutes the stored payload.

A value of AB carries no additional constructor. It is the same underlying value that was assigned A, B, or both, and the two denotations may overlap. Consequently there is no left/right tag for an ordinary sum-case reduction to inspect and no distinguished payload to substitute. The chapter’s typecase is a different operation: it applies a decidable structural test vU to the existing value and refines its binder type. Treating AB as A+B would invent run-time data that semantic union deliberately does not contain.

Exercise 9.5.

Let a finite graph R belong to both AC and BD. For any edge (d,r)R whose input lies in [[AB]], at least one of the following holds. If d[[A]], membership in AC gives r[[C]]; if d[[B]], membership in BD gives r[[D]]. In either case r[[CD]], and in particular rΩ. Hence (AC)(BD)(AB)(CD).

For the converse, choose pairwise-disjoint nonempty A,B,C,D, an element a[[A]], and d[[D]]. The one-edge graph R={(a,d)} belongs to (AB)(CD), because its input is in the domain union and its output is in DCD. It does not belong to AC, since aA but dC. Therefore it is not in the intersection on the left, disproving the converse inclusion.

Exercise 9.6.

Choose any dD and take the one-edge graph R={(d,Ω)}. It belongs to 01: no input lies in [[0]]=, so the arrow condition is vacuous. It does not belong to 11: now d[[1]]=D, but the required output would have to lie in D, whereas ΩDΩD.

Thus 01 recognizes every finite graph, including graphs that fail on some inputs, while 11 requires a successful D-valued output on every represented input edge. The extra marker Ω is precisely what makes those two types different.

Exercise 9.7.

Expand the derived meet and then use the two mutually recursive clauses: a1(a2¬a3)=¬(¬a1¬(a2¬a3)). Now N(¬a1)=N(a1)={({a1},)}, whereas N(¬(a2¬a3))=N(a2¬a3)={({a2},),(,{a3})}. The negative-union clause takes pairwise unions of the positive and negative sets. Therefore N(a1(a2¬a3))={({a1,a2},),({a1},{a3})}. Its two clauses denote respectively a1a2 and a1¬a3, as distributivity predicts.

Exercise 9.8.

For P={A×B} and N={C×D}, there are two choices of NN. If N=, then L(P,N)=A,R(P,N,N)=B¬D, so this component is empty exactly when A=D0 or BD. If N=N, then L(P,N)=A¬C,R(P,N,N)=B, so it is empty exactly when AC or B=D0. By the product-empty condition, the original type is empty exactly when (A=D0  BD)  (AC  B=D0). If A=D0 or B=D0, this conjunction holds immediately. Otherwise the two clauses force BD and AC. Conversely those two inclusions close the respective components. Hence the condition is exactly A=D0orB=D0or(AC and BD).

exercise 9.9.

Apply lemma 9.12 to the two positive atoms and the negative atom AB. The four choices of P give, respectively, Prequired alternativeA=D0orB1B2B,{1}AA1orB2B,{2}AA2orB1B,{1,2}AA1A2. For example, the second row rewrites A¬A1=D0 as AA1 and B2¬B=D0 as B2B. In the last row the codomain alternative is unavailable because P=P; the Ω output is the witness that forces domain coverage. The conjunction of these four alternatives is therefore necessary and sufficient.

Exercise 9.10.

Put Nt=Nat, Bt=Bool, and St=NtBt. For the negative arrow StNt, the first two subsets of P={NtNt,BtBt} give PDomOb(P)CodOb(P)St¬NtNtBt=D0{NtNt}Bt¬NtBt=DBt. The empty-subset row closes on its codomain component. In the next row, both Bt components are nonempty, so this is the first row that fails.

The failed row exposes the one-edge counterexample R={(true,true)}. It belongs to NtNt vacuously and to BtBt directly, so it inhabits their intersection. It does not inhabit StNt, because its input belongs to St but its output is a Boolean rather than a natural. The requested inclusion is therefore false.

exercise 9.11.

Put A=01 and X=(A1)A. The empty graph is an element of A, since every graph inhabits 01, and it is an element of A1 because it has no edge violating that arrow. Hence XD0.

Under x:X, both occurrences synthesize X. Intersection elimination gives XA=01 and XA1. Since XA, arrow contravariance gives A1X1; transitivity yields XX1. These intermediate inclusions establish the sole callability premise of T-App. For the positive arrows A1 and 01, the K= output obligation contributes 1 because nonempty X is not below 0; all other contributions are at most 1. Therefore XX=D1, and x:Xx:Xx:Xx:XXX1x:Xxx:1TApp. The enclosing one-arrow interface then gives λ(X1)x.xx:X1.

exercise 9.12.

For the variable case, substituting for the distinguished variable uses the supplied derivation Γv:A; every other lookup is unchanged. For the abstraction case, alpha-rename its binder y away from x and every free variable of v. Each premise has the form Γ,x:A,y:Cie:Di. Fresh-variable weakening gives Γ,y:Civ:A, and the induction hypothesis gives Γ,y:Cie[v/x]:Di. Reapplying T-Abs preserves the written interface. Consequently, at a beta root, lemma 9.31 selects the required body premises, applies this substitution case, intersects the resulting typings, and subsumes to the application output. This is exactly the beta case of theorem 9.32.

Exercise 9.13.

Suppose the positive root fires: caseType v as x in Ue+ee+[v/x],vU. Inversion of T-Case gives Γv:S. Value refinement gives both Γv:SU and SUD0. The latter fact makes the conditional positive premise of T-Case active, so inversion also gives Γ,x:SUe+:B+. Substitution yields Γe+[v/x]:B+, and B+B+B followed by T-Sub restores the type of the whole case.

For the negative root, vU. Value refinement instead gives Γv:S¬U and S¬UD0. Thus the negative conditional premise is active, substitution gives Γe[v/x]:B, and union introduction by subsumption gives Γe[v/x]:B+B.

Nonemptiness is load bearing in both cases: it turns the selected implication inside T-Case into an available typing premise. An actually selected branch cannot be one of the empty branches whose body was deliberately not typechecked.

exercise 9.14.

Write I=(NatNat)(BoolBool). The two successful body checks make syn(same)=I. For an argument synthesized at Nat, the subsets of the two positive arrows contribute 0 or Nat to (9.13), so INat=DNat. Symmetrically, IBool=DBool.

For S=NatBool, neither singleton domain covers S. The two proper singleton subsets therefore contribute the opposite codomains, and IS=DNatBool. Callability follows from (9.2). Thus all three applications synthesize, and the union application retains both input–output alternatives rather than choosing one branch prematurely.

Exercise 9.15.

Let A=01 and X=(A1)A, as in the chapter. Under x:X, both variable calls synthesize X. For xx, the checker therefore sets F=S=X. Intersection elimination gives XA=01. It also gives XA1; since XA, arrow contravariance yields A1X1, hence XX1. Both algorithmic callability tests succeed and the least-output calculation returns synx:X(xx)=XX=D1.

The annotated abstraction has the one-arrow interface X1. Its body check succeeds because the synthesized body type is 11; the interface is automatically well shaped when it has one arrow. Hence syn(λ(X1)x.xx)=X1. This trace uses the written interface; it performs no search for an unannotated principal type.

exercise 20.16.

For completeness, suppose the declarative last rule is Γe1:FΓe2:SFSBΓe1e2:BTApp, and the recursive checker calls return F0F and S0S. Transitivity, domain contravariance, and codomain covariance give F0FSBS0BS01. Here SBS0B is the contravariant domain step, while S0BS01 is the covariant codomain step using B1. The chain through SB01 uses both variances: 0S in the domain and B1 in the codomain. Thus F001, so both algorithmic callability tests succeed. The least-output characterization in lemma 9.23 then yields F0S0B.

Conversely, a successful application call has recursive declarative typings Γe1:F0 and Γe2:S0, together with F001 and F0S01. The existence part of lemma 9.23 strengthens the latter fact to F0S0(F0S0). Rule T-App therefore reconstructs Γe1e2:F0S0, exactly the type returned by the synthesizer. These are the two directions of the application case.

exercise 9.16.

Let S=NatBool and test Bool. Boolean algebra gives SBool=DBool,S¬Bool=DNat. Both are nonempty. In the then context, T-Var followed by T-Sub types x:Bool; in the else context the same two rules type x:Nat. Rule T-Case, with the two scope premises and the scrutinee lookup z:Sz:S, concludes z:ScaseType z as x inBoolxx:BoolNat. The order of the union records then before else; semantic equivalence makes it immaterial to subtyping.

Exercise 9.17.

Take (a,i)=(4,5,1),(a,i)=(4,5,2). Both arrays have the same unary type ArrayNat, and both indices have type Nat. The first pair satisfies 01<len(4,5)=2; the second violates the strict upper bound because 2<2 is false.

Unions, intersections, and complements of the two unary types can record only membership properties of the array value by itself or of the index value by itself. They cannot relate the chosen index to the length of the chosen array. Since the two pairs have identical component types, every such unary Boolean combination classifies them alike. Distinguishing them needs the binary refinement i<len(a), which is the next chapter’s proof obligation.

Search the book

Type to search the local edition.