Exercise 32.1.
Each request body has effect {𝖺𝗌𝗄}. Before the surrounding outer handler is applied, the first displayed phrase still has residual effect {𝖺𝗌𝗄}, while the inner handler in each of the latter two phrases discharges that request and leaves empty residual effect. After the active 𝐻𝗈𝗎𝗍 is wrapped around each whole phrase, all three complete programs have empty residual effect.
For the first phrase, nearest-name lookup finds the surrounding 𝐻𝗈𝗎𝗍. For the second, the dynamically nearer 𝐻𝗂𝗇 handles the request before the outer handler is reached. For the third, 𝗎𝗇𝖽𝖾𝗋𝖨𝗇𝗇𝖾𝗋 invokes the closure under 𝐻𝗂𝗇, so nearest-name lookup again selects 𝐻𝗂𝗇.
After replacing each request by 𝖺𝗌𝗄@𝐻𝗈𝗎𝗍(), all three requests carry the same explicit authority and therefore select 𝐻𝗈𝗎𝗍; the inner same-operation handler is skipped in the latter two programs. Thus identical request effects and identical empty residual effects coexist with different handler identities under nearest-name lookup. Effect presence does not encode the authority used to resolve the request.
exercise 32.2.
The exercise assumption gives Ω(𝐹) =1 →𝖨𝗇𝗍, fixing the operation types required by X-Handle. Let the answer type of the whole handler be 𝖨𝗇𝗍. In the handled body, 𝐹 :1 →𝖨𝗇𝗍, hence ∅∣𝐹:1→𝖨𝗇𝗍∣∅⊢𝐹(()):𝖨𝗇𝗍. Rule X-Var gives 𝑥 :𝖨𝗇𝗍 ⊢𝑥 :𝖨𝗇𝗍; X-Expr lifts that expression to a statement judgment, and X-Val therefore gives ∅∣𝐹:1→𝖨𝗇𝗍∣∅⊢𝗏𝖺𝗅 𝑥=𝐹(());𝑥:𝖨𝗇𝗍. In the clause, the operation argument has type 1, and the continuation block has type 𝑘:𝖨𝗇𝗍→𝖨𝗇𝗍. The numeral 7 has type 𝖨𝗇𝗍, so X-Call gives 𝑢:1∣𝑘:𝖨𝗇𝗍→𝖨𝗇𝗍∣∅⊢𝑘(7):𝖨𝗇𝗍. Rule X-Handle now concludes the displayed handler has type 𝖨𝗇𝗍. The four answer-type occurrences are: the handled body, the handler clause, the continuation codomain, and the entire handler; all are 𝖨𝗇𝗍.
exercise 32.3.
The restriction occurs at three mutually reinforcing points.
Value types 𝜏 do not contain block types 𝜎.
The value context Γ stores only bindings 𝑥 :𝜏; block bindings occur only in Δ.
The expression grammar contains values and value variables, but not block variables or block abstractions.
Consequently 𝗏𝖺𝗅 𝑥=𝐹;𝑥 has no derivation: X-Val requires a statement premise, while X-BVar concludes only a block judgment. The block abstraction {() ⇒𝐹} fails for the same reason in the body premise of X-Block. Finally, in 𝐺(𝐹,𝐹), the first occurrence of 𝐹 is in a value-argument position and would require an expression judgment; only the second occurrence is a legal block argument. By contrast, 𝐺((),𝐹) is derivable by X-Call: () :1 is the value argument and 𝐹 :1 →𝖨𝗇𝗍 is the block argument. The call is well typed while the matching delimiter is active, but no rule turns its block argument into a returnable value.
exercise 32.4.
Write Ξ0 for the label context outside the matching delimiter. Inversion of the redex typing gives (Ξ0,ℓ:𝜏)(ℓ)=𝜏,Γ⊢𝑣:𝜏1,Γ,𝑥:𝜏1∣Δ,𝑘:𝜏0→𝜏∣Ξ0⊢𝑠ℎ:𝜏. For the displayed context and fresh 𝑦 :𝜏0, typed context replacement gives Γ,𝑦:𝜏0∣Δ∣Ξ0⊢#ℓ{𝗏𝖺𝗅 𝑧=𝑦;𝑧}:𝜏. Rule X-Block therefore gives the reified continuation type Γ∣Δ∣Ξ0⊢{(𝑦:𝜏0)⇒#ℓ{𝗏𝖺𝗅 𝑧=𝑦;𝑧}}:𝜏0→𝜏. Value substitution replaces 𝑥 by 𝑣, and block substitution replaces 𝑘 by this continuation, so the handler body remains typed at 𝜏 in the outer context Ξ0. If 𝐻ℓ contained an inner delimiter #ℓ, it would not belong to the no-ℓ-binding grammar 𝐻ℓ; the context-replacement premise used to reconstruct the unique matching delimiter would therefore be unavailable. By contrast, a crossed #ℓ′ with ℓ′ ≠ℓ belongs to the later suffix Ξ+. It is retained inside the reified continuation and is absent from the handler body’s birth-prefix derivation under Ξ0.
exercise 32.5.
Under nearest-name lookup the call stack is 𝐻𝗂𝗇::𝐻𝗈𝗎𝗍::⋯. Invoking 𝑞 produces a request named 𝖺𝗌𝗄. The first matching stack entry is 𝐻𝗂𝗇, so the execution returns 9, even though the closure was created under 𝐻𝗈𝗎𝗍.
In capability-passing style write 𝑞(𝐹):=𝐹(()),𝗎𝗇𝖽𝖾𝗋𝖨𝗇𝗇𝖾𝗋(𝑞,𝐹𝗈𝗎𝗍):=𝗁𝖺𝗇𝖽𝗅𝖾𝐻𝗂𝗇(𝑞(𝐹𝗈𝗎𝗍)). The block argument 𝐹𝗈𝗎𝗍 names the outer capability. The inner handler does not replace the argument, so the request reaches 𝐻𝗈𝗎𝗍 and returns 7.
exercise 32.6.
Assume Σ(𝖠𝗌𝗄) =1 →𝖨𝗇𝗍 and Σ(𝖫𝗈𝗀) =𝖨𝗇𝗍 →1. The block parameter translates as 𝖢𝖺𝗉𝖳𝗒(1→𝖨𝗇𝗍/{𝖠𝗌𝗄})=(1,1→𝖨𝗇𝗍)→𝖨𝗇𝗍. Since 𝑞’s declared effect is {𝖫𝗈𝗀}, its translated type is ((1,1→𝖨𝗇𝗍)→𝖨𝗇𝗍,𝖨𝗇𝗍→1)→𝖨𝗇𝗍. Under the fixed canonical ordering, the second parameter position of the inner type corresponds to 𝖠𝗌𝗄, and the final parameter position of the outer type corresponds to 𝖫𝗈𝗀. The direct 𝖠𝗌𝗄 requirement in the body is not in the declared set of 𝑞; rule E-Def therefore makes it a definition-site capability. Writing that closed-over capability as 𝖠𝗌𝗄𝖽𝖾𝖿, the target has the shape 𝖽𝖾𝖿 𝑞={(𝑔,𝖫𝗈𝗀)⇒𝗏𝖺𝗅 𝑎=𝑔((),𝖠𝗌𝗄𝖽𝖾𝖿);𝗏𝖺𝗅 𝑏=𝖠𝗌𝗄𝖽𝖾𝖿(());𝗏𝖺𝗅 𝑢=𝖫𝗈𝗀(𝑎);𝑏};𝑠. A call is 𝑞(𝑔,𝖫𝗈𝗀𝖼𝖺𝗅𝗅). Thus the capability passed to 𝑔 is 𝖠𝗌𝗄𝖽𝖾𝖿, while the capability required by 𝑞’s own declared effect is 𝖫𝗈𝗀𝖼𝖺𝗅𝗅.
exercise 32.7.
Rule T-HVar gives Δ∣𝑃∣Γ,𝑥:1∣Ξ⊢ℎ:𝖥∣ℎ.𝗅𝖻𝗅. Then T-Up gives the pure operation value ⇑ℎ:[1→[𝖨𝗇𝗍]ℎ.𝗅𝖻𝗅]∅. Rule T-Sub widens its immediate effect from ∅ to ℎ.𝗅𝖻𝗅, using reflexive type subtyping. A second use of T-Sub widens 𝑥 :[1]∅ to 𝑥 :[1]ℎ.𝗅𝖻𝗅. The two premises and the latent result effect now have the one common effect required by T-App, which yields Δ∣𝑃∣Γ,𝑥:1∣Ξ⊢⇑ℎ𝑥:[𝖨𝗇𝗍]ℎ.𝗅𝖻𝗅. Rule WF-Unit supplies Δ ∣𝑃 ∣Ξ ⊢1 𝗍𝗒𝗉𝖾. Finally T-Lam gives Δ∣𝑃∣Γ∣Ξ⊢𝜆𝑥:1.⇑ℎ𝑥:[1→[𝖨𝗇𝗍]ℎ.𝗅𝖻𝗅]∅. If ℎ is instantiated by 𝐻ℓ, the latent effect becomes ℓ. A delimiter cannot discharge it while returning that function, because T-Down requires ℓ ∉fl(𝑇,¯𝑒); here ℓ occurs inside the returned function type.
exercise 32.8.
After the two handler-beta steps, the inner delimiter contains 𝐾𝑖=𝗅𝖾𝗍 𝑧:𝖨𝗇𝗍=[] 𝗂𝗇 ⇑𝐻ℓ𝑜𝑜(),𝐾𝑖[⇑𝐻ℓ𝑖𝑖()]. The context 𝐾𝑖 does not bind ℓ𝑖. Rule Tun-Down-up therefore substitutes 𝑥↦(),𝑘↦𝜆𝑦:𝖨𝗇𝗍.⇓ℓ𝑖(𝗅𝖾𝗍 𝑧:𝖨𝗇𝗍=𝑦 𝗂𝗇 ⇑𝐻ℓ𝑜𝑜()) into the body of 𝐻𝑖. Since that body is 𝑘(9), the inner step gives (𝜆𝑦:𝖨𝗇𝗍.⇓ℓ𝑖(𝗅𝖾𝗍 𝑧:𝖨𝗇𝗍=𝑦 𝗂𝗇 ⇑𝐻ℓ𝑜𝑜()))9, which reduces to ⇓ℓ𝑖(⇑𝐻ℓ𝑜𝑜()). The outer delimiter now sees 𝐾𝑜=⇓ℓ𝑖[],𝐾𝑜[⇑𝐻ℓ𝑜𝑜()]. Because ℓ𝑖 ≠ℓ𝑜, 𝐾𝑜 does not bind ℓ𝑜. The second Tun-Down-up step substitutes 𝑥↦(),𝑘↦𝜆𝑦:𝖨𝗇𝗍.⇓ℓ𝑜(⇓ℓ𝑖𝑦) into the body of 𝐻𝑜. Since that body is 𝑘(7), the immediate reduct is (𝜆𝑦:𝖨𝗇𝗍.⇓ℓ𝑜(⇓ℓ𝑖𝑦))7, which reduces to 7 after both value delimiters disappear. If ℓ𝑖 =ℓ𝑜, then 𝐾𝑜 itself binds the target label, so it is not an admissible no-binding context for the outer rule. The dynamically inner matching delimiter must handle the request instead.
exercise 32.9.
The function clause requires related unit arguments 𝑢1,𝑢2: V[[1]](𝑢1,𝑢2), which unfolds to 𝑢1 =() ∧𝑢2 =(). It must then establish T[[[1]ℎ.𝗅𝖻𝗅]]𝜌𝛿(𝑣1𝑢1,𝑣2𝑢2). When the bodies invoke ⇑ℎ, the relevant semantic effect clause is U𝐴. The handler environment has the form 𝜌(ℎ)=⟨𝐻ℓ11,𝐻ℓ22,𝜂⟩. It supplies both concrete handlers and the relation 𝜂. The label interpretation W[[ℎ.𝗅𝖻𝗅]] is exactly 𝜂, and U𝐴 requires the two requests to use 𝐻ℓ11 and 𝐻ℓ22, to have related unit arguments, and to produce outcomes related at unit. Thus the handler identity enters through 𝜌, not through operation-name equality.
Exercise 32.10.
Both 𝐻𝗈𝗎𝗍 and 𝐻𝗂𝗇 handle 𝖺𝗌𝗄, so the row {𝖺𝗌𝗄} is present in either case, but the handlers return 7 and 9. Missing premise: a handler identity or authority relation.
A capability block for 𝖺𝗌𝗄 grants authority to invoke that handler. It says nothing about a separately allocated mutable cell and does not prevent aliases to that cell. Missing premise: an ownership or separation invariant for memory.
The two closed handlers that always return 7 and 9 are both effect-safe, yet a context observes different integers. Missing premise: a relational abstraction or noninterference condition.
Let source terms 𝑡1,𝑡2 be logically related. A faulty compiler may translate 𝑡1 correctly and translate 𝑡2 to divergence. Source logical relatedness says nothing about that arbitrary mapping. Missing premise: a compiler simulation or semantic-preservation theorem.
Exercise 32.11.
The handler step chooses fresh ℓ and gives #ℓ{𝗏𝖺𝗅 𝑥=𝖼𝖺𝗉ℓ{(𝑥,𝑘)⇒𝑘(𝑥)}(3);𝑥}. The capability redex reifies 𝑘𝑐={(𝑦:𝖨𝗇𝗍)⇒#ℓ{𝗏𝖺𝗅 𝑥=𝑦;𝑥}}:𝖨𝗇𝗍→𝖨𝗇𝗍 and substitutes 3 for the clause parameter, yielding 𝑘𝑐(3). Block beta gives #ℓ{𝗏𝖺𝗅 𝑥 =3;𝑥}; value beta gives #ℓ{3}; delimiter return gives 3. Every term is typed at 𝖨𝗇𝗍 under the label context appropriate to its delimiter.
Replacing the body by the block variable 𝐹 fails before runtime. The handled-body premise of X-Handle requires a statement judgment; X-BVar derives only a block judgment. Thus no inversion case gives 𝐹 a value type that could escape the handler.
Exercise 32.12.
For E-Def, let the annotated effect set be 𝜀0 ={𝐹1,…,𝐹𝑛} in its canonical order. The induction hypothesis types the translated body under 𝖢𝖺𝗉𝖳𝗒(Δ,¯𝑔:¯𝜎),𝖢𝖺𝗉𝖤𝖿𝖿(𝜀′0). Keep the definition-site capabilities 𝖢𝖺𝗉𝖤𝖿𝖿(𝜀′0 ∖𝜀0) in the surrounding block context and add every annotated capability in 𝜀0 as an ordered formal parameter. Their union contains all capabilities in 𝜀′0; if an annotation is unused, target weakening supplies its formal binding. Abstracting over the ordinary parameters, translated block parameters, and 𝐹1,…,𝐹𝑛 therefore gives exactly 𝖢𝖺𝗉𝖳𝗒((¯𝜏,¯𝜎) →𝜏0/𝜀0). The continuation induction hypothesis is weakened to the union of its own capabilities and the retained definition-site capabilities, after which X-Def applies.
For E-Try, put Θ=𝖢𝖺𝗉𝖳𝗒(Δ),𝖢𝖺𝗉𝖤𝖿𝖿((𝜀∖{𝐹})∪𝜀ℎ). The translated handled statement weakens to Θ,𝐹 :𝜏1 →𝜏0, where the terminal binding is the capability introduced by the handler and shadows any outer 𝐹 required by the clause. The translated clause weakens to Θ,𝗋𝖾𝗌𝗎𝗆𝖾 :𝜏0 →𝜏. Rule X-Handle then produces the target statement at 𝜏 under exactly Θ. Thus source set subtraction corresponds to binding the handled occurrence of 𝐹, while an occurrence of 𝐹 in 𝜀ℎ remains available to the clause as an outer capability.
If one occurrence ordered {𝐹,𝐺} as (𝐹,𝐺) and another as (𝐺,𝐹), the same source block type would translate to two different positional block types and calls could swap capabilities. A fixed canonical order is therefore part of the syntax translation and of the induction invariant.
Exercise 32.13.
In the T-Down case, its first premise gives ℓ ∉dom(Ξ). Choose one label ℓ∗ fresh for Ξ and for both closing environments, alpha-rename the bound label before either closing substitution, and use the common extension Ξ+=Ξ,ℓ∗:[𝑇]¯𝑒. The induction hypothesis relates the guarded bodies at effects containing that common label. For a pair of related evaluation contexts in K, the semantic stuck relation S requires ℓ∗ ⇝̸𝐾𝑖. Its concrete-effect decomposition has ¯ℓ1 =¯ℓ2 =(ℓ∗). A matching pair of tunneled requests is classified by U𝐵; Tun-Down-up contracts both sides, and the outcome relation is fed back through the reified continuations 𝜆𝑦. ⇓ℓ∗𝐾𝑖[𝑦]. The leading later modality lowers the numerical index before the recursive T-use.
Because the type and effect well-formedness premises are checked under Ξ, which lacks ℓ∗, rule WF-Label derives ℓ∗ ∉fl(𝑇,¯𝑒). Neither the result type nor the residual effect interpretation can therefore mention the fresh label. Restricting Ξ+ back to Ξ yields the delimiter conclusion. No separate Kripke future-world restriction is involved.
Exercise 32.14.
For the first pair, use two closed programs that each handle their only 𝖺𝗌𝗄 request, one with 𝐻𝗈𝗎𝗍 and one with 𝐻𝗂𝗇. Both are effect-safe: neither can become stuck on an unhandled request. They return 7 and 9, so an integer-observing context distinguishes them. This refutes “effect safety implies contextual equivalence”.
For the second pair, take two beta-equivalent pure terms, for example (𝜆𝑥.𝑥)() and (). They are contextually equivalent in the source. Define a deliberately faulty compiler that maps the first to the target value () and the second to divergence. The target programs differ, so source equivalence alone does not imply compiler correctness. The missing premise is a semantic-preservation or simulation theorem for the compiler.
Exercise 32.15.
Ownership: a file token needs exclusive state-transition authority, not merely an effect name.
Tunnelling: the request must cross an unrelated same-operation handler and match its lexical handler identity.
Effect rows: the requirement concerns the set of possible exception operations, not one handler instance.
Control-flow linearity: the invariant counts resumption uses.
Capture sets: the property is which capability value the closure may mention.
Explicit capabilities with a label scope: the call must be rejected once the matching delimiter has left the dynamic context.
Effect rows are insufficient for item 2 because they do not distinguish the inner and outer handler instances. A capture set is insufficient for item 4: knowing that a closure mentions a resumption does not limit the number of calls to it.