Prerequisites. Direct starred prerequisites: none. No later core chapter depends on this route.
The guarded corecursor of chapter 33 produces an unbounded stream, but a stream exposes only one fixed kind of observation. A server instead receives a request, chooses a response type from that request, emits the response, and repeats. A finite free-effect tree records only a bounded dialogue. Adding unrestricted recursion records the dialogue but leaves two questions unanswered: which recursive calls are productive, and when may a finite stretch of internal computation be ignored?
A dialogue determines the tree signature
Let 𝐸:U𝑖→U𝑖 assign to each answer type 𝑋 the type 𝐸(𝑋) of events whose environment response has type 𝑋. For the running server take events 𝖱𝖾𝖺𝖽:𝐸(ℕ),𝖶𝗋𝗂𝗍𝖾(𝑛):𝐸(𝟏)(𝑛:ℕ). A read continuation must accept a natural number. A write continuation must accept the unique unit value. This dependence is the reason that an event is indexed by its response type.
Fix 𝑅:U𝑖. The type 𝖨𝖳𝗋𝖾𝖾(𝐸,𝑅) has three observations.
Γ⊢𝑟:𝑅
Γ⊢𝖱𝖾𝗍(𝑟):𝖨𝖳𝗋𝖾𝖾(𝐸,𝑅)
ITree-Ret
Γ⊢𝑡:𝖨𝖳𝗋𝖾𝖾(𝐸,𝑅)
Γ⊢𝖳𝖺𝗎(𝑡):𝖨𝖳𝗋𝖾𝖾(𝐸,𝑅)
ITree-Tau
Γ⊢𝑒:𝐸(𝑋)Γ⊢𝑘:𝑋→𝖨𝖳𝗋𝖾𝖾(𝐸,𝑅)
Γ⊢𝖵𝗂𝗌(𝑒,𝑘):𝖨𝖳𝗋𝖾𝖾(𝐸,𝑅)
ITree-Vis
The constructor 𝖳𝖺𝗎 records one internal step. Recursive equations are admitted only when every recursive occurrence lies beneath 𝖳𝖺𝗎 or in a continuation supplied to 𝖵𝗂𝗌. This is the guard condition of the frozen tree signature.
The finite prefix that reads 2, writes 3, and stops is 𝖵𝗂𝗌(𝖱𝖾𝖺𝖽,𝜆𝑥.𝖵𝗂𝗌(𝖶𝗋𝗂𝗍𝖾(𝑥+1),𝜆𝑢.𝖱𝖾𝗍(𝑢))). The type of the outer continuation is ℕ→𝖨𝖳𝗋𝖾𝖾(𝐸,𝟏); after the answer 2 it produces the write event. The write continuation has type 𝟏→𝖨𝖳𝗋𝖾𝖾(𝐸,𝟏). If the outer continuation were given type 𝟏→𝖨𝖳𝗋𝖾𝖾(𝐸,𝟏), ITree-Vis would reject the read node before any recursion question arose.
The guarded equation 𝗌𝗎𝖼𝖼𝖲𝖾𝗋𝗏𝖾𝗋:=𝖵𝗂𝗌(𝖱𝖾𝖺𝖽,𝜆𝑥.𝖵𝗂𝗌(𝖶𝗋𝗂𝗍𝖾(𝑥+1),𝜆𝑢.𝖳𝖺𝗎(𝗌𝗎𝖼𝖼𝖲𝖾𝗋𝗏𝖾𝗋))) defines an element of 𝖨𝖳𝗋𝖾𝖾(𝐸,𝟎). Here 𝟎 is the empty return type. The recursive call lies below one visible read, one visible write, and one 𝖳𝖺𝗎, so it satisfies the guard condition.
Deleting both visible events leaves 𝗌𝗉𝗂𝗇:𝖨𝖳𝗋𝖾𝖾(𝐸,𝑅),𝗌𝗉𝗂𝗇:=𝖳𝖺𝗎(𝗌𝗉𝗂𝗇). This equation is guarded, but it never returns and never performs a visible event. Guardedness gives productivity of tree observations; it does not give termination or fairness.
For terms of the following types, 𝑡:𝖨𝖳𝗋𝖾𝖾(𝐸,𝐴),𝑘:𝐴→𝖨𝖳𝗋𝖾𝖾(𝐸,𝐵), define 𝖻𝗂𝗇𝖽(𝑡,𝑘):𝖨𝖳𝗋𝖾𝖾(𝐸,𝐵) by the observation equations 𝖻𝗂𝗇𝖽(𝖱𝖾𝗍(𝑎),𝑘)≡𝑘(𝑎),𝖻𝗂𝗇𝖽(𝖳𝖺𝗎(𝑡),𝑘)≡𝖳𝖺𝗎(𝖻𝗂𝗇𝖽(𝑡,𝑘)),𝖻𝗂𝗇𝖽(𝖵𝗂𝗌(𝑒,ℎ),𝑘)≡𝖵𝗂𝗌(𝑒,𝜆𝑥.𝖻𝗂𝗇𝖽(ℎ(𝑥),𝑘)).(𝐵𝑖𝑛𝑑−𝑅𝑒𝑡)(𝐵𝑖𝑛𝑑−𝑇𝑎𝑢)(𝐵𝑖𝑛𝑑−𝑉𝑖𝑠) The recursive calls in the last two clauses occur below 𝖳𝖺𝗎 and 𝖵𝗂𝗌, respectively.
For 𝑞:𝖨𝖳𝗋𝖾𝖾(𝐸,ℕ) and 𝑘:ℕ→𝖨𝖳𝗋𝖾𝖾(𝐸,𝐵), the expression 𝖻𝗂𝗇𝖽(𝑞,𝑘) is stuck when 𝑞 is neutral. The equations above do not inspect an unknown tree. By contrast, 𝖻𝗂𝗇𝖽(𝖳𝖺𝗎(𝖱𝖾𝗍(2)),𝑘)(𝐵𝑖𝑛𝑑−𝑇𝑎𝑢)≡𝖳𝖺𝗎(𝖻𝗂𝗇𝖽(𝖱𝖾𝗍(2),𝑘))(𝐵𝑖𝑛𝑑−𝑅𝑒𝑡)≡𝖳𝖺𝗎(𝑘(2)). This calculation retains the internal step. The equivalence introduced below will be permitted to erase it.
★☆☆ Calculate 𝖻𝗂𝗇𝖽(𝖳𝖺𝗎(𝖳𝖺𝗎(𝖱𝖾𝗍(3))),𝑘) through both silent steps. State which of the resulting equalities are judgmental and which later weak equivalence erases the two silent constructors.
Ordinary syntactic equality distinguishes 𝑡 from 𝖳𝖺𝗎(𝑡). Identifying every silent computation would instead identify 𝗌𝗉𝗂𝗇 with a return, because both could discard arbitrarily many silent steps. The relation must erase any finite number of silent steps while requiring an infinite silent computation to be matched by infinite silence.
The strong bisimulation𝗌𝖻𝗂𝗌𝗂𝗆(𝑡,𝑢) is the greatest relation that matches equal returns, identical visible events with related continuations at every answer, and one 𝖳𝖺𝗎 on each side.
For a relation 𝑆 on subtrees, let 𝖤𝗎𝗍𝗍𝖥(𝑆,𝑡,𝑢) be generated by the following rules.
𝑎=𝑏
𝖤𝗎𝗍𝗍𝖥(𝑆,𝖱𝖾𝗍(𝑎),𝖱𝖾𝗍(𝑏))
Eutt-Ret
∀𝑥:𝑋.𝑆(𝑘(𝑥),ℎ(𝑥))
𝖤𝗎𝗍𝗍𝖥(𝑆,𝖵𝗂𝗌(𝑒,𝑘),𝖵𝗂𝗌(𝑒,ℎ))
Eutt-Vis
𝑆(𝑡,𝑢)
𝖤𝗎𝗍𝗍𝖥(𝑆,𝖳𝖺𝗎(𝑡),𝖳𝖺𝗎(𝑢))
Eutt-Tau
𝖤𝗎𝗍𝗍𝖥(𝑆,𝑡,𝑢)
𝖤𝗎𝗍𝗍𝖥(𝑆,𝖳𝖺𝗎(𝑡),𝑢)
Eutt-TauL
𝖤𝗎𝗍𝗍𝖥(𝑆,𝑡,𝑢)
𝖤𝗎𝗍𝗍𝖥(𝑆,𝑡,𝖳𝖺𝗎(𝑢))
Eutt-TauR
The termination-sensitive weak equivalence𝖾𝗎𝗍𝗍(𝑡,𝑢) is the greatest fixed point of the monotone operator 𝑆↦𝖤𝗎𝗍𝗍𝖥(𝑆,−,−). The last two rules belong to the inductive layer 𝖤𝗎𝗍𝗍𝖥: they may remove only a finite number of unmatched silent steps before a coinductive appeal to 𝑆.
For every 𝑡, Eutt-TauL and the matching outer form of 𝑡 derive 𝖾𝗎𝗍𝗍(𝖳𝖺𝗎(𝑡),𝑡). No finite derivation of 𝖤𝗎𝗍𝗍𝖥 can turn 𝗌𝗉𝗂𝗇 into 𝖱𝖾𝗍(𝑟): after every finite sequence of Eutt-TauL uses, the left tree is again 𝗌𝗉𝗂𝗇, whereas the right tree exposes a return. This is the first boundary at which the inductive layer matters.
Proof. Reflexivity uses the coinductive relation 𝑆0(𝑡,𝑢):=(𝑡=𝑢). Equal returns use Eutt-Ret; equal visible nodes use Eutt-Vis and the coinduction hypothesis pointwise; equal silent nodes use Eutt-Tau.
For symmetry, close the converse relation 𝑆1(𝑡,𝑢):=𝖾𝗎𝗍𝗍(𝑢,𝑡). The return and visible cases exchange their two arguments. Eutt-TauL becomes Eutt-TauR, and Eutt-TauR becomes Eutt-TauL. Thus every generator is preserved.
Transitivity needs the strengthened relation 𝑆2(𝑡,𝑣):=∃𝑢.𝖾𝗎𝗍𝗍(𝑡,𝑢)∧𝖾𝗎𝗍𝗍(𝑢,𝑣). For a one-layer witness 𝑑, let 𝗌𝗍𝗋𝗂𝗉(𝑑) be its exposed return, visible, or matched-silent node together with the finite lists of left and right 𝖳𝖺𝗎 constructors removed by 𝑑. Apply this operation first to the left premise. Its middle observation fixes a finite prefix of the middle tree. Apply it to the right premise and extend the shorter of the two middle prefixes by matched uses of Eutt-Tau; the two exposures now name the same middle node. This finite realignment is possible because both prefix lists come from inductive 𝖤𝗎𝗍𝗍𝖥 derivations. If both exposed nodes are returns, their values are equal by transitivity of equality. If they are visible, both premises expose the same middle event, so the outer events coincide; apply the coinduction hypothesis to each pair of continuations. If the aligned nodes are silent, apply Eutt-Tau to the two related continuations. Every stripped constructor is restored with Eutt-TauL or Eutt-TauR. The stripping phases are finite because they are derivations in 𝖤𝗎𝗍𝗍𝖥. This proves that 𝑆2 is a post-fixed point and hence lies in the greatest fixed point.
A strong bisimulation uses only the return, visible, and matched-silent cases, which are the first three weak generators. Coinduction therefore gives the last implication. ◻
Assume 𝖾𝗎𝗍𝗍(𝑡,𝑢)and∀𝑎:𝐴.𝖾𝗎𝗍𝗍(𝑘(𝑎),ℎ(𝑎)). Then 𝖾𝗎𝗍𝗍(𝖻𝗂𝗇𝖽(𝑡,𝑘),𝖻𝗂𝗇𝖽(𝑢,ℎ)). Moreover, for 𝑘:𝐴→𝖨𝖳𝗋𝖾𝖾(𝐸,𝐵) and ℎ:𝐵→𝖨𝖳𝗋𝖾𝖾(𝐸,𝐶), 𝖾𝗎𝗍𝗍(𝖻𝗂𝗇𝖽(𝖻𝗂𝗇𝖽(𝑡,𝑘),ℎ),𝖻𝗂𝗇𝖽(𝑡,𝜆𝑥.𝖻𝗂𝗇𝖽(𝑘(𝑥),ℎ))).
Proof of Theorem 86.6 — Bind congruence and associativity
Proof. Use coinduction with pairs of binds as the strengthened relation. After a finite number of unmatched silent steps in 𝑡 or 𝑢, there are three aligned forms. A return pair reduces by (Bind-Ret) to 𝑘(𝑎) and ℎ(𝑎), related by hypothesis. A visible pair reduces by (Bind-Vis); Eutt-Vis applies, and each continuation is again a pair of binds in the coinductive relation. A matched silent pair reduces by (Bind-Tau) on both sides and uses Eutt-Tau. The unmatched constructors are restored with Eutt-TauL and Eutt-TauR. These are all generators of 𝖤𝗎𝗍𝗍𝖥.
For associativity, use the coinductive relation containing the displayed pair for every subtree 𝑡. At a return, both sides compute to 𝖻𝗂𝗇𝖽(𝑘(𝑎),ℎ). At a visible node, the two uses of (Bind-Vis) expose the same event and put the continuation pair back in the relation. At a silent node, both uses of (Bind-Tau) expose matched silent constructors. These three cases establish the post-fixed-point obligation; congruence alone is not being used as associativity. ◻
★★☆ Prove that 𝖻𝗂𝗇𝖽(𝗌𝗉𝗂𝗇,𝑘) is strongly bisimilar to 𝗌𝗉𝗂𝗇. Then use the return case of definition 86.4 to show that it is not weakly equivalent to 𝖱𝖾𝗍(𝑏) for any 𝑏:𝐵. State where termination sensitivity enters both arguments.
A handler from 𝐸 to interaction trees over 𝐹 is a dependent function 𝐻:∏𝑋:U𝑖𝐸(𝑋)→𝖨𝖳𝗋𝖾𝖾(𝐹,𝑋). Its interpreter 𝗂𝗇𝗍𝖾𝗋𝗉(𝐻,−) is determined by 𝗂𝗇𝗍𝖾𝗋𝗉(𝐻,𝖱𝖾𝗍(𝑟))≡𝖱𝖾𝗍(𝑟),𝗂𝗇𝗍𝖾𝗋𝗉(𝐻,𝖳𝖺𝗎(𝑡))≡𝖳𝖺𝗎(𝗂𝗇𝗍𝖾𝗋𝗉(𝐻,𝑡)),𝗂𝗇𝗍𝖾𝗋𝗉(𝐻,𝖵𝗂𝗌(𝑒,𝑘))≡𝖻𝗂𝗇𝖽(𝐻(𝑒),𝜆𝑥.𝗂𝗇𝗍𝖾𝗋𝗉(𝐻,𝑘(𝑥))).(𝐼𝑛𝑡𝑒𝑟𝑝−𝑅𝑒𝑡)(𝐼𝑛𝑡𝑒𝑟𝑝−𝑇𝑎𝑢)(𝐼𝑛𝑡𝑒𝑟𝑝−𝑉𝑖𝑠)
Proof of Theorem 86.8 — Interpreter identity and composition
Proof. For identity, coinduct on 𝑡. In the calculation below, I-Vis abbreviates (Interp-Vis), B-Vis abbreviates (Bind-Vis), and B-Ret abbreviates (Bind-Ret). Put 𝑞𝑥:=𝗂𝗇𝗍𝖾𝗋𝗉(𝗍𝗋𝗂𝗀𝗀𝖾𝗋,𝑘(𝑥)). The return and silent cases follow from (Interp-Ret) and (Interp-Tau). At a visible node, 𝗂𝗇𝗍𝖾𝗋𝗉(𝗍𝗋𝗂𝗀𝗀𝖾𝗋,𝖵𝗂𝗌(𝑒,𝑘))𝐼−𝑉𝑖𝑠≡𝖻𝗂𝗇𝖽(𝖵𝗂𝗌(𝑒,𝖱𝖾𝗍),𝜆𝑥.𝑞𝑥)𝐵−𝑉𝑖𝑠≡𝖵𝗂𝗌(𝑒,𝜆𝑥.𝖻𝗂𝗇𝖽(𝖱𝖾𝗍(𝑥),𝜆𝑦.𝑞𝑦))𝐵−𝑅𝑒𝑡≡𝖵𝗂𝗌(𝑒,𝜆𝑥.𝑞𝑥). Apply Eutt-Vis and the coinduction hypothesis.
For composition, strengthen the coinduction relation with the displayed pair of interpretations. The visible case expands the interpreter twice and uses the associativity clause of theorem 86.6. Reassociation leaves the resulting handler exactly 𝐽⋄𝐻. Return and silent cases use the corresponding interpreter equations. Thus all three observations match. ◻
For event families 𝐸 and 𝐹, their tagged sum is (𝐸+𝐸𝐹)(𝑋):=𝐸(𝑋)+𝐹(𝑋). Handlers 𝐻:𝐸⇒𝖨𝖳𝗋𝖾𝖾(𝐺) and 𝐽:𝐹⇒𝖨𝖳𝗋𝖾𝖾(𝐺) determine the copair [𝐻,𝐽](𝗂𝗇𝗅(𝑒)):=𝐻(𝑒),[𝐻,𝐽](𝗂𝗇𝗋(𝑓)):=𝐽(𝑓). The tags are retained even when 𝐸(𝑋)=𝐹(𝑋); deleting them makes it impossible to select the intended handler branch.
★★☆ Let 𝐸 contain reads and 𝐹 contain writes. Define handlers for both into a state-and-output signature 𝐺, form their copair, and calculate the interpretation of one read followed by one write. Show at which step the 𝗂𝗇𝗅 or 𝗂𝗇𝗋 tag selects the handler.
★★★ Define 𝗆𝖺𝗉(𝑓,𝑡):=𝖻𝗂𝗇𝖽(𝑡,𝜆𝑥.𝖱𝖾𝗍(𝑓(𝑥))). Prove 𝖾𝗎𝗍𝗍(𝗆𝖺𝗉(𝑔,𝗆𝖺𝗉(𝑓,𝑡)),𝗆𝖺𝗉(𝑔∘𝑓,𝑡)) by coinduction. Write the visible and unmatched silent cases; the return case alone is not a complete proof.
For a finite list ¯𝑥=[𝑥0,…,𝑥𝑚−1] of environment replies and a silent-step budget 𝑏:ℕ, use the partial observer 𝗈𝖻𝗌𝖾𝗋𝗏𝖾𝑏,2𝑚(𝑡,¯𝑥). It skips at most 𝑏 consecutive 𝖳𝖺𝗎 nodes and records the first 2𝑚 visible events. At a read it feeds the next 𝑥𝑞 to the continuation. At a write it feeds the unit value. It reports 𝗌𝗂𝗅𝖾𝗇𝗍-𝗉𝗋𝖾𝖿𝗂𝗑 if its entire budget is spent on 𝖳𝖺𝗎 nodes. This result is not a termination claim.
For every 𝑚:ℕ, budget 𝑏≥1, and input list [𝑥0,…,𝑥𝑚−1], the first 2𝑚 visible events of 𝗌𝗎𝖼𝖼𝖲𝖾𝗋𝗏𝖾𝗋 are 𝗋𝖾𝖺𝖽(𝑥0);𝗐𝗋𝗂𝗍𝖾(𝑥0+1);⋯;𝗋𝖾𝖺𝖽(𝑥𝑚−1);𝗐𝗋𝗂𝗍𝖾(𝑥𝑚−1+1). Inserting a silent prefix of length at most 𝑏 before any visible event preserves this prefix. Every finite insertion is therefore accepted by some finite choice of 𝑏. The observer applied to 𝗌𝗉𝗂𝗇 reports 𝗌𝗂𝗅𝖾𝗇𝗍-𝗉𝗋𝖾𝖿𝗂𝗑 at every finite budget and never reports a return.
Proof. Induct on the input list. The empty list requests no visible events. For 𝑥::¯𝑥, unfold definition 86.2. The first visible node is 𝖱𝖾𝖺𝖽; feeding 𝑥 exposes 𝖶𝗋𝗂𝗍𝖾(𝑥+1); feeding unit exposes 𝖳𝖺𝗎(𝗌𝗎𝖼𝖼𝖲𝖾𝗋𝗏𝖾𝗋). The observer skips this one silent node and the induction hypothesis computes the remaining prefix from ¯𝑥. Each additional finite silent prefix is removed by one more finite observer step, so it does not change the recorded events.
For 𝗌𝗉𝗂𝗇, every finite unfolding uses 𝗌𝗉𝗂𝗇≡𝖳𝖺𝗎(𝗌𝗉𝗂𝗇). Induction on the search budget shows that no visible or return node is reached. The observer therefore reports 𝗌𝗂𝗅𝖾𝗇𝗍-𝗉𝗋𝖾𝖿𝗂𝗑 rather than termination. ◻
At input [2,4], the calculation gives 𝗋𝖾𝖺𝖽(2);𝗐𝗋𝗂𝗍𝖾(3);𝗋𝖾𝖺𝖽(4);𝗐𝗋𝗂𝗍𝖾(5). This is a finite-observation theorem. It neither schedules competing servers nor proves fairness for an external event implementation.
Suggested first pass.
None of these problems is a prerequisite. Begin with exercise 86.1 and exercise 86.3; for the practical sequence, complete stages 1–3 before stages 4–5.
★★★ Reconstruct the transitivity proof of theorem 86.5 for the case in which the left premise strips two silent nodes and the right premise strips one. Display the strengthened relation, the aligned observation, and the three rules that restore the silent nodes.
★★☆ Give a handler that maps each write event to two writes. Calculate the first four source events and the corresponding target prefix. Then give a nonproductive host-language function that the frozen guarded interpreter signature does not admit; identify the missing guard.
★★★Practical project.recursive-effect-interpreter Build a Kappa finite observer in five declared stages: (1) the tree/event representation, (2) the visible-prefix observer, (3) the successor server, (4) a weak-step test that ignores one inserted silent step, and (5) a budgeted silent-divergence detector. Maintain the invariant that every recorded event is visible and appears in protocol order. On input [2,4], print exactly read 2; write 3; read 4; write 5; the tree with one inserted silent step must print the same prefix; and a pure silent loop must print silent-prefix, never a return. Mutating the write response from 𝑥+1 to 𝑥 must fail the named prefix test.
Sources. The tree signature, guarded bind, termination-sensitive weak bisimulation, and interpreter laws follow Xia, Zakowski, He, Hur, Malecha, Pierce, and Zdancewic’s frozen POPL interaction-tree development. Its Figure 4 uses an inductive layer inside the greatest fixed point so that only finitely many unmatched silent steps are removed. The Kappa observer checks the finite server calculation; it is not a replay of the source’s Rocq proofs. The precise source is [yXZH^+20].