A finite list can be inspected until a constructor closes it. A stream has no last constructor to reach. Its correctness question is instead finite: after any requested number of tail observations, can the next head be produced? A definition that answers every such request is productive: every finite sequence of tail observations can be followed by a head observation that returns an element.
Streams are given by observations
Fix 𝐴:U𝑖. The signature 𝑇𝖼𝗈 extends 𝑇0 by one coinductive record and a guarded corecursor.
A stream over 𝐴 is an element of 𝖲𝗍𝗋𝖾𝖺𝗆(𝐴). It is observed by two destructors: 𝗁𝖾𝖺𝖽 returns the next element and 𝗍𝖺𝗂𝗅 returns the stream after that element.
Γ⊢𝐴:U𝑖
Γ⊢𝖲𝗍𝗋𝖾𝖺𝗆(𝐴):U𝑖
Stream-form
Γ⊢𝑠:𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)
Γ⊢𝗁𝖾𝖺𝖽(𝑠):𝐴
Head
Γ⊢𝑠:𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)
Γ⊢𝗍𝖺𝗂𝗅(𝑠):𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)
Tail
For a state type 𝑆:U𝑗, an output ℎ:𝑆→𝐴, a transition 𝑡:𝑆→𝑆, and an initial state 𝑥:𝑆, the guarded corecursor has type
Γ⊢𝑆:U𝑗Γ⊢ℎ:𝑆→𝐴Γ⊢𝑡:𝑆→𝑆Γ⊢𝑥:𝑆
Γ⊢𝖼𝗈𝗋𝖾𝖼𝐴(𝑆,ℎ,𝑡,𝑥):𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)
Stream-corec
with judgmental observation equations 𝗁𝖾𝖺𝖽(𝖼𝗈𝗋𝖾𝖼𝐴(𝑆,ℎ,𝑡,𝑥))≡ℎ(𝑥),𝗍𝖺𝗂𝗅(𝖼𝗈𝗋𝖾𝖼𝐴(𝑆,ℎ,𝑡,𝑥))≡𝖼𝗈𝗋𝖾𝖼𝐴(𝑆,ℎ,𝑡,𝑡(𝑥)).(𝐶𝑜𝑟𝑒𝑐−ℎ𝑒𝑎𝑑)(𝐶𝑜𝑟𝑒𝑐−𝑡𝑎𝑖𝑙) The recursive stream occurs only on the right of a tail observation. This placement is the guarded-call invariant of this fragment.
The rules do not add a constructor 𝐴→𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)→𝖲𝗍𝗋𝖾𝖺𝗆(𝐴). Such a constructor would invite dependent pattern matching on coinductive data and a restricted unfolding rule for recursively defined coinductive values. The destructor presentation makes the two equations that compute into the primitive interface.
Define 𝗇𝗍𝗁:ℕ→𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)→𝐴 by structural recursion on its natural-number argument: 𝗇𝗍𝗁(𝟢,𝑠):=𝗁𝖾𝖺𝖽(𝑠),𝗇𝗍𝗁(𝗌𝗎𝖼(𝑛),𝑠):=𝗇𝗍𝗁(𝑛,𝗍𝖺𝗂𝗅(𝑠)). The observation depth of 𝗇𝗍𝗁(𝑛,𝑠) is 𝑛: it requests 𝑛 tails and then one head.
For 𝑆,ℎ,𝑡,𝑥 as in definition 85.1 and every 𝑛:ℕ, 𝖨𝖽𝐴(𝗇𝗍𝗁(𝑛,𝖼𝗈𝗋𝖾𝖼𝐴(𝑆,ℎ,𝑡,𝑥)),ℎ(𝑡𝑛(𝑥))) is inhabited, where 𝑡0(𝑥):=𝑥 and 𝑡𝗌𝗎𝖼(𝑛)(𝑥):=𝑡𝑛(𝑡(𝑥)). Hence every finite observation of a guarded corecursive stream is identified with an application of ℎ at a finite state iterate.
Proof of Theorem 85.3 — Productivity of guarded corecursion
Proof. Induct on 𝑛 with the state 𝑥:𝑆 quantified in the motive. At zero, the required identification is reflexivity after the judgmental calculation 𝗇𝗍𝗁(𝟢,𝖼𝗈𝗋𝖾𝖼𝐴(𝑆,ℎ,𝑡,𝑥))𝑑𝑒𝑓𝑖𝑛𝑖𝑡𝑖𝑜𝑛85.2≡𝗁𝖾𝖺𝖽(𝖼𝗈𝗋𝖾𝖼𝐴(𝑆,ℎ,𝑡,𝑥))(𝐶𝑜𝑟𝑒𝑐−ℎ𝑒𝑎𝑑)≡ℎ(𝑥). For a successor, instantiate the induction hypothesis at 𝑡(𝑥): 𝗇𝗍𝗁(𝗌𝗎𝖼(𝑛),𝖼𝗈𝗋𝖾𝖼𝐴(𝑆,ℎ,𝑡,𝑥))𝑑𝑒𝑓𝑖𝑛𝑖𝑡𝑖𝑜𝑛85.2≡𝗇𝗍𝗁(𝑛,𝗍𝖺𝗂𝗅(𝖼𝗈𝗋𝖾𝖼𝐴(𝑆,ℎ,𝑡,𝑥)))(𝐶𝑜𝑟𝑒𝑐−𝑡𝑎𝑖𝑙)≡𝗇𝗍𝗁(𝑛,𝖼𝗈𝗋𝖾𝖼𝐴(𝑆,ℎ,𝑡,𝑡(𝑥)))IH(𝑡(𝑥))=ℎ(𝑡𝑛(𝑡(𝑥)))𝑖𝑡𝑒𝑟𝑎𝑡𝑒𝑑𝑒𝑓𝑖𝑛𝑖𝑡𝑖𝑜𝑛≡ℎ(𝑡𝗌𝗎𝖼(𝑛)(𝑥)). The middle relation is the identification obtained from the induction hypothesis. Each closed numeral instance is judgmental by repeated use of (Corec-tail) followed by (Corec-head); the theorem for a neutral 𝑛 is propositional because structural recursion on 𝑛 is stuck. ◻
The equation 𝑠=𝗍𝖺𝗂𝗅(𝑠) is not an instance of Stream-corec: no output function produces a head before the recursive transition. More subtle productive programs may also fail to have the corecursor form when productivity depends on the behavior of a higher-order argument. Thus this fragment proves productivity for terms generated by its rule; it does not describe every productive stream program.
For 𝑥:𝐴 and 𝑓:𝐴→𝐴, define 𝗂𝗍𝖾𝗋𝖺𝗍𝖾(𝑓,𝑥):=𝖼𝗈𝗋𝖾𝖼𝐴(𝐴,𝜆𝑎.𝑎,𝑓,𝑥). Equations (Corec-head) and (Corec-tail) give 𝗁𝖾𝖺𝖽(𝗂𝗍𝖾𝗋𝖺𝗍𝖾(𝑓,𝑥))≡𝑥,𝗍𝖺𝗂𝗅(𝗂𝗍𝖾𝗋𝖺𝗍𝖾(𝑓,𝑥))≡𝗂𝗍𝖾𝗋𝖺𝗍𝖾(𝑓,𝑓(𝑥)). For 𝑔:𝐴→𝐵 and 𝑠:𝖲𝗍𝗋𝖾𝖺𝗆(𝐴), define 𝗆𝖺𝗉(𝑔,𝑠):=𝖼𝗈𝗋𝖾𝖼𝐵(𝖲𝗍𝗋𝖾𝖺𝗆(𝐴),𝜆𝑢.𝑔(𝗁𝖾𝖺𝖽(𝑢)),𝗍𝖺𝗂𝗅,𝑠). It computes by observation: 𝗁𝖾𝖺𝖽(𝗆𝖺𝗉(𝑔,𝑠))≡𝑔(𝗁𝖾𝖺𝖽(𝑠)),𝗍𝖺𝗂𝗅(𝗆𝖺𝗉(𝑔,𝑠))≡𝗆𝖺𝗉(𝑔,𝗍𝖺𝗂𝗅(𝑠)).(𝑀𝑎𝑝−ℎ𝑒𝑎𝑑)(𝑀𝑎𝑝−𝑡𝑎𝑖𝑙)
For 𝑓:𝐴→𝐵→𝐶, 𝑠:𝖲𝗍𝗋𝖾𝖺𝗆(𝐴), and 𝑡:𝖲𝗍𝗋𝖾𝖺𝗆(𝐵), use the state 𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)×𝖲𝗍𝗋𝖾𝖺𝗆(𝐵) to define 𝗓𝗂𝗉𝖶𝗂𝗍𝗁(𝑓,𝑠,𝑡):=𝖼𝗈𝗋𝖾𝖼𝐶(𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)×𝖲𝗍𝗋𝖾𝖺𝗆(𝐵),𝜆(𝑢,𝑣).𝑓(𝗁𝖾𝖺𝖽(𝑢))(𝗁𝖾𝖺𝖽(𝑣)),𝜆(𝑢,𝑣).(𝗍𝖺𝗂𝗅(𝑢),𝗍𝖺𝗂𝗅(𝑣)),(𝑠,𝑡)). Its two reusable computation equations are 𝗁𝖾𝖺𝖽(𝗓𝗂𝗉𝖶𝗂𝗍𝗁(𝑓,𝑠,𝑡))≡𝑓(𝗁𝖾𝖺𝖽(𝑠))(𝗁𝖾𝖺𝖽(𝑡)),𝗍𝖺𝗂𝗅(𝗓𝗂𝗉𝖶𝗂𝗍𝗁(𝑓,𝑠,𝑡))≡𝗓𝗂𝗉𝖶𝗂𝗍𝗁(𝑓,𝗍𝖺𝗂𝗅(𝑠),𝗍𝖺𝗂𝗅(𝑡)).(𝑍𝑖𝑝−ℎ𝑒𝑎𝑑)(𝑍𝑖𝑝−𝑡𝑎𝑖𝑙)
Define the Fibonacci stream by the state transition (𝑎,𝑏)↦(𝑏,𝑎+𝑏): 𝖿𝗂𝖻𝗌:=𝖼𝗈𝗋𝖾𝖼ℕ(ℕ×ℕ,𝜆(𝑎,𝑏).𝑎,𝜆(𝑎,𝑏).(𝑏,𝑎+𝑏),(0,1)). The first five observations are 𝗇𝗍𝗁(0,𝖿𝗂𝖻𝗌)≡0,𝗇𝗍𝗁(1,𝖿𝗂𝖻𝗌)≡1,𝗇𝗍𝗁(2,𝖿𝗂𝖻𝗌)≡1,𝗇𝗍𝗁(3,𝖿𝗂𝖻𝗌)≡2,𝗇𝗍𝗁(4,𝖿𝗂𝖻𝗌)≡3. Each equality is a judgmental closed calculation. Apply (Corec-tail) repeatedly to the numeral depth. Finish with (Corec-head).
Proof. Induct on 𝑛 while quantifying over 𝑥. At zero both endpoints reduce to 𝑡(𝑥). At 𝗌𝗎𝖼(𝑛), the iterate definition and the induction hypothesis at 𝑡(𝑥) give 𝑡𝗌𝗎𝖼(𝗌𝗎𝖼(𝑛))(𝑥)≡𝑡𝗌𝗎𝖼(𝑛)(𝑡(𝑥))IH(𝑡(𝑥))=𝑡(𝑡𝑛(𝑡(𝑥)))≡𝑡(𝑡𝗌𝗎𝖼(𝑛)(𝑥)). ◻
Proof. Let (𝑎𝑛,𝑏𝑛) be the 𝑛th iterate of (𝑎,𝑏)↦(𝑏,𝑎+𝑏) at (0,1). By theorem 85.3, 𝗇𝗍𝗁(𝑛,𝖿𝗂𝖻𝗌)=𝑎𝑛. By lemma 85.7, applying the transition to (𝑎𝑛,𝑏𝑛) gives 𝑎𝑛+1=𝑏𝑛. The same facts give 𝑎𝑛+2𝑙𝑒𝑚𝑚𝑎85.7=𝑏𝑛+1𝑡𝑟𝑎𝑛𝑠𝑖𝑡𝑖𝑜𝑛𝑒𝑞𝑢𝑎𝑡𝑖𝑜𝑛=𝑎𝑛+𝑏𝑛𝑎𝑛+1=𝑏𝑛=𝑎𝑛+𝑎𝑛+1. Substitution of the three observation equations yields the result. This argument holds for arbitrary 𝑛; it is not an extrapolation from the five closed observations above. ◻
★☆☆ Use Boolean state and negation to define the alternating stream 𝗍𝗍,𝖿𝖿,𝗍𝗍,…. Calculate observations at depths zero through four and identify the state iterate used by each calculation.
A pattern describes how an input was constructed. A copattern describes how a result will be observed. For streams, the primitive copatterns are 𝗁𝖾𝖺𝖽(◻) and 𝗍𝖺𝗂𝗅(◻), where ◻ marks the defined result.
A unary stream definition by copatterns has the form 𝗁𝖾𝖺𝖽(𝐹(𝑥))=ℎ(𝑥),𝗍𝖺𝗂𝗅(𝐹(𝑥))=𝐹(𝑡(𝑥)), where 𝑥:𝑆, ℎ:𝑆→𝐴, and 𝑡:𝑆→𝑆. It is complete because it gives one clause for each stream destructor. Its compilation is 𝐹(𝑥):=𝖼𝗈𝗋𝖾𝖼𝐴(𝑆,ℎ,𝑡,𝑥). The two source clauses become the two judgmental equations (Corec-head) and (Corec-tail). A unary clause system is accepted by the guarded copattern fragment if and only if it contains both displayed clauses for some 𝑆,ℎ,𝑡 and compiles to this corecursor term. Thus “accepted” names this syntactic class rather than an unstated checking judgment.
For example, the two equations for 𝗆𝖺𝗉 in construction 85.5 are a copattern definition. Compilation chooses the input stream itself as state. The right side of the tail clause is a guarded recursive call because a tail observation has been matched before the call is demanded.
★★☆ Give copattern clauses for 𝗓𝗂𝗉𝖶𝗂𝗍𝗁(𝑓,𝑠,𝑡) and compile them to the corecursor using the pair state from construction 85.6. Derive both clauses from the compiled term. Then delete the tail clause and state exactly which observation is uncovered.
Ordinary induction on a stream cannot begin because there is no stream constructor on which to split. A first attempt can instead induct on finite observation depth. Fix 𝑠:𝖲𝗍𝗋𝖾𝖺𝗆(𝐴) and try to prove 𝑃(𝑛):=𝖨𝖽𝐴(𝗇𝗍𝗁(𝑛,𝗆𝖺𝗉(𝜆𝑥.𝑥,𝑠)),𝗇𝗍𝗁(𝑛,𝑠)).(𝐹𝑎𝑖𝑙𝑒𝑑−𝑑𝑒𝑝𝑡ℎ−𝑖𝑛𝑑𝑢𝑐𝑡𝑖𝑜𝑛) The zero case reduces to reflexivity. In the successor case, the two tail equations reduce the goal to 𝖨𝖽𝐴(𝗇𝗍𝗁(𝑛,𝗆𝖺𝗉(𝜆𝑥.𝑥,𝗍𝖺𝗂𝗅(𝑠))),𝗇𝗍𝗁(𝑛,𝗍𝖺𝗂𝗅(𝑠))). This is not 𝑃(𝑛): the fixed stream 𝑠 has changed to 𝗍𝖺𝗂𝗅(𝑠). One repair quantifies over every stream. The reusable repair records instead a relation whose evidence gives equal heads and another piece of evidence after taking tails. Those two obligations determine bisimulation.
Streams 𝑠,𝑡:𝖲𝗍𝗋𝖾𝖺𝗆(𝐴) are observationally equal, written 𝑠≈𝐴𝑡, when 𝑠≈𝐴𝑡:=∏𝑛:ℕ𝖨𝖽𝐴(𝗇𝗍𝗁(𝑛,𝑠),𝗇𝗍𝗁(𝑛,𝑡)). This is an internal family of identifications. It does not add a judgmental equation 𝑠≡𝑡 and therefore does not make a stuck destructor compute.
A nested copattern, also called a deep copattern, places a finite composite of destructors around the defined result. The customary deep-copattern presentation of Fibonacci consists of 𝗁𝖾𝖺𝖽(𝖿𝗂𝖻𝗌)=0,𝗁𝖾𝖺𝖽(𝗍𝖺𝗂𝗅(𝖿𝗂𝖻𝗌))=1,𝗍𝖺𝗂𝗅(𝗍𝖺𝗂𝗅(𝖿𝗂𝖻𝗌))≈ℕ𝗓𝗂𝗉𝖶𝗂𝗍𝗁(+,𝖿𝗂𝖻𝗌,𝗍𝖺𝗂𝗅(𝖿𝗂𝖻𝗌)). The first two clauses are judgmental closed instances of the state-machine equations. The third is only observational; it is proved in corollary 85.17 and is not a primitive unfolding equation. Deep copattern notation therefore does not enlarge definitional equality.
The signature 𝑇𝖼𝗈 has no uniqueness or eta rule saying that a stream is equal to the corecursor determined by its observations. In this fragment, a proof of 𝑠≈𝐴𝑡 therefore does not yield an inhabitant of 𝖨𝖽𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)(𝑠,𝑡). A stream-extensionality principle can close that gap. An observational type theory extended with a stream clause defined by all finite head-and-tail observations can also close it. Neither extension is a rule of 𝑇𝖼𝗈.
A relation 𝐵:𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)→𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)→U𝑘 is a stream bisimulation when it is equipped with functions 𝖻𝗂𝗌𝗂𝗆𝖧𝖾𝖺𝖽𝐵:∏𝑠:𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)∏𝑡:𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)𝐵(𝑠,𝑡)→𝖨𝖽𝐴(𝗁𝖾𝖺𝖽(𝑠),𝗁𝖾𝖺𝖽(𝑡)),𝖻𝗂𝗌𝗂𝗆𝖳𝖺𝗂𝗅𝐵:∏𝑠:𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)∏𝑡:𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)𝐵(𝑠,𝑡)→𝐵(𝗍𝖺𝗂𝗅(𝑠),𝗍𝖺𝗂𝗅(𝑡)). The first component matches the immediate observations. The second returns the same relation after one tail observation.
Proof. We must construct an identification at every depth 𝑛. Induct on 𝑛 while quantifying over 𝑠,𝑡, and 𝑞:𝐵(𝑠,𝑡). At zero, 𝗇𝗍𝗁(0,𝑠)≡𝗁𝖾𝖺𝖽(𝑠)and𝗇𝗍𝗁(0,𝑡)≡𝗁𝖾𝖺𝖽(𝑡), so 𝖻𝗂𝗌𝗂𝗆𝖧𝖾𝖺𝖽𝐵(𝑠,𝑡,𝑞) has the required type. At 𝗌𝗎𝖼(𝑛), the tail component gives 𝑞′:=𝖻𝗂𝗌𝗂𝗆𝖳𝖺𝗂𝗅𝐵(𝑠,𝑡,𝑞):𝐵(𝗍𝖺𝗂𝗅(𝑠),𝗍𝖺𝗂𝗅(𝑡)). The induction hypothesis at 𝑞′ gives 𝗇𝗍𝗁(𝑛,𝗍𝖺𝗂𝗅(𝑠))=𝐴𝗇𝗍𝗁(𝑛,𝗍𝖺𝗂𝗅(𝑡)), which converts along the two successor equations of definition 85.2 to the required identification at depth 𝗌𝗎𝖼(𝑛). ◻
Deleting the head clause allows a relation between streams with different first elements. Deleting closure under tail allows a relation that matches only the first element. Each deletion therefore invalidates the corresponding case of the proof of theorem 85.13.
★☆☆ Let 𝑠,𝑡:𝖲𝗍𝗋𝖾𝖺𝗆(𝐴) and let 𝐵(𝑠,𝑡) mean only that 𝗁𝖾𝖺𝖽(𝑠)=𝗁𝖾𝖺𝖽(𝑡). Give two streams related by 𝐵 whose depth-one observations differ. Identify the missing premise of definition 85.12.
Proof. Define the relation by the dependent sum 𝐿(𝑟):=𝗆𝖺𝗉(𝑓,𝗆𝖺𝗉(𝑔,𝑟)),𝑅(𝑟):=𝗆𝖺𝗉(𝜆𝑥.𝑓(𝑔(𝑥)),𝑟),𝐵(𝑢,𝑣):=∑𝑟:𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)(𝖨𝖽𝖲𝗍𝗋𝖾𝖺𝗆(𝐶)(𝑢,𝐿(𝑟))×𝖨𝖽𝖲𝗍𝗋𝖾𝖺𝗆(𝐶)(𝑣,𝑅(𝑟))). The original pair belongs to 𝐵 with witness 𝑠. For a pair witnessed by 𝑟, eliminate the two displayed identities. It remains to treat the canonical representatives 𝑢≡𝗆𝖺𝗉(𝑓,𝗆𝖺𝗉(𝑔,𝑟)) and 𝑣≡𝗆𝖺𝗉(𝜆𝑥.𝑓(𝑔(𝑥)),𝑟). Their heads calculate as 𝗁𝖾𝖺𝖽(𝑢)(𝑀𝑎𝑝−ℎ𝑒𝑎𝑑)≡𝑓(𝗁𝖾𝖺𝖽(𝗆𝖺𝗉(𝑔,𝑟)))(𝑀𝑎𝑝−ℎ𝑒𝑎𝑑)≡𝑓(𝑔(𝗁𝖾𝖺𝖽(𝑟)))(𝑀𝑎𝑝−ℎ𝑒𝑎𝑑)≡𝗁𝖾𝖺𝖽(𝑣). Their tails satisfy 𝗍𝖺𝗂𝗅(𝑢)(𝑀𝑎𝑝−𝑡𝑎𝑖𝑙)≡𝗆𝖺𝗉(𝑓,𝗆𝖺𝗉(𝑔,𝗍𝖺𝗂𝗅(𝑟))),𝗍𝖺𝗂𝗅(𝑣)(𝑀𝑎𝑝−𝑡𝑎𝑖𝑙)≡𝗆𝖺𝗉(𝜆𝑥.𝑓(𝑔(𝑥)),𝗍𝖺𝗂𝗅(𝑟)). Thus the tail pair belongs to 𝐵 with witness 𝗍𝖺𝗂𝗅(𝑟) and two reflexivity identifications after the displayed computations. Transporting back along the eliminated identities gives the required head and tail data for the original 𝑢,𝑣. The relation is a bisimulation, and theorem 85.13 gives the result. ◻
★★☆ Let 𝑠,𝑡:𝖲𝗍𝗋𝖾𝖺𝗆(𝐴). Assume 𝑓:𝐴→𝐴→𝐴 and 𝑐:∏𝑥:𝐴∏𝑦:𝐴𝖨𝖽𝐴(𝑓(𝑥)(𝑦),𝑓(𝑦)(𝑥)). Put 𝑢:=𝗓𝗂𝗉𝖶𝗂𝗍𝗁(𝑓,𝑠,𝑡),𝑣:=𝗓𝗂𝗉𝖶𝗂𝗍𝗁(𝑓,𝑡,𝑠). Construct a bisimulation proving 𝑢≈𝐴𝑣. State the tail witness and use 𝑐 only in the head component.
Proof. Induct on 𝑛 while quantifying over 𝑠 and 𝑡. At zero, 𝗇𝗍𝗁(0,𝗓𝗂𝗉𝖶𝗂𝗍𝗁(𝑓,𝑠,𝑡))𝑑𝑒𝑓𝑖𝑛𝑖𝑡𝑖𝑜𝑛85.2≡𝗁𝖾𝖺𝖽(𝗓𝗂𝗉𝖶𝗂𝗍𝗁(𝑓,𝑠,𝑡))(𝑍𝑖𝑝−ℎ𝑒𝑎𝑑)≡𝑓(𝗁𝖾𝖺𝖽(𝑠))(𝗁𝖾𝖺𝖽(𝑡))𝑑𝑒𝑓𝑖𝑛𝑖𝑡𝑖𝑜𝑛85.2≡𝑓(𝗇𝗍𝗁(0,𝑠))(𝗇𝗍𝗁(0,𝑡)). At 𝗌𝗎𝖼(𝑛), the calculation is 𝗇𝗍𝗁(𝗌𝗎𝖼(𝑛),𝗓𝗂𝗉𝖶𝗂𝗍𝗁(𝑓,𝑠,𝑡))𝑑𝑒𝑓𝑖𝑛𝑖𝑡𝑖𝑜𝑛85.2≡𝗇𝗍𝗁(𝑛,𝗍𝖺𝗂𝗅(𝗓𝗂𝗉𝖶𝗂𝗍𝗁(𝑓,𝑠,𝑡)))(𝑍𝑖𝑝−𝑡𝑎𝑖𝑙)≡𝗇𝗍𝗁(𝑛,𝗓𝗂𝗉𝖶𝗂𝗍𝗁(𝑓,𝗍𝖺𝗂𝗅(𝑠),𝗍𝖺𝗂𝗅(𝑡)))IH(𝗍𝖺𝗂𝗅(𝑠),𝗍𝖺𝗂𝗅(𝑡))=𝑓(𝗇𝗍𝗁(𝑛,𝗍𝖺𝗂𝗅(𝑠)))(𝗇𝗍𝗁(𝑛,𝗍𝖺𝗂𝗅(𝑡)))𝑑𝑒𝑓𝑖𝑛𝑖𝑡𝑖𝑜𝑛85.2≡𝑓(𝗇𝗍𝗁(𝗌𝗎𝖼(𝑛),𝑠))(𝗇𝗍𝗁(𝗌𝗎𝖼(𝑛),𝑡)). ◻
Proof of Corollary 85.17 — The feedback equation for Fibonacci
Proof. By lemma 85.16, specializing to addition, 𝖿𝗂𝖻𝗌, and 𝗍𝖺𝗂𝗅(𝖿𝗂𝖻𝗌) identifies the right observation at depth 𝑛 with 𝗇𝗍𝗁(𝑛,𝖿𝗂𝖻𝗌)+𝗇𝗍𝗁(𝑛+1,𝖿𝗂𝖻𝗌). The left observation is 𝗇𝗍𝗁(𝑛+2,𝖿𝗂𝖻𝗌), and proposition 85.8 gives the final identity for every neutral 𝑛. ◻
The selected coinductive-record schema
Streams have one observable field and one successor field. The same proof works for finitely many fields.
Fix observation types 𝑂1,…,𝑂𝑚. Fix also 𝑟 recursive successor fields. The schema generates a coinductive record 𝐶 with destructors 𝑜𝑖:𝐶→𝑂𝑖(1≤𝑖≤𝑚),𝑑𝑗:𝐶→𝐶(1≤𝑗≤𝑟). Given a state 𝑆, outputs ℎ𝑖:𝑆→𝑂𝑖, transitions 𝑡𝑗:𝑆→𝑆, and 𝑥:𝑆, its corecursor satisfies 𝑜𝑖(𝖼𝗈𝗋𝖾𝖼𝐶(𝑆,¯ℎ,¯𝑡,𝑥))≡ℎ𝑖(𝑥),𝑑𝑗(𝖼𝗈𝗋𝖾𝖼𝐶(𝑆,¯ℎ,¯𝑡,𝑥))≡𝖼𝗈𝗋𝖾𝖼𝐶(𝑆,¯ℎ,¯𝑡,𝑡𝑗(𝑥)). Every recursive occurrence is the complete result of a recursive destructor. Dependent observation types, nested recursive fields, mixed inductive–coinductive declarations, and higher-order guards are not in this schema.
For 𝑘:ℕ, indices 1≤𝑗1,…,𝑗𝑘≤𝑟, and 1≤𝑖≤𝑚, abbreviate 𝑐𝑥:=𝖼𝗈𝗋𝖾𝖼𝐶(𝑆,¯ℎ,¯𝑡,𝑥). Then 𝑜𝑖(𝑑𝑗𝑘(⋯𝑑𝑗1(𝑐𝑥)⋯))≡ℎ𝑖(𝑡𝑗𝑘(⋯𝑡𝑗1(𝑥)⋯)). For 𝑘≡𝟢, both finite composites are empty and the equation reads 𝑜𝑖(𝑐𝑥)≡ℎ𝑖(𝑥).
Proof of Theorem 85.19 — Finite-observation productivity for the schema
Proof. Induct on 𝑘. The empty word reduces by the 𝑜𝑖 equation. In a nonempty word, the destructor adjacent to the corecursor is 𝑑𝑗1; its equation replaces the state 𝑥 by 𝑡𝑗1(𝑥). Apply the induction hypothesis to the remaining word 𝑗2,…,𝑗𝑘 at that state. A finite index list is empty or has this first entry, so these are all cases. ◻
Downen and Ariola’s contextual signature has terms 𝑣, coterms 𝑒, values 𝑉, covalues 𝐸, commands ⟨𝑣∣𝑒⟩, types generated in part by ℕ, 𝖲𝗍𝗋𝖾𝖺𝗆(𝐴), and 𝐴→𝐵, and three equality judgments under Γ∣Δ: command equality, value equality 𝑣=𝑣′:𝐴, and consumer equality 𝑒=𝑒′÷𝐴. Here 𝑒÷𝐴 means that the coterm 𝑒 consumes a value of type 𝐴. Its cut congruence is the named rule
Γ∣Δ⊢𝑣=𝑣′:𝐴Γ∣Δ⊢𝑒=𝑒′÷𝐴
Γ∣Δ⊢⟨𝑣∣𝑒⟩=⟨𝑣′∣𝑒′⟩
Cut
A productive command property Ψ(𝛼) has base form ⟨𝑉∣𝛼⟩=⟨𝑉′∣𝛼⟩, with 𝛼 absent from 𝑉,𝑉′, and is closed under the stream rule
Γ,𝛽÷𝐴∣Δ⊢Ψ[𝗁𝖾𝖺𝖽𝛽/𝛼]Γ,𝛼÷𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)∣Δ,Ψ(𝛼)⊢Ψ[𝗍𝖺𝗂𝗅𝛼/𝛼]
Γ,𝛼÷𝖲𝗍𝗋𝖾𝖺𝗆(𝐴)∣Δ⊢Ψ(𝛼)
ωStream
For a concrete instance, let 𝑢0,𝑢1:𝖲𝗍𝗋𝖾𝖺𝗆(ℕ) have the contextual equations 𝗁𝖾𝖺𝖽(𝑢𝑖)=0,𝗍𝖺𝗂𝗅(𝑢𝑖)=𝑢𝑖(𝑖∈{0,1}), and put Ψ(𝛼):=⟨𝑢0∣𝛼⟩=⟨𝑢1∣𝛼⟩. The head premise of 𝜔𝖲𝗍𝗋𝖾𝖺𝗆 contracts to ⟨0∣𝛽⟩=⟨0∣𝛽⟩. The tail premise contracts back to Ψ(𝛼) and is discharged by the displayed hypothesis in that premise. Thus the rule derives Ψ(𝛼) from one immediate value equality and one guarded reuse.
The head premise of 𝜔𝖲𝗍𝗋𝖾𝖺𝗆 performs the same role as 𝖻𝗂𝗌𝗂𝗆𝖧𝖾𝖺𝖽𝐵, and its tail premise performs the same role as 𝖻𝗂𝗌𝗂𝗆𝖳𝖺𝗂𝗅𝐵. The contextual rule phrases those obligations as command equality under a reusable hypothesis; definition 85.12 phrases them as destructor observations of a relation witness. Their Theorem 5.21 proves semantic soundness of the extensional logic for both call-by-value and call-by-name. Theorem 5.23 concludes, separately, that derivable command, value, and covalue equalities imply their corresponding observational equivalences. The stronger strategy-specific logics use the separate soundness statement of Theorem 5.28. None of these results proves a guarded-corecursor or copattern-coverage theorem for 𝑇𝖼𝗈.
Fix 𝖲𝗂𝗓𝖾:U𝑖 and a relation <𝑠. The optional signature 𝑇𝗌𝗂𝗓𝖾 describes observations bounded by a supplied descending size chain. Its rules do not postulate a distinguished size with arbitrarily many available tails, so they describe sized approximants rather than asserting an infinite-stream object.
Let 𝑆:𝖲𝗂𝗓𝖾→U𝑘. Given ℎ:∏𝛼:𝖲𝗂𝗓𝖾𝑆(𝛼)→𝐴,𝑡:∏𝛼:𝖲𝗂𝗓𝖾∏𝛽:𝖲𝗂𝗓𝖾𝛽<𝑠𝛼→𝑆(𝛼)→𝑆(𝛽), the corecursor rule is
Γ⊢𝑥:𝑆(𝛼)
Γ⊢𝖼𝗈𝗋𝖾𝖼𝛼𝐴(𝑆,ℎ,𝑡,𝑥):𝖲𝗍𝗋𝖾𝖺𝗆𝛼(𝐴)
Sized-corec
It is governed by 𝗁𝖾𝖺𝖽𝛼(𝖼𝗈𝗋𝖾𝖼𝛼𝐴(𝑆,ℎ,𝑡,𝑥))≡ℎ(𝛼,𝑥),𝗍𝖺𝗂𝗅𝛼,𝛽(𝑟,𝖼𝗈𝗋𝖾𝖼𝛼𝐴(𝑆,ℎ,𝑡,𝑥))≡𝖼𝗈𝗋𝖾𝖼𝛽𝐴(𝑆,ℎ,𝑡,𝑡(𝛼,𝛽,𝑟,𝑥)).(𝑆𝑖𝑧𝑒𝑑−𝑐𝑜𝑟𝑒𝑐−ℎ𝑒𝑎𝑑)(𝑆𝑖𝑧𝑒𝑑−𝑐𝑜𝑟𝑒𝑐−𝑡𝑎𝑖𝑙) The only recursively produced approximant in the second equation is indexed by 𝑟:𝛽<𝑠𝛼, which is its decrease certificate. Deleting 𝑟 would define a different, unsupported signature, while adding a distinguished infinity size or size-weakening operation would require additional rules not present here.
For 𝑓:𝐴→𝐵 and 𝑠:𝖲𝗍𝗋𝖾𝖺𝗆𝛼(𝐴), take 𝑆(𝛾):=𝖲𝗍𝗋𝖾𝖺𝗆𝛾(𝐴), ℎ(𝛾,𝑢):=𝑓(𝗁𝖾𝖺𝖽𝛾(𝑢)), and 𝑡(𝛾,𝛿,𝑟,𝑢):=𝗍𝖺𝗂𝗅𝛾,𝛿(𝑟,𝑢). Then 𝗆𝖺𝗉𝛼(𝑓,𝑠):=𝖼𝗈𝗋𝖾𝖼𝛼𝐵(𝑆,ℎ,𝑡,𝑠):𝖲𝗍𝗋𝖾𝖺𝗆𝛼(𝐵). The two corecursor equations calculate to 𝗁𝖾𝖺𝖽𝛼(𝗆𝖺𝗉𝛼(𝑓,𝑠))≡𝑓(𝗁𝖾𝖺𝖽𝛼(𝑠)),𝗍𝖺𝗂𝗅𝛼,𝛽(𝑟,𝗆𝖺𝗉𝛼(𝑓,𝑠))≡𝗆𝖺𝗉𝛽(𝑓,𝗍𝖺𝗂𝗅𝛼,𝛽(𝑟,𝑠)). Thus map is constructed from the displayed corecursor rather than postulated as a second recursive operation.
Let 𝛼𝑛<𝑠⋯<𝑠𝛼1<𝑠𝛼0 be witnessed by 𝑟𝑞:𝛼𝑞+1<𝑠𝛼𝑞. Starting at 𝑥0:𝑆(𝛼0), define 𝑥𝑞+1:=𝑡(𝛼𝑞,𝛼𝑞+1,𝑟𝑞,𝑥𝑞). Applying the corresponding 𝑛 tails and then 𝗁𝖾𝖺𝖽𝛼𝑛 to 𝖼𝗈𝗋𝖾𝖼𝛼0𝐴(𝑆,ℎ,𝑡,𝑥0) reduces judgmentally to ℎ(𝛼𝑛,𝑥𝑛).
Proof of Theorem 85.24 — Bounded observation calculation
Proof. Induct on the length of the displayed chain. At zero, the calculation is 𝗁𝖾𝖺𝖽𝛼0(𝖼𝗈𝗋𝖾𝖼𝛼0𝐴(𝑆,ℎ,𝑡,𝑥0))(𝑆𝑖𝑧𝑒𝑑−𝑐𝑜𝑟𝑒𝑐−ℎ𝑒𝑎𝑑)≡ℎ(𝛼0,𝑥0). A successor chain first uses (Sized-corec-tail). The resulting term is 𝖼𝗈𝗋𝖾𝖼𝛼1𝐴(𝑆,ℎ,𝑡,𝑥1). The induction hypothesis applies to its shorter tail. The calculation covers exactly the observations backed by the displayed finite chain. If <𝑠 is well founded, accessibility rules out any one infinite sequence of successive tail observations. It does not impose a uniform finite bound on the depths reachable from a fixed size: at an 𝜔-like size, every finite depth may be reachable along its own finite chain. No infinite-stream productivity conclusion follows from the bounded calculation alone. ◻
For finite sizes ̂0<𝑠̂1<𝑠̂2<𝑠̂3, let 𝑆(𝛾):=ℕ, ℎ(𝛾,𝑥):=𝑥, and 𝑡(𝛾,𝛿,𝑟,𝑥):=𝑥+𝑥. Construct 𝑠:=𝖼𝗈𝗋𝖾𝖼̂3ℕ(𝑆,ℎ,𝑡,2):𝖲𝗍𝗋𝖾𝖺𝗆̂3(ℕ). Its successive heads along the displayed descent are 2,4,8,16. At the first depth, the map calculation is 𝗁𝖾𝖺𝖽̂3(𝗆𝖺𝗉̂3(𝗌𝗎𝖼,𝑠))𝑐𝑜𝑛𝑠𝑡𝑟𝑢𝑐𝑡𝑖𝑜𝑛85.23≡𝗌𝗎𝖼(𝗁𝖾𝖺𝖽̂3(𝑠))(𝑆𝑖𝑧𝑒𝑑−𝑐𝑜𝑟𝑒𝑐−ℎ𝑒𝑎𝑑)≡𝗌𝗎𝖼(2)natural-numbercomputation≡3. One, two, and three applications of (Sized-corec-tail) give the corresponding mapped heads 5, 9, and 17. This is a mathematical sized approximant calculation, not an infinite stream and not a theorem about every implementation named “sized types.”
Abel and Pientka’s calculus combines size quantification, variance, copatterns, and a reducibility interpretation at its published signature; the bounded fragment above deliberately includes neither its infinity size nor its size-weakening structure. Experimental Agda sized-type features have also admitted consistency bugs; no implementation theorem is inferred from the mathematical display above.
★★★ Specify a stream of triangular numbers first by a pair-state corecursor and then by complete head/tail copattern clauses. Compile the clauses, calculate the first six observations, and prove that the two definitions are observationally equal.
★★☆ Use the accepted clause system 𝗁𝖾𝖺𝖽(𝗓𝖾𝗋𝗈𝗌)≡0 and 𝗍𝖺𝗂𝗅(𝗓𝖾𝗋𝗈𝗌)≡𝗓𝖾𝗋𝗈𝗌. Let 𝗇𝖺𝗍𝗌:=𝗂𝗍𝖾𝗋𝖺𝗍𝖾(𝗌𝗎𝖼,𝟢), so that 𝗁𝖾𝖺𝖽(𝗇𝖺𝗍𝗌)≡𝟢. First prove by induction that 𝗇𝗍𝗁(𝑛,𝗆𝖺𝗉(𝑔,𝑠)) is identified with 𝑔(𝗇𝗍𝗁(𝑛,𝑠)). Use that lemma to prove 𝗍𝖺𝗂𝗅(𝗇𝖺𝗍𝗌)≈ℕ𝗆𝖺𝗉(𝗌𝗎𝖼,𝗇𝖺𝗍𝗌)and𝖨𝖽ℕ(𝗇𝗍𝗁(𝑛,𝗇𝖺𝗍𝗌),𝑛). Explain why replacing the observational equality by ≡ would not give the unary state-update clause required by definition 85.9; do not claim that the guarded fragment is complete.
★★★Practical project.guarded-stream-observer Implement in Kappa the state-machine corecursor through a finite observer rather than by constructing an infinite host value. Maintain the invariant that a request of depth 𝑛 performs exactly 𝑛 state transitions before applying the output function. On the Fibonacci state machine, print the observations at depths 0 through 9; the exact output must be 0,1,1,2,3,5,8,13,21,34. A mutated transition (𝑎,𝑏)↦(𝑎,𝑎+𝑏) must fail the acceptance test by printing 0,0 in the first two positions. Report both traces.
Sources. The destructor and copattern presentation follows Abel, Pientka, Thibodeau, and Setzer, especially its stream and Fibonacci examples [APTS13]. The sized boundary follows Abel and Pientka’s journal development [AP16]. The contextual comparison is restricted to the exact soundness results of Downen and Ariola [DA25].