exercise 9.1.
Let 𝗌𝖺𝗆𝖾:=𝜆(𝖭𝖺𝗍→𝖭𝖺𝗍;𝖡𝗈𝗈𝗅→𝖡𝗈𝗈𝗅)𝑥.𝑥. The two body derivations are the variable trees 𝑥:𝖭𝖺𝗍∈𝑥:𝖭𝖺𝗍𝑥:𝖭𝖺𝗍⊢𝑥:𝖭𝖺𝗍T−Var,𝑥:𝖡𝗈𝗈𝗅∈𝑥:𝖡𝗈𝗈𝗅𝑥:𝖡𝗈𝗈𝗅⊢𝑥:𝖡𝗈𝗈𝗅T−Var. Therefore the single abstraction rule gives a derivation D of 𝑥:𝖭𝖺𝗍⊢𝑥:𝖭𝖺𝗍𝑥:𝖡𝗈𝗈𝗅⊢𝑥:𝖡𝗈𝗈𝗅⋅⊢𝗌𝖺𝗆𝖾:(𝖭𝖺𝗍→𝖭𝖺𝗍)∧(𝖡𝗈𝗈𝗅→𝖡𝗈𝗈𝗅)T−Abs. Let 𝐼 abbreviate the displayed intersection. Semantic intersection elimination gives 𝐼 ≤𝖭𝖺𝗍 →𝖭𝖺𝗍 and 𝐼 ≤𝖡𝗈𝗈𝗅 →𝖡𝗈𝗈𝗅. Reuse the already constructed derivation D in two subsumption steps, then intersect their conclusions: D𝐼≤𝖭𝖺𝗍→𝖭𝖺𝗍⋅⊢𝗌𝖺𝗆𝖾:𝖭𝖺𝗍→𝖭𝖺𝗍T−SubD𝐼≤𝖡𝗈𝗈𝗅→𝖡𝗈𝗈𝗅⋅⊢𝗌𝖺𝗆𝖾:𝖡𝗈𝗈𝗅→𝖡𝗈𝗈𝗅T−Sub⋅⊢𝗌𝖺𝗆𝖾:𝐼T−Inter. No second T-Abs instance and no pair constructor is introduced.
Exercise 9.2.
Use the single annotated abstraction 𝗌𝖺𝗆𝖾=𝜆(𝖭𝖺𝗍→𝖭𝖺𝗍;𝖡𝗈𝗈𝗅→𝖡𝗈𝗈𝗅)𝑥.𝑥. The two variable derivations under 𝑥 :𝖭𝖺𝗍 and 𝑥 :𝖡𝗈𝗈𝗅, followed by T-Abs, give ⋅⊢𝗌𝖺𝗆𝖾:(𝖭𝖺𝗍→𝖭𝖺𝗍)∧(𝖡𝗈𝗈𝗅→𝖡𝗈𝗈𝗅). 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 (𝜆(𝖭𝖺𝗍→𝖭𝖺𝗍)𝑥.𝑥,𝜆(𝖡𝗈𝗈𝗅→𝖡𝗈𝗈𝗅)𝑥.𝑥). 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: (𝐴∨𝐵)∧𝐴=D𝐴,(𝐴∨𝐵)∧¬𝐴=D𝐵∧¬𝐴. Thus the positive branch receives all of 𝐴, including the overlap 𝐴 ∧𝐵, while the negative branch receives precisely the part of 𝐵 outside 𝐴.
For an empty negative branch, take 𝐴 =𝖭𝖺𝗍 ∨𝖡𝗈𝗈𝗅 and 𝐵 =𝖡𝗈𝗈𝗅. Then 𝐵 ≤𝐴, so 𝐵 ∧¬𝐴 =D0. For a proper refinement, take 𝐴 =𝖭𝖺𝗍 and 𝐵 =𝖭𝖺𝗍 ∨𝖡𝗈𝗈𝗅. Disjointness of the two basic tags gives 𝐵∧¬𝐴=D𝖡𝗈𝗈𝗅and𝖡𝗈𝗈𝗅≤𝖭𝖺𝗍∨𝖡𝗈𝗈𝗅,𝖡𝗈𝗈𝗅≠D𝖭𝖺𝗍∨𝖡𝗈𝗈𝗅. 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 𝗂𝗇𝗅 𝑣 or 𝗂𝗇𝗋 𝑣. The corresponding root reduction inspects that tag, chooses a branch, and substitutes the stored payload.
A value of 𝐴 ∨𝐵 carries no additional constructor. It is the same underlying value that was assigned 𝐴, 𝐵, 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 𝑣 ⊩𝑈 to the existing value and refines its binder type. Treating 𝐴 ∨𝐵 as 𝐴 +𝐵 would invent run-time data that semantic union deliberately does not contain.
Exercise 9.5.
Let a finite graph 𝑅 belong to both 𝐴 →𝐶 and 𝐵 →𝐷. For any edge (𝑑,𝑟) ∈𝑅 whose input lies in [[𝐴 ∨𝐵]], at least one of the following holds. If 𝑑 ∈[[𝐴]], membership in 𝐴 →𝐶 gives 𝑟 ∈[[𝐶]]; if 𝑑 ∈[[𝐵]], membership in 𝐵 →𝐷 gives 𝑟 ∈[[𝐷]]. In either case 𝑟 ∈[[𝐶 ∨𝐷]], and in particular 𝑟 ≠Ω. Hence (𝐴→𝐶)∧(𝐵→𝐷)≤(𝐴∨𝐵)→(𝐶∨𝐷).
For the converse, choose pairwise-disjoint nonempty 𝐴,𝐵,𝐶,𝐷, an element 𝑎 ∈[[𝐴]], and 𝑑 ∈[[𝐷]]. The one-edge graph 𝑅 ={(𝑎,𝑑)} belongs to (𝐴 ∨𝐵) →(𝐶 ∨𝐷), because its input is in the domain union and its output is in 𝐷 ≤𝐶 ∨𝐷. It does not belong to 𝐴 →𝐶, since 𝑎 ∈𝐴 but 𝑑 ∉𝐶. Therefore it is not in the intersection on the left, disproving the converse inclusion.
Exercise 9.6.
Choose any 𝑑 ∈𝐷 and take the one-edge graph 𝑅={(𝑑,Ω)}. It belongs to 0 →1: no input lies in [[0]] =∅, so the arrow condition is vacuous. It does not belong to 1 →1: now 𝑑 ∈[[1]] =𝐷, but the required output would have to lie in 𝐷, whereas Ω ∈𝐷Ω ∖𝐷.
Thus 0 →1 recognizes every finite graph, including graphs that fail on some inputs, while 1 →1 requires a successful 𝐷-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: 𝑎1∧(𝑎2∨¬𝑎3)=¬(¬𝑎1∨¬(𝑎2∨¬𝑎3)). Now ―――N(¬𝑎1)=N(𝑎1)={({𝑎1},∅)}, whereas ―――N(¬(𝑎2∨¬𝑎3))=N(𝑎2∨¬𝑎3)={({𝑎2},∅),(∅,{𝑎3})}. The negative-union clause takes pairwise unions of the positive and negative sets. Therefore N(𝑎1∧(𝑎2∨¬𝑎3))={({𝑎1,𝑎2},∅),({𝑎1},{𝑎3})}. Its two clauses denote respectively 𝑎1 ∧𝑎2 and 𝑎1 ∧¬𝑎3, as distributivity predicts.
Exercise 9.8.
For 𝑃 ={𝐴 ×𝐵} and 𝑁 ={𝐶 ×𝐷}, there are two choices of 𝑁′ ⊆𝑁. If 𝑁′ =∅, then 𝐿(𝑃,𝑁′)=𝐴,𝑅(𝑃,𝑁,𝑁′)=𝐵∧¬𝐷, so this component is empty exactly when 𝐴 =D0 or 𝐵 ≤𝐷. If 𝑁′ =𝑁, then 𝐿(𝑃,𝑁′)=𝐴∧¬𝐶,𝑅(𝑃,𝑁,𝑁′)=𝐵, so it is empty exactly when 𝐴 ≤𝐶 or 𝐵 =D0. By the product-empty condition, the original type is empty exactly when (𝐴=D0 ∨ 𝐵≤𝐷) ∧ (𝐴≤𝐶 ∨ 𝐵=D0). If 𝐴 =D0 or 𝐵 =D0, this conjunction holds immediately. Otherwise the two clauses force 𝐵 ≤𝐷 and 𝐴 ≤𝐶. Conversely those two inclusions close the respective components. Hence the condition is exactly 𝐴=D0or𝐵=D0or(𝐴≤𝐶 and 𝐵≤𝐷).
exercise 9.9.
Apply lemma 9.12 to the two positive atoms and the negative atom 𝐴 →𝐵. The four choices of 𝑃′ give, respectively, 𝑃′required alternative∅𝐴=D0or𝐵1∧𝐵2≤𝐵,{1}𝐴≤𝐴1or𝐵2≤𝐵,{2}𝐴≤𝐴2or𝐵1≤𝐵,{1,2}𝐴≤𝐴1∨𝐴2. For example, the second row rewrites 𝐴 ∧¬𝐴1 =D0 as 𝐴 ≤𝐴1 and 𝐵2 ∧¬𝐵 =D0 as 𝐵2 ≤𝐵. In the last row the codomain alternative is unavailable because 𝑃′ =𝑃; the Ω output is the witness that forces domain coverage. The conjunction of these four alternatives is therefore necessary and sufficient.
Exercise 9.10.
Put 𝑁𝑡 =𝖭𝖺𝗍, 𝐵𝑡 =𝖡𝗈𝗈𝗅, and 𝑆𝑡 =𝑁𝑡 ∨𝐵𝑡. For the negative arrow 𝑆𝑡 →𝑁𝑡, the first two subsets of 𝑃 ={𝑁𝑡 →𝑁𝑡,𝐵𝑡 →𝐵𝑡} give 𝑃′DomOb(𝑃′)CodOb(𝑃′)∅𝑆𝑡¬𝑁𝑡∧𝑁𝑡∧𝐵𝑡=D0{𝑁𝑡→𝑁𝑡}𝐵𝑡¬𝑁𝑡∧𝐵𝑡=D𝐵𝑡. The empty-subset row closes on its codomain component. In the next row, both 𝐵𝑡 components are nonempty, so this is the first row that fails.
The failed row exposes the one-edge counterexample 𝑅={(𝗍𝗋𝗎𝖾,𝗍𝗋𝗎𝖾)}. It belongs to 𝑁𝑡 →𝑁𝑡 vacuously and to 𝐵𝑡 →𝐵𝑡 directly, so it inhabits their intersection. It does not inhabit 𝑆𝑡 →𝑁𝑡, because its input belongs to 𝑆𝑡 but its output is a Boolean rather than a natural. The requested inclusion is therefore false.
exercise 9.11.
Put 𝐴 =0 →1 and 𝑋 =(𝐴 →1) ∧𝐴. The empty graph is an element of 𝐴, since every graph inhabits 0 →1, and it is an element of 𝐴 →1 because it has no edge violating that arrow. Hence 𝑋 ≠D0.
Under 𝑥 :𝑋, both occurrences synthesize 𝑋. Intersection elimination gives 𝑋 ≤𝐴 =0 →1 and 𝑋 ≤𝐴 →1. Since 𝑋 ≤𝐴, arrow contravariance gives 𝐴 →1 ≤𝑋 →1; transitivity yields 𝑋 ≤𝑋 →1. These intermediate inclusions establish the sole callability premise of T-App. For the positive arrows 𝐴 →1 and 0 →1, the 𝐾′ =∅ output obligation contributes 1 because nonempty 𝑋 is not below 0; all other contributions are at most 1. Therefore 𝑋 ∘𝑋 =D1, and 𝑥:𝑋⊢𝑥:𝑋𝑥:𝑋⊢𝑥:𝑋𝑋≤𝑋→1𝑥:𝑋⊢𝑥𝑥:1T−App. The enclosing one-arrow interface then gives ⋅ ⊢𝜆(𝑋→1)𝑥.𝑥 𝑥 :𝑋 →1.
exercise 9.12.
For the variable case, substituting for the distinguished variable uses the supplied derivation Γ ⊢𝑣 :𝐴; every other lookup is unchanged. For the abstraction case, alpha-rename its binder 𝑦 away from 𝑥 and every free variable of 𝑣. Each premise has the form Γ,𝑥:𝐴,𝑦:𝐶𝑖⊢𝑒:𝐷𝑖. Fresh-variable weakening gives Γ,𝑦 :𝐶𝑖 ⊢𝑣 :𝐴, and the induction hypothesis gives Γ,𝑦:𝐶𝑖⊢𝑒[𝑣/𝑥]:𝐷𝑖. 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: 𝖼𝖺𝗌𝖾𝖳𝗒𝗉𝖾 𝑣 𝖺𝗌 𝑥 𝗂𝗇 𝑈⇒𝑒+∣𝑒−⟶𝑒+[𝑣/𝑥],𝑣⊩𝑈. Inversion of T-Case gives Γ ⊢𝑣 :𝑆. Value refinement gives both Γ ⊢𝑣 :𝑆 ∧𝑈 and 𝑆 ∧𝑈 ≠D0. The latter fact makes the conditional positive premise of T-Case active, so inversion also gives Γ,𝑥 :𝑆 ∧𝑈 ⊢𝑒+ :𝐵+. Substitution yields Γ ⊢𝑒+[𝑣/𝑥] :𝐵+, and 𝐵+ ≤𝐵+ ∨𝐵− followed by T-Sub restores the type of the whole case.
For the negative root, 𝑣 ⊮𝑈. Value refinement instead gives Γ ⊢𝑣 :𝑆 ∧¬𝑈 and 𝑆 ∧¬𝑈 ≠D0. Thus the negative conditional premise is active, substitution gives Γ ⊢𝑒−[𝑣/𝑥] :𝐵−, and union introduction by subsumption gives Γ ⊢𝑒−[𝑣/𝑥] :𝐵+ ∨𝐵−.
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 𝐼=(𝖭𝖺𝗍→𝖭𝖺𝗍)∧(𝖡𝗈𝗈𝗅→𝖡𝗈𝗈𝗅). The two successful body checks make syn(𝗌𝖺𝗆𝖾) =𝐼. For an argument synthesized at 𝖭𝖺𝗍, the subsets of the two positive arrows contribute 0 or 𝖭𝖺𝗍 to (9.13), so 𝐼 ∘𝖭𝖺𝗍 =D𝖭𝖺𝗍. Symmetrically, 𝐼 ∘𝖡𝗈𝗈𝗅 =D𝖡𝗈𝗈𝗅.
For 𝑆 =𝖭𝖺𝗍 ∨𝖡𝗈𝗈𝗅, neither singleton domain covers 𝑆. The two proper singleton subsets therefore contribute the opposite codomains, and 𝐼∘𝑆=D𝖭𝖺𝗍∨𝖡𝗈𝗈𝗅. 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 𝐴 =0 →1 and 𝑋 =(𝐴 →1) ∧𝐴, as in the chapter. Under 𝑥 :𝑋, both variable calls synthesize 𝑋. For 𝑥 𝑥, the checker therefore sets 𝐹 =𝑆 =𝑋. Intersection elimination gives 𝑋 ≤𝐴 =0 →1. It also gives 𝑋 ≤𝐴 →1; since 𝑋 ≤𝐴, arrow contravariance yields 𝐴 →1 ≤𝑋 →1, hence 𝑋 ≤𝑋 →1. Both algorithmic callability tests succeed and the least-output calculation returns syn𝑥:𝑋(𝑥𝑥)=𝑋∘𝑋=D1.
The annotated abstraction has the one-arrow interface 𝑋 →1. Its body check succeeds because the synthesized body type is 1 ≤1; the interface is automatically well shaped when it has one arrow. Hence syn⋅(𝜆(𝑋→1)𝑥.𝑥𝑥)=𝑋→1. 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 Γ⊢𝑒1:𝐹Γ⊢𝑒2:𝑆𝐹≤𝑆→𝐵Γ⊢𝑒1𝑒2:𝐵T−App, and the recursive checker calls return 𝐹0 ≤𝐹 and 𝑆0 ≤𝑆. Transitivity, domain contravariance, and codomain covariance give 𝐹0≤𝐹≤𝑆→𝐵≤𝑆0→𝐵≤𝑆0→1. Here 𝑆 →𝐵 ≤𝑆0 →𝐵 is the contravariant domain step, while 𝑆0 →𝐵 ≤𝑆0 →1 is the covariant codomain step using 𝐵 ≤1. The chain through 𝑆 →𝐵 ≤0 →1 uses both variances: 0 ≤𝑆 in the domain and 𝐵 ≤1 in the codomain. Thus 𝐹0 ≤0 →1, so both algorithmic callability tests succeed. The least-output characterization in lemma 9.23 then yields 𝐹0 ∘𝑆0 ≤𝐵.
Conversely, a successful application call has recursive declarative typings Γ ⊢𝑒1 :𝐹0 and Γ ⊢𝑒2 :𝑆0, together with 𝐹0 ≤0 →1 and 𝐹0 ≤𝑆0 →1. The existence part of lemma 9.23 strengthens the latter fact to 𝐹0≤𝑆0→(𝐹0∘𝑆0). Rule T-App therefore reconstructs Γ ⊢𝑒1 𝑒2 :𝐹0 ∘𝑆0, exactly the type returned by the synthesizer. These are the two directions of the application case.
exercise 9.16.
Let 𝑆 =𝖭𝖺𝗍 ∨𝖡𝗈𝗈𝗅 and test 𝖡𝗈𝗈𝗅. Boolean algebra gives 𝑆∧𝖡𝗈𝗈𝗅=D𝖡𝗈𝗈𝗅,𝑆∧¬𝖡𝗈𝗈𝗅=D𝖭𝖺𝗍. Both are nonempty. In the then context, T-Var followed by T-Sub types 𝑥 :𝖡𝗈𝗈𝗅; in the else context the same two rules type 𝑥 :𝖭𝖺𝗍. Rule T-Case, with the two scope premises and the scrutinee lookup 𝑧 :𝑆 ⊢𝑧 :𝑆, concludes 𝑧:𝑆⊢𝖼𝖺𝗌𝖾𝖳𝗒𝗉𝖾 𝑧 𝖺𝗌 𝑥 𝗂𝗇𝖡𝗈𝗈𝗅⇒𝑥∣𝑥:𝖡𝗈𝗈𝗅∨𝖭𝖺𝗍. The order of the union records then before else; semantic equivalence makes it immaterial to subtyping.
Exercise 9.17.
Take (𝑎,𝑖)=(⟨4,5⟩,1),(𝑎′,𝑖′)=(⟨4,5⟩,2). Both arrays have the same unary type 𝖠𝗋𝗋𝖺𝗒 𝖭𝖺𝗍, and both indices have type 𝖭𝖺𝗍. The first pair satisfies 0 ≤1 <𝗅𝖾𝗇(⟨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 𝑖 <𝗅𝖾𝗇(𝑎), which is the next chapter’s proof obligation.