Quick viewing(Text Mode)

A Computational Understanding of Classical (Co)Recursion

A Computational Understanding of Classical (Co)Recursion

A Computational Understanding of Classical (Co)

Paul Downen Zena M. Ariola University of Oregon University of Oregon Eugene, Oregon Eugene, Oregon [email protected] [email protected]

Abstract The goal of this paper is to introduce the basic principles Recursion and induction are mature, well-understood top- of coinductive and inductive structures from a computational ics in programming. Yet their duals, corecursion and co- point of view, by presenting a language that captures known induction, are still exotic and underdeveloped programming intuitions about them. For example, Harper [23] explains that features. We aim to put them on equal footing by giving a an in a infinite stream of natural numbers can only foundation for corecursion based on computation, analogous be generated after computing all the proceeding elements. to the original computational foundation of recursion. At the Moreover, the introduction of stream objects is sometimes lower level, we show how the connection between the two described as the “dual” to the elimination of natural numbers 휆 can be strengthened through their implementation details [35, 37], but how is this so? Especially since, in the -calculus, in an abstract machine. At the higher level, we develop a stream objects are introduced with an internal “seed” used syntactic equational theory for inductive and coinductive to generate the elements in order, whereas the elimination reasoning based on control flow. We also observe the impact of natural numbers has no such internal state. of evaluation strategy: call-by- has efficient recursion To make these intuitions precise, we express the (co)- and strong coinductive reasoning, but call-by-value has effi- inductive principles with symmetric forms of recursion and cient corecursion and strong . corecursion in a programming language. This symmetry is en- capsulated by the duality [9, 22] between data types—defined CCS Concepts: • Theory of computation → Program by the structure of objects—and codata types—defined by the schemes. behavior of objects. We aim to demystify coinductive codata Keywords: Corecursion, Coinduction, Control, Duality types, and to make them more suitable for widespread use in programming environments [15, 21]. ACM Format: Our contributions (•) and observations (–) are: Paul Downen and Zena M. Ariola. 2020. A Computational Under- standing of Classical (Co)Recursion. In 22nd International Sympo- – (Section2) We point out the impact of evaluation strat- sium on Principles and Practice of Declarative Programming (PPDP ’20), egy on recursion combinators for inductive types: September 8–10, 2020, Bologna, Italy. ACM, New York, NY, USA, * In call-by-value, recursion is eager, and is just as 14 pages. https://doi.org/10.1145/3414080.3414086 inefficient as its encoding in terms of the iterator. * In call-by-name, recursion may end early; an asymp- 1 Introduction totic complexity improvement. Induction is a familiar and commonplace notion with many – (Section3) In an abstract machine, the recursor for firm foundations: logical, algebraic, and computational. Co- inductive types like numbers accumulates a continu- induction—the dual to induction—instead looks unfamiliar, ation during evaluation, maintaining the progress of and is usually relegated to coalgebras [36], since traditionally recursion that is implicit in the 휆-calculus. only the categorical setting speaks clearly about this duality. • (Section4) Applying duality in an abstract machine based on the [4, 11], we derive the Permission to make digital or hard copies of all or part of this work for corresponding corecursors for infinite streams with a personal or classroom use is granted without fee provided that copies value accumulator dual to the recursor’s continuation. are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. Copyrights – (Section 4.2) Like recursion, corecursion can be more for components of this work owned by others than the author(s) must efficient than coiteration by letting corecursive pro- be honored. Abstracting with credit is permitted. To copy otherwise, or cesses stop early. Dual to recursion, this improvement republish, to post on servers or to redistribute to lists, requires prior specific in algorithmic complexity is only seen in call-by-value. permission and/or a fee. Request permissions from [email protected]. • (Section5) We translate the fully-general corecursor PPDP ’20, September 8–10, 2020, Bologna, Italy from the abstract machine back into direct style in © 2020 Copyright held by the owner/author(s). Publication rights licensed 휆휇 to ACM. terms of a -calculus using first- control effects. ACM ISBN 978-1-4503-8821-4/20/09...$15.00 • (Section 5.1) (Co)recursive introduction rules require https://doi.org/10.1145/3414080.3414086 an internal state to express non-trivial computations. PPDP ’20, September 8–10, 2020, Bologna, Italy P. Downen and Z.M. Ariola

Var 퐴, 퐵 ::= 퐴 → 퐵 | nat Γ, 푥 : 퐴 ⊢ 푥 : 퐴 푀, 푁 푥 | 휆푥.푀 | 푀 푁 | | 푀 | 푀 ::= zero succ rec as ralt Γ, 푥 : 퐴 ⊢ 푀 : 퐵 Γ ⊢ 푀 : 퐴 → 퐵 Γ ⊢ 푁 : 퐴 푁 푥 푦.푀 →퐼 →퐸 ralt ::= {zero → | succ → } Γ ⊢ 휆푥.푀 : 퐴 → 퐵 Γ ⊢ 푀 푁 : 퐵 ⊢ 푀 : nat Figure 1. System T: 휆-calculus with numbers and recursion. nat퐼 Γ nat퐼 Γ ⊢ zero : nat zero Γ ⊢ succ 푀 : nat succ Γ ⊢ 푀 : nat Γ ⊢ 푁 : 퐴 Γ, 푥 : nat,푦 : 퐴 ⊢ 푁 ′ : 퐴 nat퐸 Γ ⊢ rec 푀 as {zero → 푁 | succ 푥 → 푦.푁 ′} : 퐴 In contrast, recursive elimination rules (as in System T) do not. We define the corresponding stateless corecursor Figure 2. Type system of System T. as coelimination. Call-by-name values (푉 ) and evaluation contexts (퐸): • (Section6) We present a direct-style equational the- 푉,푊 푀 퐸 퐸 푁 퐸 ory of natural numbers and streams, corresponding ::= ::= □ | | rec as ralt to weak induction and coinduction, based on control Call-by-value values (푉 ) and evaluation contexts (퐸): flow. The theory does not resort to bisimulation [18]; 푉,푊 ::= 푥 | 휆푥.푀 | zero | succ푉 it uses syntactic, locally criteria for valid applications 퐸 ::= □ | 퐸 푁 | 푉 퐸 | succ 퐸 | rec 퐸 as ralt of the coinductive hypothesis. ′ • (Section 6.3) We identify the impact of evaluation strat- Operational rules, where ralt = {zero →푁 | succ 푥→푦.푁 }:

egy on equational reasoning in order to generalize the (훽→)(휆푥.푀) 푉 ↦→ 푀 [푉 /푥] weak (co)inductive principles to strong (co)induction: (훽zero) rec zero as ralt ↦→ 푁 * In call-by-value, strong induction is sound. ′ (훽succ) rec succ푉 as ralt ↦→ (휆푦.푁 [푉 /푥])(rec푉 as ralt) * In call-by-name, strong coinduction is sound, which subsumes the traditional notion of bisimulation. Figure 3. Operational of System T.

2 Recursion in the These macro-expansions are analogous to the common syn- tactic sugar of let-bindings in terms of functions: The prototypical example of computational recursion is Gödel’s System T [20], whose is given in fig.1. System T ex- let 푥 = 푀 in 푁 := (휆푥.푁 ) 푀 tends the simply-typed 휆-calculus, whose focus is on func- tions of type 퐴 → 퐵, with ways to construct and use natural The type system of System T is given in fig.2. The Var, →퐼 numbers of type nat. Values of nat are built with the famil- and →퐸 typing rules are from the simply typed 휆-calculus. iar constructors zero (denoting the number 0) and succ 푀 The two nat퐼 introduction rules give the types of the con- (denoting the successor of the number represented by 푀). structors of nat, and the nat퐸 elimination rule types the nat This way, the number 푛 can be written as succ푛 zero. To use recursor. If rec is seen instead as a primitive , rather these numbers, System T includes a recursor of the form than a syntactic construct, it would have the type rec 푀 as {zero → 푁 | succ 푥 → 푦.푁 ′}. This recursor is rec퐴 : nat → 퐴 → (nat → 퐴 → 퐴) → 퐴 similar to pattern-matching in : the nat term 푀 is analyzed to determine if it has the shape zero or whereas the primitive functions corresponding to case and succ 푥, and the matching branch is returned. But in addition iter on nat would have the type to binding the predecessor of 푀 to 푥 in the succ 푥 branch, this 퐴 퐴 퐴 퐴 recursor also binds 푦 to the recursive result that is returned casenat : nat → → (nat → ) → 푀 퐴 퐴 퐴 퐴 퐴 if is replaced with its predecessor. iternat : nat → → ( → ) → Notice how the recursor performs two jobs at the same time: finding the predecessor of a natural numbers as well System T’s call-by-name and -value operational seman- as calculating the recursive result given for the predeces- tics are given in fig.3. Both of these evaluation strategies 훽 sor. These two functionalities are captured separately by a share operational rules of the same form, with → being 훽 휆 훽 훽 conventional case-expression and the iterator, respectively. the well-known rule of the -calculus and zero and succ Both can be expressed in terms of macro-expansions into defining recursion on the two nat constructors. The only the recursor by ignoring the unneeded parameter: difference between call-by-value and -name evaluation lies in their notion of values 푉 (i.e., those terms which can be substituted for variables) and evaluation contexts (i.e., the case 푀 of { zero → 푁 rec 푀 as { zero → 푁 ′ := ′ location of the next reduction step to perform). Note that we | succ 푥 → 푁 } | succ 푥 → . 푁 } take this notion seriously, and never substitute a non-value 푀 푁 푀 푁 iter of { zero → rec as { zero → for a variable. As such, the 훽succ rule does not substitute the ′ := ′ | succ → 푦. 푁 } | succ → 푦. 푁 } recursive computation rec푉 as ralt for 푦, since it might not A Computational Understanding of Classical (Co)Recursion PPDP ’20, September 8–10, 2020, Bologna, Italy be a value (in call-by-value). Instead, the recursive computa- used (such as in the pred function), then rec can provide tion is merely bound to 푦, so that the correct next reduction an answer without computing the recursive result. How- step can be performed in either evaluation strategy. ever, when encoding rec with iter, the result of the recursive In call-by-name, this next step is indeed to substitute value must always be computed before an answer is seen, rec푉 as ralt for 푦, and so we have: regardless of whether or not 푦 is needed. rec succ 푀 as ralt ↦→→ 푁 ′[푀/푥, rec 푀 as ralt/푦] Notice that this difference in cost is only apparent in call- by-name, which can be asymptotically more efficient when So call-by-name recursion is computed starting with the the recursive 푦 is not needed to compute 푁 ′, as in pred. In current (largest) number first and ending with the smallest call-by-value, the recursor must descend to the base case number needed (possibly the base case for zero). If a recursive anyway before the incremental recursive steps are propa- result is not needed (such as with the encoding of case) gated backward. That is to say, the call-by-value rec has the then it is not computed at all, allowing for an early end of same asymptotic complexity as its encoding via iter. the recursion. In contrast, call-by-value must evaluate the In contrast, inductive reasoning is more powerful in call- 푦 recursive result first before it can be substituted for . As by-value, because every (closed) value of type nat will have such, call-by-value recursion always starts by computing the form succ푛 zero for some number 푛 ≥ 0. We will ex- the base case for zero (whether or not it is needed), and the plore the differences in inductive reasoning later in section6. intermediate results are propagated backwards until the case Therefore, when choosing between a call-by-value or call-by- for the initial number is reached. So call-by-value allows for name semantics for a language, there is a tension between no opportunity to end the computation of rec early. reasoning power and asymptotic efficiency for recursion. Both the type system and operational semantics of Sys- tem T work together, ensuring that well-typed programs (i.e., 3 Recursion in an Abstract Machine closed terms of type nat) always finish and return a value built by the nat constructors. An abstract machine is a useful tool for explicating lower- level performance details of recursion. Unlike the operational 1 (Type safety & Termination). If • ⊢ 푀 : nat in semantics given in fig.3, which has to search for the next System T then 푀 ↦→→ zero or 푀 ↦→→ succ푉 for some 푉 . redex at every step, an abstract machine explicitly includes this search in the computation itself. As such, every step of As example uses of the recursor, we can encode the fol- the machine can apply by matching only on the top-level lowing by pattern-matching form of the machine state. plus zero 푦 = 푦 plus (succ 푥) 푦 = succ (plus 푥 푦) We will now examine an abstract machine for System T, pred zero = zero pred (succ 푥) = 푥 which spells out how to find and perform each redex ina minus 푥 zero = 푥 minus 푥 (succ푦) = minus (pred 푥) 푦 computation.1 First, consider this abstract machine for call- into System T’s rec as follows: by-name System T based on the Krivine machine [28]: plus = 휆푥.휆푦. iter 푥 as{zero → 푦 | succ → 푧. succ 푧} ⟨푀 푁 ||퐸⟩ ↦→ ⟨푀||푁 · 퐸⟩ pred = 휆푥. case 푥 of{zero → zero | succ푦 → 푦} ⟨rec 푀 as ralt||퐸⟩ ↦→ ⟨푀|| rec ralt with 퐸⟩ minus = 휆푥.휆푦. iter푦 as{zero → 푥 | succ → 푧. pred 푧} ⟨휆푥.푀||푁 · 퐸⟩ ↦→ ⟨푀 [푁 /푥]||퐸⟩ Note that plus can be defined using only iter, however pred ⟨zero || rec ralt with 퐸⟩ ↦→ ⟨푁 ||퐸⟩ (and therefore minus) uses case, which is not immediately ⟨succ 푀|| rec ralt with 퐸⟩ ↦→ ⟨푁 ′[푀/푥, rec 푀 as ralt/푦]||퐸⟩ available from iter. where ralt := {zero → 푁 | succ 푥 → 푦.푁 ′} above. The 2.1 Recursion vs iteration first two rules are refocusing rules that move the attention We saw how iteration can be encoded in terms of recursion by of the machine closer to the next reduction building a larger just ignoring the predecessor. The only cost of this encoding continuation: for function application (푁 · 퐸 corresponding is an unused variable binding, which is easily optimized away. to 퐸[□ 푁 ]) and recursion (rec ralt with 퐸 corresponding to In practice, the encoding of iteration will perform exactly 퐸[rec □ as ralt]). The latter three rules are reduction rules the same as if we had taken iteration as a primitive. which correspond to steps of the operational semantics in Going the other way, it is also known that recursion can fig.3. Note that in the machine, the recursor must explicitly be encoded in terms of iteration by using pairs as follows: accumulate and build upon a continuation, “adding to” the rec 푀 as snd(iter 푀 as place it returns to with every recursive call. { zero → 푁 := { zero → (zero, 푁 ) | succ 푥 → 푦.푁 ′} | succ → (푥,푦).(succ 푥, 푁 ′)}) 1Our primary interest in abstract machines is in the accumulation and use of these continuations. For simplicity, we leave out other common details Unfortunately, this encoding of recursion is not always as sometimes specified by abstract machines, such as modeling a concrete efficient as the original. If the recursive parameter 푦 is never representation of and environments. PPDP ’20, September 8–10, 2020, Bologna, Italy P. Downen and Z.M. Ariola

푐 푣 푒 Commands ( ), general terms ( ), and general coterms ( ): Γ ⊢ 푣 : 퐴 Γ ⊢ 푒 ÷ 퐴 Cut 푐 ::= ⟨푣||푒⟩ 푣,푤 ::= 휇훼.푐 | 푉 푒, 푓 ::= 휇푥.푐˜ | 퐸 Γ ⊢ ⟨푣||푒⟩ ralt ::= {zero → 푣 | succ 푥 → 푦.푤} VarR VarL Γ, 푥 : 퐴 ⊢ 푥 : 퐴 Γ, 훼 ÷ 퐴 ⊢ 훼 ÷ 퐴 푉 퐸 Call-by-name values ( ) and evaluation contexts ( ): Γ, 훼 ÷ 퐴 ⊢ 푐 Γ, 푥 : 퐴 ⊢ 푐 ActR ActL 푉,푊 ::= 휇훼.푐 | 푥 | 휆푥.푣 | zero | succ 푣 Γ ⊢ 휇훼.푐 : 퐴 Γ ⊢ 휇푥.푐˜ ÷ 퐴 퐸, 퐹 훼 푣 퐸 퐸 ::= | · | rec ralt with Γ, 푥 : 퐴 ⊢ 푣 : 퐵 ⊢ 푣 퐴 ⊢ 푒 ÷ 퐵 →푅 Γ : Γ →퐿 Call-by-value values (푉 ) and evaluation contexts (퐸): Γ ⊢ 휆푥.푣 : 퐴 → 퐵 Γ ⊢ 푣 · 푒 ÷ 퐴 → 퐵 Γ ⊢ 푉 : nat 푉,푊 ::= 푥 | 휆푥.푣 | zero | succ푉 nat푅 nat푅 ⊢ zero ⊢ 푉 succ 퐸, 퐹 ::= 휇푥.푐˜ | 훼 | 푉 · 푒 | rec ralt with 푒 Γ zero : nat Γ succ : nat Γ ⊢ 푣 : 퐴 Γ, 푥 : nat,푦 : 퐴 ⊢ 푤 : 퐴 Γ ⊢ 퐸 ÷ 퐴 Operational reduction rules: nat퐿 Γ ⊢ rec{zero → 푣 | succ 푥 → 푦.푤} with 퐸 ÷ nat (휇)⟨휇훼.푐||퐸⟩ ↦→ 푐 [퐸/훼] (휇˜)⟨푉 ||휇푥.푐˜ ⟩ ↦→ 푐 [푉 /푥] Figure 5. Type system for the System T machine. (훽→)⟨휆푥.푣||푉 · 퐸⟩ ↦→ ⟨푣 [푉 /푥]||퐸⟩ can be translated to the language of the abstract machine (훽 )⟨zero || rec ralt with 퐸⟩ ↦→ ⟨푣||퐸⟩ zero using 휇- and 휇˜-bindings as follows: (훽succ)⟨succ푉 || rec ralt with 퐸⟩ ↦→ ⟨휇훼.⟨푉 || rec ralt with 훼⟩ 휇푦. 푤 푉 푥 퐸 푥 := 푥 || ˜ ⟨ [ / ]|| ⟩⟩ J K 휆푥.푀 := 휆푥. 푀 where ralt = {zero → 푣 | succ 푥 → 푦.푤} J K J K zero := zero Figure 4. Uniform abstract machine for System T. J K succ 푀 := 휇훼.⟨ 푀 ||휇푥.˜ ⟨succ 푥||훼⟩⟩ J K J K This abstract machine is specialized for the call-by-name 푀 푁 := 휇훼.⟨ 푀 ||휇푥.˜ ⟨ 푁 ||휇푦.˜ ⟨푥||푦 · 훼⟩⟩⟩ J K J K J K semantics. How should we approach the call-by-value ver- rec 푀 as ralt := 휇훼.⟨ 푀 || rec ralt with 훼⟩ sion? We could define an entirely separate abstract machine J K J K J K {zero →푀 | succ 푥→푦.푁 } := {zero → 푀 | succ 푥→푦. 푁 } with many more refocusing rules and continuations (corre- J K J K J K sponding to the additional cases of evaluation contexts in We can also give a type system directly for the abstract call-by-value). Instead, we will unite both evaluation strate- machine, as shown in fig.5. This system has judgments for gies with a common abstract machine, shown in fig.4, based assigning types to terms as usual: Γ ⊢ 푣 : 퐴 states that 푣 on the 휆휇휇˜ sequent calculus [7]. Machine states are com- produces an output of type 퐴. In addition, there are also mands (푐) of the form ⟨푣||푒⟩ which puts together a general judgments Γ for assigning types to coterms (Γ ⊢ 푒 ÷ 퐴 states term (푣) which produces an output and a general coterm (푒, that 푒 consumes an input of type 퐴) and commands (Γ ⊢ 푐 read as “continuation terms” as well as the dual to terms) states that 푐 is safe to compute, and does not produce or which consumes an input. consume anything). With this type system, we can capture As with System T, the operational semantics depends on the fact that compilation preserves types as well as the oper- the notion of value (푉 ) and covalue (퐸, analogous to eval- ational semantics of System T terms. uation contexts and read as “continuation values” as well Theorem 2 (Type Preservation). Γ ⊢ 푀 : 퐴 iff Γ ⊢ 푀 : 퐴. as the dual to values) specialized to either evaluation strat- J K egy. However, now the syntax of general terms and coterms Theorem 3 (Operational Correspondence). For any also depend on the of values and covalues. Gen- • ⊢ 푀 : nat in System T: 휇 eral terms include -bindings (corresponding to Scheme’s 푀 푀 훼 훼 휇 1. ↦→→ zero if and only if ⟨ || ⟩ ↦→→⟨zero || ⟩, and call/cc) and values, and general coterms include ˜-bindings 푀 푉 J K푀 훼 푉 ′ 훼 푥 푀 2. ↦→→ succ if and only if ⟨ || ⟩ ↦→→⟨succ || ⟩, (corresponding to contexts let = □ in ) and covalues. J K Note that in call-by-name, values are the same as general under both call-by-name and -value evaluation. terms, but covalues are more restrictive than coterms. Dually, Remark 1. Since the 휆휇휇˜-calculus is based on the of call-by-value covalues are the same as general coterms, but Gentzen’s sequent calculus [16], the type system in fig.5 too values are more restrictive than terms. can be viewed as a term assignment for a particular sequent The semantics in fig.4 no longer has any of the old refo- calculus. In particular, the 푣 : 퐴 corresponds to a cusing rules; instead the generic 휇 and 휇˜ reductions perform 퐴 푒÷퐴 퐴 any needed refocusing by substituting a value for the bound that is true. Dually corresponds to a proof that variable 푥, or a covalue for the bound covariable 훼 (read as is , and hence the notation, which can be understood as 푒 퐴 “continuation variable” as well as the dual to a variable). For a built-in − in : − . As such, the built-in negation example, the refocusing rule ⟨푀 푁 ||퐸⟩ ↦→ ⟨푀||푁 · 퐸⟩ is en- in every 푒÷퐴 (or 훼÷퐴) can be removed by swapping between coded as 푀 푁 = 휇훼.⟨푀||푁 ·훼⟩, where 훼 stands for the generic the left- and right-hand sides of the turnstyle (⊢), so that 푒 ÷퐴 퐸 in the refocusing step. More formally, all System T terms on the right becomes 푒 : 퐴 on the left, and 훼 ÷ 퐴 on the left A Computational Understanding of Classical (Co)Recursion PPDP ’20, September 8–10, 2020, Bologna, Italy

Types and corecursive alternatives for streams: just passes the accumulator to 푒, which (may) return the 퐴, 퐵 ::= · · · | strm 퐴 calt ::= {head 훼 → 푒 | tail 훽 → 훾.푓 } current element to the continuation 훼. The corecursive case tail 훽 → 훾.푓 also passes the accumulator to 푓 , which may Extension of call-by-name (co)values: return an updated accumulator (through 훾) or circumvent 푉,푊 ::= · · · | corec calt with 푣 퐸, 퐹 ::= · · · | head 퐸 | tail 퐸 further corecursion by returning another stream directly to Extension of call-by-value (co)values: the remaining projection (via 훽). As with the syntax, the operational semantics in fig.6 and 푉,푊 ::= · · · | corec calt with푉 퐸, 퐹 ::= · · · | head 푒 | tail 푒 typing rules in fig.7 are roughly symmetric to the rules for Operational reduction rules: natural numbers, where roles of terms and coterms have

(훽head)⟨corec calt with푉 || head 퐸⟩ ↦→ ⟨푉 ||푒 [퐸/훼]⟩ been flipped. As with System T, these typing and operational rules work together to ensure type safety and termination (훽tail)⟨corec calt with푉 || tail 퐸⟩ ↦→ ⟨휇훾.⟨푉 ||푓 [퐸/훽]⟩||휇푥.˜ ⟨corec calt with 푥||퐸⟩⟩ when extended with infinite streams. where calt := {head 훼 → 푒 | tail 훽 → 훾.푓 }. Theorem 4 (Type safety & Termination). If 훼 ÷ nat ⊢ 푐 푐 훼 Figure 6. Stream corecursion in the abstract machine. in the (co)recursive abstract machine then ↦→→⟨zero || ⟩ or 푐 ↦→→⟨succ푉 ||훼⟩ for some 푉 . Γ ⊢ 퐸 ÷ 퐴 Γ ⊢ 퐸 ÷ strm 퐴 strm퐿 strm퐿 Similar to recursion, we can define two special cases of Γ ⊢ head 퐸 ÷ strm 퐴 head Γ ⊢ tail 퐸 ÷ strm 퐴 head corec which only use part of its functionality by just ignoring Γ, 훼 ÷ 퐴 ⊢ 푒 ÷ 퐵 Γ, 훽 ÷ strm 퐴,훾 ÷ 퐵 ⊢ 푓 ÷ 퐵 Γ ⊢ 푉 : 퐵 strm푅 a parameter in the corecursive branch: Γ ⊢ corec{head 훼 → 푒 | tail 훽 → 훾.푓 } with푉 : strm 퐴 cocase { head 훼 → 푒 corec { head 훼 → 푒 Figure 7. Typing rules for streams in the abstract machine. | tail 훽 → 푓 } := | tail 훽 → .푓 } with푉 with푉 becomes 훼 : 퐴 on the right. Doing so gives a conventional coiter { head 훼 → 푒 corec { head 훼 → 푒 two-sided sequent calculus as in [4, 11], where the rules | tail → 훾.푓 } := | tail → 훾.푓 } 푉 푉 labeled 퐿 with conclusions of the form 푥푖 : 퐵푖, 훼 푗 ÷퐶푗 ⊢ 푒 ÷퐴 with with 푥 퐵 | 푒 퐴 ⊢ 훼 퐶 correspond to left rules of the form 푖 : 푖 : 푗 : 푗 Specifically, cocase simply pattern-matches on the projec- in the sequent calculus. tion of the form head 훼 or tail 훽 without corecursing at all, whereas coiter always corecurses by providing an updated 4 Corecursion in an Abstract Machine accumulator in the tail 훽 case without referring to 훽. Our abstract machine is based on the 휆휇휇˜-calculus, a sym- As examples, consider the following two streams: metric language reflecting many dualities of classical logic. scons 푥 (푦 ,푦 ,... ) = 푥,푦 ,푦 ,... Producers (terms) are dual to consumers (coterms), call-by- 1 2 1 2 count 푥 = 푥, succ 푥, succ(succ 푥),... value is dual to call-by-name [7, 38], and so on. This sym- metry can help us answer the question: what is the dual to scons 푥 푠 appends a new element 푥 on top of the stream 푠, and recursion, i.e., what is corecursion? count 푥 counts all the successive natural numbers starting As a prototypical example of a coinductive type, consider with 푥. These two definitions can be made formal in terms infinite streams of values, chosen for their familiarity (other of a language with copattern matching [2] like so: coinductive types work just as well), which we will represent head(scons 푥 푠) = 푥 head(count 푥) = 푥 by the type strm 퐴 as given in fig.6. The intention is that tail(scons 푥 푠) = 푠 tail(count 푥) = count (succ 푥) strm 퐴 is roughly dual to nat, and so we will flip the roles of terms and coterms belonging to streams. In contrast with nat, which correspond to the following uses of corecursion: which has constructors for building values, strm 퐴 has two scons := 휆푥.휆푠. cocase{head 훼 → 훼 | tail 훽 → 휇˜ .⟨푠||훽⟩} with 푥 퐸 destructors for building covalues. First, the covalue head count := 휆푥. coiter{head 훼 → 훼 | tail → 훾.휇푥.˜ ⟨succ 푥||훾⟩} with 푥 projects out the first element of its given stream and passes its value to 퐸. Second, the covalue tail 퐸 discards the first To see the full generality of corecursion, consider app that element of the stream and passes the remainder of the stream appends a list (serving as the prefix) to a stream (serving as to 퐸. Next, in order to define stream values, we have a co- the suffix): 푉 recursor of the form corec calt with where calt matches app [푥1, 푥2, . . . , 푥푛](푦1,푦2,... ) = 푥1, 푥2, . . . , 푥푛,푦1,푦2,... the head and tail destructors above. The corecursor generates (on the fly) the values of the This function can be formally defined in terms of copatterns and corec, respectively, like so: stream using푉 as an incremental accumulator or seed, saving the progress made through the stream so far. In particular, head(app nil 푦푠) = head푦푠 head(app (cons 푥 ) 푦푠) = 푥 the base case head 훼 → 푒 matching the head projection tail(app nil 푦푠) = tail푦푠 tail(app (cons 푥 푥푠) 푦푠) = app 푥푠 푦푠 PPDP ’20, September 8–10, 2020, Bologna, Italy P. Downen and Z.M. Ariola app := 휆푥푠.휆푦푠. corec From the point of view of polarity in programming lan- {head 훼 → case {nil → ⟨푦푠|| head 훼⟩ | cons 푥 → ⟨푥||훼⟩} guages [31, 39], the ⊤ type for we use in “numbered ⊤” | tail 훽 →훾. case {nil → ⟨푦푠|| tail 훽⟩ | cons 푥 푥푠′ → ⟨푥푠′||훾⟩}} should be interpreted as a positive type (written as 1 in [19]). Dually, the ⊥ type for falsehood in “strm ⊥” is a with 푥푠 negative type (also called ⊥ in linear logic). Above, the continuation case{nil → 푐 | cons 푥 푥푠 → 푐 ′} corresponds to the case □ of {nil → 푐 | cons 푥 푥푠 → 푐 ′} 4.2 Corecursion vs coiteration evaluation context for pattern-matching on lists. Note that, Recall from section2 that recursion in call-by-name versus the behavior of the corecursive case for tail 훽 depends on call-by-value have different algorithmic complexities. The ′ ′ the accumulator: the tail 푥푠 of a non-empty cons 푥 푥푠 is same holds for corecursion, with the benefit going instead to passed to 훾 which updates the corecursive seed for the next call-by-value. For example, consider the scons function for stream destructor, whereas the empty nil triggers the end of appending a new element to a stream. Ideally, scons should corecursion because 훾 is ignored and the suffix stream 푦푠 is not leave a lingering effect on the underlying stream. That passed directly to the original continuation tail 훽. is to say, the tail of scons 푥 푠 should just be 푠. This happens directly in call-by-value. Consider indexing 4.1 Properly dual (co)recursive types the 푛 + 1푡ℎ element of scons in call-by-value: Although we derived corecursion from recursion using du- ⟨ || · · 푛+1 ( )⟩ ↦→→⟨ || 푛+1 ( )⟩( ) ality, our prototypical examples of natural numbers and scons 푥 푠 tail head 훼 scons푥,푠 tail head 훼 훽→ 푛 streams were not perfectly dual to one another. While the ↦→→⟨푠|| tail (head 훼)⟩(훽tail휇휇˜) 퐸 푉 (co)recursive case of tail looks similar to succ , the base Notice how, after the first tail is resolved, the computation cases of head 퐸 and zero don’t exactly line up, because head incurred by scons has completely vanished. In contrast, the takes a parameter but zero does not. computation of scons continues to linger in call-by-name: One way to perfect the duality is to generalize the nat ⟨ || · · 푛+1 ( )⟩ ↦→→⟨ || 푛+1 ( )⟩( ) type to numbered 퐴: this type represents values of 퐴 labeled scons 푥 푠 tail head 훼 scons푥,푠 tail head 훼 훽→ 푛 with a natural number. We can define numbered 퐴 by the ↦→→⟨scons푣1,푠 || tail (head 훼)⟩(훽tail휇˜) 푛 following generalized constructors: where 푣1 = 휇˜ .⟨푥||휇˜ .⟨푠|| tail (head 훼)⟩⟩ 푉 퐴 푉 퐴 Γ ⊢ : Γ ⊢ : numbered Here, we will spend time over the next 푛 tail projections to 푉 퐴 푉 퐴 Γ ⊢ zero : numbered Γ ⊢ succ : numbered build up an ever larger accumulator until the head is reached, zero푉 labels the value 푉 with 0, and succ푉 increments the even though the result will inevitably just be asking 푠 directly. numeric label of 푉 . With the generalized zero constructor, In this way, the efficiency of corecursion is better in call-by- we must generalize recursion with an extra parameter: value than in call-by-name. Also recall from section 2.1 that we were able to encode ralt ::= {zero 푥 → 푣 | succ푦 → 푧.푤} the recursor in terms of the (apparently) weaker iterator It turns out that numbered 퐴 is the proper dual to strm 퐴. using pairs. We can do a similar encoding of corecursion in In more detail, we can express the duality relation (which terms of coiteration using the dual of pairs: sum types. Sum we write as ∼) between values and covalues of these two types in the sequent calculus look like [38]: types. Assuming that 푉 ∼ 퐸, we have the following duality 푉 푒 , 푒 푉 푒 푉 푒 , 푒 푉 푒 between the constructors and destructors: ⟨left ||[ 1 2]⟩ ↦→ ⟨ || 1⟩⟨right ||[ 1 2]⟩ ↦→ ⟨ || 2⟩ zero푉 ∼ head 퐸 succ푉 ∼ tail 퐸 We can then write the following encoding of corecursion: For (co)recursion, we have the following dualities, assuming corec { head 훼 → 푒 coiter { head 훼 → [head 훼, 푒] 푣 ∼ 푒 (under 푥 ∼ 훼) and 푤 ∼ 푓 (under 푦 ∼ 훽 and 푧 ∼ 훾): | tail 훽 → 훾.푓 } := | tail → [훽,훾].[tail 훽, 푓 ]} corec{head 훼 → 푒 | tail 훽 → 훾.푓 } with푉 with right푉 ∼ rec{zero 푥 → 푣 | succ푦 → 푧.푤} As with recursion, this encoding forces a performance penalty We could also express the proper duality by restricting for functions like scons which can return a stream directly streams instead of generalizing numbers. In terms of the in the corecursive case instead of updating the accumulator. type defined above, nat is isomorphic to numbered ⊤, where ⊤ represents the usual unit type with a single value (often 5 Functional, Effectful (Co)recursion written as ()). Since ⊤ corresponds to , its dual is We saw how corecursion, and not just coiteration, can be the ⊥ type corresponding to logical falsehood with a single expressed inside an abstract machine. How can corecursion covalue that represents an empty continuation. With this in be seen in a more familiar language similar to System T? mind, the type nat is properly dual to strm ⊥, i.e., an infinite Our key insight is that the generality of corecursor is made stream of computations that do not return. possible by control effects equivalent to Scheme’s call/cc A Computational Understanding of Classical (Co)Recursion PPDP ’20, September 8–10, 2020, Bologna, Italy

addition to everything from System T, this language has 휇- 퐴, 퐵 ::= 퐴 → 퐵 | nat | strm 퐴 abstractions (휇훼.퐽) and jumps (⟨푀||푄⟩) from the 휆휇-calculus, 퐽, 퐿 ::= ⟨푀||푄⟩ along with the dual 휇˜-abstractions (휇푥.퐽˜ ). Intuitively, the 휇휇˜– 푀, 푁 ::= 푥 | 휇훼.퐽 | 휆푥.푀 | 푀 푁 abstractions serve the same role as in the abstract machine— | zero | succ 푀 | rec 푀 as ralt assigning a name to the continuation of a term or the value | head 푀 | tail 푀 | corec calt with 푀 given to a continuation, respectively—but now appear in the 푄, 푅 = 훼 | 휇푥.퐽 :: ˜ context of a direct-style, functional language. = { → 푁 | 푥 → 푦.푀} ralt :: zero succ The corecursor corec calt with 푀 appears almost the same = { → 푥.푁 | 훽 → 푦.푀} calt :: head tail as it did in the abstract machine (albeit slightly generalized 푀 Figure 8. Syntax of 휆휇휇˜ extended with (co)recursion. so that the accumulator does not need to be a value), but the stream alternatives calt are written in a different from, 푥.푁 훽 푦.푀 Γ ⊢ 푀 : 퐴 Γ ⊢ 푄 ÷ 퐴 {head → | tail → }, so that corecursion can be 퐶푢푡 Γ ⊢ ⟨푀||푄⟩ written entirely with terms. Similarly, the stream projections now appear as terms rather than coterms. head 푀 returns the Γ, 훼 ÷ 퐴 ⊢ 퐽 Γ, 푥 : 퐴 ⊢ 퐽 푀 푀 퐴푐푡 퐶표퐴푐푡 first element of a stream , and tail returns the remaining Γ ⊢ 휇훼.퐽 : 퐴 Γ ⊢ 휇푥.퐽˜ ÷ 퐴 elements of 푀. In total, the syntax of this 휆휇휇˜-calculus is Γ ⊢ 푀 : strm 퐴 Γ ⊢ 푀 : strm 퐴 biased toward terms, where the only coterms are labels (i.e., strm퐼head strm퐼tail Γ ⊢ head 푀 : 퐴 Γ ⊢ tail 푀 : strm 퐴 covariables 훼) or abstractions (휇푥.퐽˜ ). Γ, 푥 : 퐵 ⊢ 푁 : 퐴 Γ, 훽 ÷ strm 퐴,푦 : 퐵 ⊢ 푁 ′ : 퐵 Γ ⊢ 푀 : 퐵 As before, we can macro-define the special cases for cocase strm퐸 Γ ⊢ corec{head → 푥.푁 | tail 훽 → 푦.푁 ′} with 푀 : strm 퐴 and coiter as ignoring the unneeded parameters of corec (and the unneeded accumulator for cocase): Figure 9. Type system for corecursion in 휆휇휇˜.

Call-by-name values (푉 ), covalues (퐾), and evaluation contexts (퐸): corec { head → .푁 cocase {head → 푁 푉,푊 ::= 푀 퐾, 퐻 ::= 훼 := | tail 훼 → .휇 .⟨푀||훼⟩} | tail → 푀} 퐸, 퐹 ::= □ | 퐸 푁 | rec 퐸 as ralt | head 퐸 | tail 퐸 | ⟨퐸||퐾⟩ with zero 푥.푁 푥.푁 Call-by-value values, covalues, and evaluation contexts: coiter { head → corec { head → | tail → 푦.푁 ′} = | tail → 푦.푁 ′} 푉,푊 ::= 푥 | 휆푥.푀 | zero | succ푉 | corec calt with푉 : with 푀 with 푀 퐾, 퐻 ::= 푄 퐸, 퐹 ::= □ | 퐸 푁 | 푉 퐸 | succ 퐸 | rec 퐸 as ralt The intuitive understanding is that cocase introduces a stream | head 퐸 | tail 퐸 | corec calt with 퐸 | ⟨퐸||퐾⟩ whose first element is exactly 푁 and remainder is 푀, analo- Operational reduction rules: gous to scons previously in section4, so that: (휇)⟨퐸[휇훼.퐽]||퐾⟩ ↦→ 퐽 [⟨퐸[푀]||퐾⟩/⟨푀||훼⟩] (휇˜)⟨푉 ||휇푥.퐽˜ ⟩ ↦→ 퐽 [푉 /푥] head(cocase{head → 푁 | tail → 푀}) = 푁 ( )( ) ↦→ [ / ] 훽→ 휆푥.푀 푉 푀 푉 푥 tail(cocase{head → 푁 | tail → 푀}) = 푀 (훽zero) rec zero as ralt ↦→ 푁 (훽 ) rec succ푉 as ralt ↦→ 휇훼.⟨rec푉 as ralt||휇푦.˜ ⟨푁 [푉 /푥]||훼⟩⟩ succ As we saw with scons, call-by-value evaluation reaches these (훽head) head(corec calt with푉 ) ↦→ 푁 [푉 /푥] results directly but it may take (arbitrarily many) steps with (훽tail)⟨퐸[tail(corec calt with푉 )]||퐾⟩ call-by-name evaluation. coiter can be read as an endless ↦→ ⟨퐸[corec calt with 푁 ′[푉 /푦, ⟨퐸[푀]||퐾⟩/⟨푀||훽⟩]]||퐾⟩ loop that either returns the current element (given by binding the value of 푀 to 푥 in 푁 ) or calculates the remaining stream = { → | → ′} Where ralt : zero 푁 succ 푥 푦.푁 and by updating its internal state (given by binding 푀 to 푦 in 푁 ). calt := {head → 푥.푁 | tail 훽 → 푦.푁 ′} above. However, there is no opportunity for coiter to avoid updating 휆휇휇 Figure 10. Operational semantics for (co)recursion in ˜. the internal state in the tail case, and so the coiteration will continue no matter how deeply the stream is inspected. operator. The corecursive branch is given access to two con- The type system for the (co)recursive 휆휇휇˜-calculus extends tinuations: one to update the accumulator and continue the the one for System T with additional typing rules given in corecursion, and the other to end corecursion early by pro- fig.9. As with the abstract machine, we have judgments for viding another stream in its entirety. checking that a continuation 푄 accepts an input of type 퐴 Our functional language for expressing corecursion is (written Γ ⊢ 푄 ÷ 퐴) and that a jump 퐽 is well-typed (written based on the 휆휇휇˜-calculus [8]—an extension of Parigot’s Γ ⊢ 퐽). Writing the type for a continuation of 퐴 as the nega- 휆휇-calculus [33] with 휇˜-abstractions—as shown in fig.8. In tion −퐴 (recall remark1), we can view the stream operations PPDP ’20, September 8–10, 2020, Bologna, Italy P. Downen and Z.M. Ariola as primitive constants with the following types: Theorem 6 (Operational correspondence). For any jump 훼 ÷ ⊢ 퐽 휆휇 head : strm 퐴 → 퐴 tail : strm 퐴 → strm 퐴 nat in (co)recursive , under both call-by-name and -value evaluation: cocasestrm 퐴 : 퐴 → strm 퐴 → strm 퐴 퐽 훼 퐽 훼 coiter퐵 : (퐵→퐴) → (퐵→퐵) → 퐵 → strm 퐴 1. ↦→→⟨zero || ⟩ if and only if ↦→→⟨zero || ⟩, and strm 퐴 퐽 푉 훼 J K퐽 푉 ′ 훼 퐵 퐵 퐴 퐴 퐵 퐵 퐵 퐴 2. ↦→→⟨succ || ⟩ if and only if ↦→→⟨succ || ⟩. corecstrm 퐴 : ( → ) → (−(strm )→ → ) → → strm J K The operational semantics for (co)recursion is given in The example streams repeat 푥 = 푥, 푥, 푥, . . . and alt = , , , ,... fig. 10. The rules for functions (훽→) and recursion (훽zero, 훽succ) 0 1 0 1 can be written in terms of corecursion like so: are the same as from fig.3. The 휇 rule states how the evalua- repeat := 휆푥. coiter{head → 푦.푦 | tail → 푧.푧} with 푥 tion context is captured by 휇훼.퐽 and the 휇˜ rule states how flip := 휆푥. case 푥 of{zero → succ zero | succ → zero} values are bound by 휇푥.퐽˜ , after which the jump 퐽 is per- alt := coiter{head → 푥.푥 | tail → 푥.flip 푥} with zero formed in either case. The 휇 rule makes use of structural substitution to substitute an evaluation context (퐸) for a co- Notice that the operational semantics of fig. 10 gives alter- variable (훼), written as 퐽 [퐸[푀]/⟨훼||푀⟩] in general, meaning nating outputs for the elements of alt: that every jump of the form ⟨훼||푀⟩ inside 퐽 (where 훼 ap- pears free) is replaced by 퐸[푀]. Note that to be syntactically ⟨head alt||훼⟩ ↦→ ⟨zero ||훼⟩ well-formed, the left- and right-hand-sides of the 휇 rule are ⟨head(tail alt)||훼⟩ ↦→→⟨head alt′||훼⟩ ↦→ ⟨succ zero ||훼⟩ 훼 훼 훼 both jumps. The 훽head rule projects out the first element of ⟨head(tail(tail alt))|| ⟩ ↦→→⟨head alt|| ⟩ ↦→ ⟨zero|| ⟩ a corecursive stream by substituting the accumulator for the variable bound by the head case. The 훽 rule projects and so on, where the intermediate state of the stream is tail ′ { → 푥.푥 | → 푥. 푥} out the remainder of a corecursive stream by updating the alt := coiter head tail flip with succ zero. accumulator. This update performs two important bindings 5.1 A corecursive coeliminator required by the tail case: (a) the current value of the accumu- lator is substituted for the bound variable, and (b) the current Recall from section 4.1 that in the abstract machine, recursion evaluation context is substituted for the covariable bound by and cocorecursion are perfectly dual to one another for dual the copattern tail 훽. As such, the 훽tail reduction may result in types. The recursor has an internal state in the form of a a new accumulator if this computation returns normally, or covalue (i.e., continuation) keeping track of the call stack it may jump to 훽 and provide an altogether different stream. built up by each step of recursion, whereas the corecursor The reduction theory of the (co)recursive 휆휇휇˜-calculus is has an internal state in the form of a value (i.e., accumulator) written as 퐽 → 퐽 ′ (and similar for (co)terms) and includes that keeping of the progress made from one element to the the compatible closure of the operational rules (that is, they next as projections are made deeper into the stream. may be applied in any context, not just evaluation contexts). Yet, in the 휆휇휇˜-calculus, the recursor and corecursor no We also include the following additional rule in the reduction longer appear dual at all: the corecursor still has its inter- theory, which accounts for administrative reductions that nal state but the recursor just returns a result, seemingly bind arbitrary terms inside of an evaluation context: statelessly. How can the duality between these two forms be restored? The mismatch is born from the fact that introduc- (휍)⟨푀||휇푥.퐸˜ [푥]⟩ → 퐸[푀] tions and eliminations of terms are not dual do each other 휍 reduction completes the correspondence with the abstract in the sense we need. Instead, an elimination of terms is machine, given by this extension of the System T translation: symmetric to an elimination of coterms, i.e., a coelimination. ⟨푀||푄⟩ := ⟨ 푀 || 푄 ⟩ Coeliminators for functions have appeared before [6, 32], J K J K J K which has been used to study the issues of confluence [27] 훼 := 훼 J K and head normalization [26] with control effects. We can 휇푥.퐽˜ := 휇푥.˜ 퐽 J K J K derive a similar form of coelimination for streams here, us- head 푀 := 휇훼.⟨ 푀 || head 훼⟩ ing 휇˜-abstractions. First, the head and tail projections can be J K J K defined via macro-expansion as coterms like so: tail 푀 := 휇훼.⟨ 푀 || tail 훼⟩ J K J K corec calt with 푀 := 휇훼.⟨ 푀 ||휇푥.˜ ⟨corec calt with 푥||훼⟩⟩ head푄 := 휇푥.˜ ⟨head 푥||푄⟩ tail푄 := 휇푥.˜ ⟨tail 푥||푄⟩ J K J K J K {head → 푥.푁 | tail 훽 → 푦.푀} From there, we can give the following syntactic sugar for J K := {head 훼 → 휇푥.˜ ⟨ 푁 ||훼⟩ | tail 훽 → 훾.휇푦.˜ ⟨ 푀 ||훾⟩} corecursion defined by eliminating these two coterms: J K J K This translation preserves both the types and operations of 휇푥.˜ ⟨corec { head → 푧.휇훼.⟨푧||푅⟩ 휆휇휇 corec푄 as the (co)recursive ˜-calculus in the abstract machine. | 훽 → 푦.휇훾.⟨푦||푅′⟩} { head 훼 → 푅 := tail Theorem 5 (Type Preservation). Γ ⊢ 퐽 in (co)recursive 휆휇 if ′ with 푥 | tail 훽 → 훾.푅 } 푄 and only if Γ ⊢ 퐽 , and analogously for (co)terms. || ⟩ J K A Computational Understanding of Classical (Co)Recursion PPDP ’20, September 8–10, 2020, Bologna, Italy

The new definitions allow us to derive these reductions: Properties (Φ), strict (Ψ(푥)) and productive (Ψ(훼)) properties, hy- pothesis (휃), environments (Γ), and judgments: 퐾 푅 퐾 훼 corec head as calt →→ [ / ] Φ ::= 푐 =푐′ | 푣 = 푣 ′ : 퐴 | 푒 = 푒′ ÷ 퐴 | ∀푥:퐴.Φ | ∀훼÷퐴.Φ | Φ′⇒ Φ corec tail 퐾 as calt →→ 휇푥.˜ ⟨휇훾.⟨푥||푅′[퐾/훽]⟩|| corec 퐾 as calt⟩ Ψ(푥) ::= ⟨푥||퐸⟩ = ⟨푥||퐸′⟩ | ∀푦:퐴.Ψ(푥) | ∀훼÷퐴.Ψ(푥)(푦 ≠ 푥) This provides us an alternative understanding of corecursion: Ψ(훼) ::= ⟨푉 ||훼⟩ = ⟨푉 ′||훼⟩ | ∀푥:퐴.Ψ(훼) | ∀훽÷퐴.Ψ(훼)(훽 ≠ 훼) rather than focusing on generating some infinite object, we Γ ::= • | Γ, 푥 : 퐴 | Γ, 훼 ÷ 퐴 | Γ, Φ Judge ::= Γ ⊢ Φ can instead focus on processing a finite observation. In other Equality of computation (plus rules for reflexivity, symmetry, tran- words, we can write corecursive definitions in the same style sitivity, and compatibility of equality): as recursion on the natural numbers, with the twist that we Γ ⊢ 푐 푐 ↦→ 푐′ are calculating a question rather than an answer. 푅푒푑 Γ ⊢ 푐 = 푐′ As an example, we can write definitions for the streams Induction, coinduction, and principles: evens (푥 , 푥 ,... ) = 푥 , 푥 , 푥 ,... odds (푥 , 푥 ,... ) = 푥 , 푥 , 푥 ,... 0 1 0 2 4 0 1 1 3 5 Γ, 푥 : 퐴 ⊢ ⟨푥||푒⟩ = ⟨푥||푒′⟩ Γ, 훼 ÷ 퐴 ⊢ ⟨푣||훼⟩ = ⟨푣 ′||훼⟩ ( )( ) 휎휇˜ 휎휇 merge 푥0, 푥1,... 푦0,푦1,... = 푥0,푦0, 푥1,푦1,... Γ ⊢ 푒 = 푒′ ÷ 퐴 Γ ⊢ 푣 = 푣 ′ : 퐴 using pairs and the coeliminator above as follows: Γ, 푥 : 퐴, 훽 ÷ 퐵 ⊢ Ψ(푥 · 훽/훼) 휔→ evens := 휆푠.휇훾.⟨푠||corec훾 as { head 훼 → head 훼 Γ, 훼 ÷ 퐴 → 퐵 ⊢ Ψ(훼) | tail → 훽. tail(tail 훽)}⟩ Γ ⊢ Ψ(zero/푥) Γ, 푥 : nat, Ψ(푥) ⊢ Ψ(succ 푥/푥) 휔nat odds := 휆푠.휇훾.⟨푠||corec훾 as { head 훼 → tail(head 훼) Γ, 푥 : nat ⊢ Ψ(푥) | tail → 훽. tail(tail 훽)}⟩ Γ, 훽÷퐴 ⊢ Ψ(head 훽/훼) Γ, 훼÷ strm 퐴, Ψ(훼) ⊢ Ψ(tail 훼/훼) 휔strm merge := 휆푠.휆푠′.휇훾.⟨(푠, 푠′)||corec훾{ head 훼→휇˜(푠, ).⟨푠|| head 훼⟩ Γ, 훼 ÷ strm 퐴 ⊢ Ψ(훼) | tail →훾.휇˜(푠, 푠′).⟨(푠′, tail푠)||훾⟩}⟩ Rules of properties: Ax Coher Γ, Φ ⊢ Φ Γ, succ푉 = zero : nat ⊢ Φ 6 Syntactic (Co)Inductive Reasoning ′ Γ, Φ ⊢ Φ Γ ⊢ Φ′ ⇒ ΦΓ ⊢ Φ′ We have examined how to define (co)recursive programs and IntroH Lemm Γ ⊢ Φ′ ⇒ Φ Γ ⊢ Φ compute their results, but how can we about when ex- ′ pressions are equivalent? It’s unsatisfactory to only consider Γ, 푥 : 퐴 ⊢ Φ Γ ⊢ ∀푥:퐴.ΦΓ ⊢ 푉 = 푉 : 퐴 IntroL ′ SubstL two expressions equal when they reduce to some common Γ ⊢ ∀푥:퐴.Φ Γ ⊢ Φ[푉 /푥 = 푉 /푥] reduct; that misses out on far too many equalities. For exam- Γ, 훼 ÷ 퐴 ⊢ Φ Γ ⊢ ∀훼÷퐴.ΦΓ ⊢ 퐸 = 퐸′ ÷ 퐴 IntroR SubstR ple, it is easy to show by reduction that plus zero 푥 ↦→→ 푥 be- Γ ⊢ ∀훼÷퐴.Φ Γ ⊢ Φ[퐸/훼 = 퐸′/훼] cause plus was defined by recursion on its first , but Figure 11. Equational theory of (co)induction in the abstract 푥 plus zero doesn’t reduce at all, even though it is nonethe- machine. less equivalent to zero in any context. Likewise, evens alt and repeat zero are both equivalent to the same stream is productive on 훼 because it immediately returns a value to (0, 0, 0,... ), but how do we prove it? To answer these ques- 훼 on both side of its equality. tions, we develop a syntactic equational theory with notions The general rules for properties formalize their intuitive of induction and coinduction dual to one another. meaning above in the equational theory. Ax says we can con- clude assumptions are true, while Coher says zero = succ푉 6.1 Equational theory of the abstract machine is an incoherent assumption. IntroH and Lemm introduce The equational theory for the abstract machine is given in an assumption or eliminate an assumption by proving the fig. 11. All judgments have the form Γ ⊢ Φ, where Γ is the required property as a side lemma. Quantifiers can be intro- assumptions and Φ is the property being proved. The main duced when their property holds on a generic (co)variable properties are the base equalities for commands (푐 =푐 ′) and (IntroL and IntroR), and eliminated by substituting any equal (co)terms of some type 퐴 (푣 = 푣 ′ : 퐴 and 푒 = 푒 ′ ÷ 퐴). In addi- (co)value for the bound (co)variable (SubstL and SubstR). tion, properties may universally quantify over (co)variables The notation Φ[푉 /푥 = 푉 ′/푥] (and likewise Φ[퐸/훼 = 퐸′/훼]) (∀푥:퐴.Φ and ∀훼÷퐴.Φ), or depend on the truth of another means to perform the substitution [푉 /푥] on the left-hand property (Φ′ ⇒ Φ). These latter three forms of properties side of all equations in Φ and [푉 ′/푥] on the right-hand sides. will turn out to be essential for proving equalities that re- The Red rule states that reduction steps of the operational quire a more general (co)inductive hypothesis. (Co)-inductive semantics count as equalities, and the reflexivity, symme- hypotheses can be stored in the environment as Γ, Φ. Addi- try, transitivity, and compatibility rules are standard for an tionally, we have two special cases for properties. A property equational theory. The 휎휇˜ and 휎휇 rules establish a logical Ψ(푥) is strict on 푥 because it uses 푥 directly with some co- equivalence between equality of commands versus equality value on both sides of its equality. Dually, a property Ψ(훼) of (co)terms. They say that any two terms (dually coterms) PPDP ’20, September 8–10, 2020, Bologna, Italy P. Downen and Z.M. Ariola are equal when they form equal commands with a generic any generic stream 푥 gives the same response when its pro- covariable (dually variable). These rules allow us to jection is broken down and rebuilt from scratch from the derive the extensionality 휂 for 휇- and 휇˜-abstractions base case (head 훼) up. Now, consider how to prove 훿strm. 훼÷ 퐴 휎휇 in the 휆휇휇˜-calculus for any term Γ ⊢ 푣 : 퐴 or coterm Γ ⊢ 푒 ÷퐴: After supposing a generic observation strm ( ) inside the for 푥 (IntroL, SubstL, ReflR), it suffices to show: (휂 ) Γ ⊢ 휇훼.⟨푣||훼⟩ = 푣 : 퐴 (휂 ) Γ ⊢ 휇푥.˜ ⟨푥||푒⟩ = 푒 ÷ 퐴 휇 휇˜ 훼÷ strm 퐴 ⊢ ∀푥: strm 퐴. 휔 Similarly, the → rule expresses a form of extensionality ⟨coiter{head 훼 → head 훼 | tail → 훽. tail 훽} with 푥||훼⟩ = ⟨푥||훼⟩ for functions in terms of call stacks—it is sufficient to test a Notice that this property is productive on 훼, so we may ap- productive property on a generic call stack—that can derive ply 휔strm. The remaining calculations for the two premises the more usual 휂 for functions in 휆휇휇˜: of 휔strm continue as follows, where we make use of the (휂→) Γ ⊢ 휆푥.휇훼.⟨푉 ||푥 · 훼⟩ = 푉 : 퐴 → 퐵 shorthand cdeep := {head 훼 → head 훼 | tail → 훽. tail 훽}: The restriction of 휔→ to productive properties corresponds • For head 훽/훼, we have the calculation: to the usual restriction of the 휂 axiom in the call-by-value ⟨coiter cdeep with 푥|| head 훽⟩ ↦→ ⟨푥|| head 훽⟩(훽head) 휆-calculus: 휆푥.푀 푥 ≠ 푀 when 푀 is not equal to a value. 훽 훼 퐶퐼퐻 This prevents equalities like 휆 .휇 .⟨zero ||훼⟩ = 휇 .⟨zero ||훼⟩, • For tail / , assume the coinductive hypothesis ( ) ∀푥: strm 퐴.⟨coiter cdeep with 푥||훽⟩ = ⟨푥||훽⟩, so we have that are incoherent under call-by-value evaluation. For ex- the following calculation in call-by-value and -name: ample, with 푒1 := 휇˜ .⟨succ zero ||훼⟩, we have on the one ⟨coiter cdeep with 푥|| tail 훽⟩ hand ⟨휆 .휇 .⟨zero ||훼⟩||푒1⟩ ↦→→⟨succ zero ||훼⟩, whereas on the other hand ⟨휇 .⟨zero ||훼⟩||푒1⟩ ↦→→⟨zero ||훼⟩. ↦→ ⟨휇훽.⟨푥|| tail 훽⟩||휇푦.˜ ⟨coiter cdeep with푦||훽⟩⟩(훽tail) The most interesting rules of the equation theory are the = ⟨휇훽.⟨푥|| tail 훽⟩||휇푦.˜ ⟨푦||훽⟩⟩(퐶퐼퐻 [푦/푥]) 휔 ones for (co)induction. The nat rule corresponds to the fol- = ⟨휇훽.⟨푥|| tail 훽⟩||훽⟩(휂 ) lowing weak induction property on the natural numbers, and 휇˜ 휔strm corresponds to the dual weak coinduction property: ↦→ ⟨푥|| tail 훽⟩(휇) 푥 (휔nat) Ψ(zero) ⇒ (∀푥:nat.Ψ(푥)⇒Ψ(succ 푥)) ⇒ (∀푥:nat.Ψ(푥)) Note that the generalization over in the coinductive hypothesis is essential for instantiating 푥 (via SubstL) (휔strm) (∀훽÷퐴.Ψ(head 훽)) ⇒ (∀훼÷ strm 퐴.Ψ(훼)⇒Ψ(tail 훼)) with the bound 푦 newly introduced by 훽tail reduction. ⇒ (∀ ÷ ( )) 훼 strm 퐴.Ψ 훼 Analogously to the “deep” extensionality properties 훿nat Notice that both of these rules for induction and coinduction and 훿strm of (co)iteration, we can also derive the following are restricted to strict and productive properties, respectively. “shallow” extensionality properties 휂nat and 휂strm for per- Reminiscent of [34], this restriction prevents the same kinds forming (co)case analysis on the structure of a numeric value of incoherence issues as the above one for functions, which or a stream projection: we will return to in more detail in section 6.3. For now, the  zero → zero  (휂 ) ∀훼÷nat. case with 훼 = 훼 ÷ nat primary fact about this (co)inductive equational theory is nat succ푦 → succ푦 that it is coherent for either evaluation strategy. head 훼 → head 훼 (휂strm) ∀푥: strm 퐴. cocase with 푥 = 푥 : strm 퐴 Definition 1 (Coherence). An equational theory for the tail 훽 → tail 훽 (co)recursive abstract machine is coherent if 훼 ÷ nat ⊢ 푐 = 푐 1 2 6.2 Equational theory of the 휆휇휇˜-calculus implies either: Instead of reasoning in the lower-level language of the ab- 1. 푐푖 ↦→→⟨zero ||훼⟩ for both 푖 = 1, 2, or stract machine, we can also reason directly in the higher- 2. 푐푖 ↦→→⟨succ푉푖 ||훼⟩ for some 푉푖 and both 푖 = 1, 2. level language of 휆휇휇˜ using the equational theory given in 휆 Theorem 7. The equational theory in fig. 11 is coherent for fig. 12. This theory is closer to the -calculus. For example 휂 휔→ both call-by-value and call-by-name evaluation. the familiar axiom can be proved from : (휂 ) Γ ⊢ 휆푥.푉 푥 = 푉 : 퐴 → 퐵 To better understand (co)induction, 휔nat and 휔strm prove → the following properties about (co)iteration: The two theories correspond to one another, by pointwise zero → zero  extending the translation of 휆휇휇˜ over Φ and Γ. (훿nat) ∀훼÷nat. iter with 훼 = 훼 ÷ nat succ → 푦. succ푦 Theorem 8 (Soundness & Completeness). Γ ⊢ Φ iff Γ ⊢ Φ . J K J K head 훼 → head 훼  퐴 (훿strm) ∀푥: strm 퐴. coiter with 푥 = 푥 : strm 퐴 For example, we can prove evens alt = repeat zero : strm . tail → 훽. tail 훽 By applying 휎휇, it suffices to show that Intuitively, these are deep extensionality axioms for the re- 훼 ÷ strm nat ⊢ ⟨evens alt||훼⟩ = ⟨repeat zero||훼⟩ cursor and corecursor. Any generic observer 훼 cannot tell the difference if a natural number is first broken downand Both sides can reduce to a productive property on 훼 (that rebuilt from scratch from the base case (zero) up. Likewise, is to say, ⟨evens alt||훼⟩ ↦→→⟨evensalt ||훼⟩ for a closed value A Computational Understanding of Classical (Co)Recursion PPDP ’20, September 8–10, 2020, Bologna, Italy

Properties (Φ), strict (Ψ(푥)) and productive (Ψ(훼)) properties, hy- Γ ⊢ Φ[zero/푥] Γ, 푥 : nat, Φ ⊢ Φ[succ 푥/푥] pothesis (휃), environments (Γ), and judgments: 휎nat Γ, 푥 : nat ⊢ Φ Φ ::= 퐽 = 퐽 ′ | 푀 = 푀 ′: 퐴 |푄 =푄 ′÷ 퐴 | ∀푥:퐴.Φ | ∀훼÷퐴.Φ | Φ′⇒ Φ Γ, 훽 ÷ 퐴 ⊢ Φ[⟨head 푀||훽⟩/⟨푀||훼⟩] Ψ(푥) ::= 퐸[푥] = 퐸′[푥] | 퐸[푥] = 퐸′[푥]: 퐴 | ∀푦:퐴.Ψ(푥) | ∀훼÷퐴.Ψ(푥) Γ, 훼 ÷ strm 퐴, Φ ⊢ Φ[⟨tail 푀||훼⟩/⟨푀||훼⟩] Ψ(훼) ::= ⟨푉 ||훼⟩ = ⟨푉 ′||훼⟩ | ∀푥:퐴.Ψ(훼) | ∀훽÷퐴.Ψ(훼) 휎strm Γ, 훼 ÷ strm 퐴 ⊢ Φ Γ ::= • | Γ, 푥 : 퐴 | Γ, 훼 ÷ 퐴 | Γ, Φ Judge ::= Γ ⊢ Φ Figure 14. Strong (co)induction in 휆휇휇˜. Equality of computation (plus rules for reflexivity, symmetry, tran- sitivity, and compatibility of equality): induction and coinduction safe? The rules for strong (co)- ′ ′ Γ ⊢ 퐽 퐽 → 퐽 Γ ⊢ 푀 : 퐴 푀 → 푀 ′ Γ ⊢푄 ÷ 퐴 푄 →푄 induction (휎nat and 휎strm) are given for the abstract ma- Red Red Red Γ ⊢ 퐽 = 퐽 ′ Γ ⊢ 푀 = 푀 ′ : 퐴 Γ ⊢ 푄 = 푄 ′ ÷ 퐴 chine (fig. 13) and the 휆휇휇˜-calculus (fig. 14), which generalize Induction, coinduction, and extensionality principles: the weaker rules (휔nat and 휔strm) to any property, not just Γ, 훼÷퐴 ⊢ ⟨푀||훼⟩ = ⟨푀 ′||훼⟩ Γ, 푥:퐴 ⊢ ⟨푥||푄⟩ = ⟨푥||푄 ′⟩ strict or productive ones. As it turns out, unlike the weaker 휎휇 휎휇˜ Γ ⊢ 푀 = 푀 ′ : 퐴 Γ ⊢ 푄 = 푄 ′ ÷ 퐴 forms, strong induction and coinduction are only coherent under certain evaluation strategies. Γ, 푥 : 퐴 ⊢ 푉 푥 = 푉 ′ 푥 : 퐵 휔→ Γ ⊢ 푉 = 푉 ′ : 퐴 → 퐵 Theorem 9. 1. The equational theory in fig. 11 extended with 휎nat is coherent for call-by-value evaluation. Γ ⊢ Ψ(zero/푥) Γ, 푥 : nat, Ψ(푥) ⊢ Ψ(succ 푥/푥) 휔nat 2. The equational theory in fig. 11 extended with 휎strm is Γ, 푥 : nat ⊢ Ψ(푥) coherent for call-by-name evaluation. Γ, 훽 ÷ 퐴 ⊢ Ψ(⟨head 푀||훽⟩/⟨푀||훼⟩) To see where the extensions could be incoherent, notice Γ, 훼 ÷ strm 퐴, Ψ(훼) ⊢ Ψ(⟨tail 푀||훼⟩/⟨푀||훼⟩) 휔strm that the 휎nat rule proves this (non-푥-strict) property: Γ, 훼 ÷ strm 퐴 ⊢ Ψ(훼) 훼 ÷ ⊢ ∀푥 . Plus the same rules of properties as fig. 11. nat :nat ⟨푥|| case{zero → zero | succ → zero} with 훼⟩ = ⟨zero ||훼⟩ Figure 12. Equational theory of (co)induction in 휆휇휇˜. Call-by-name allows for the value 휇 .⟨succ zero ||훼⟩ to be Γ ⊢ Φ[zero/푥] Γ, 푥 : nat, Φ ⊢ Φ[succ 푥/푥] substituted for 푥 in this equation, leading to the incoher- 휎nat Γ, 푥 : nat ⊢ Φ ent equality 훼÷ nat ⊢ ⟨succ zero ||훼⟩=⟨zero ||훼⟩ contradicting theorem7. Dually, 휎strm proves (the non-훼-productive): Γ, 훽 ÷ 퐴 ⊢ Φ[head 훽/훼] Γ, 훼 ÷ strm 퐴, Φ ⊢ Φ[tail 훼/훼] 휎strm Γ, 훼 ÷ strm 퐴 ⊢ Φ 훼 ÷ nat ⊢ ∀훽÷ strm 퐴. 훼 훼 훽 훼 Figure 13. Strong (co)induction in the abstract machine. ⟨cocase{head → | tail → } with zero || ⟩ = ⟨zero || ⟩ and yet call-by-value allows the covalue 휇˜ .⟨succ zero ||훼⟩ to 훼 훼 be substituted for 훽, leading to the same incoherent equality evensalt and likewise ⟨repeat zero || ⟩ ↦→ ⟨repeatzero|| ⟩), so we can apply 휔nat to this reduced equality. The remaining contradicting theorem7. calculations for the two premises of 휔nat are as follows: In contrast to 휔nat, 휎nat is general enough to let us derive the traditional notion of strong induction on the natural • For head 훽/훼, we have the calculation: numbers. First, define the ordering relation on numbers in terms of the following equality: ⟨evensalt || head 훽⟩ ↦→→⟨alt|| head 훽⟩ 훽 훽 ↦→ ⟨zero || ⟩ ← ⟨repeatzero|| head ⟩ 푀 ≤ 푁 : nat := minus 푀 푁 = zero : nat [ • For tail 훽/훼, assume the coinductive hypothesis (퐶퐼퐻) We then write ∀푥≤푀:nat.Φ as shorthand for the property 훽 훽 ∀푥 . 푥 ≤ 푀 ⇒ 휎 ⟨evensalt || ⟩ = ⟨repeatzero|| ⟩, so we have the following :nat : nat Φ. Applying nat to this gives: calculation in both call-by-value and call-by-name: Γ ⊢ ∀푦≤zero:nat.ΦΓ, 푥: nat, ∀푦≤푥:nat.Φ ⊢ ∀푦≤ succ 푥:nat.Φ 휎nat Γ, 푥: nat ⊢ ∀푦≤푥:nat.Φ ⟨evensalt || tail 훽⟩ ↦→→⟨evenstail(tail alt) ||훽⟩(evens) 푦 . 푦 = ⟨evensalt ||훽⟩(alt) Since ∀ ≤zero:nat = zero : nat is derivable (by definition 푥 . 푥 푥 휎 = ⟨repeat ||훽⟩(퐶퐼퐻) of ≤) as well as ∀ :nat ≤ : nat (by induction with nat), zero we can specialize the above application to derive the follow- ←← ⟨repeatzero|| tail 훽⟩(repeat) [ ing simpler statement of strong induction on the naturals: 6.3 Strong (co)induction Γ ⊢ Φ[zero/푥] Γ, 푥: nat, ∀푦≤푥:nat.Φ ⊢ Φ[succ 푥/푥] ⊢ The form of (co)induction we have considered so far is weak, Γ, 푥: nat Φ and necessarily so since in some cases a stronger rule would As with induction on the natural numbers, we can derive be incoherent. But this raises the question: when is strong the dual notion of strong coinduction on infinite streams. PPDP ’20, September 8–10, 2020, Bologna, Italy P. Downen and Z.M. Ariola

First, define the ordering relation on stream projections as: which proceeds by the following calculation: 푄 ≤ 푅 ÷ strm 퐴 := depth 푄 ≤ depth 푅 : nat ⟨tail(tail(merge (evens 푠)(odds 푠)))||훼⟩ where depth 푄 computes the depth of any stream projection = ⟨tail(merge (odds 푠)(tail(evens 푠)))||훼⟩(merge) 푄, effectively converting tail푛 (head 훼) to succ푛 zero: = ⟨merge (tail(evens 푠))(tail(odds 푠))||훼⟩(merge) depth 푄 := 휇훼.⟨count||coiter푄 as{head → head 훼 | tail →훽. tail 훽}⟩ = ⟨merge (evens(tail(tail푠)))(odds(tail(tail푠)))||훼⟩(evens, odds) As before, we write the quantification ∀훼≤푄÷ strm 퐴.Φ as = ⟨tail(tail푠)||훼⟩(퐶퐼퐻 [tail(tail푠)/푠]) shorthand for ∀훼÷ strm 퐴. 훼 ≤ 푄 ÷ strm 퐴 ⇒ Φ. Applying 휎 The traditional principle of bisimulation on streams is also strm to this property gives: subsumed by the strong coinduction rule 휎strm, written as Γ, 훿 ÷ 퐴 ⊢ ∀훽≤head 훿÷strm 퐴.Φ 퐴 the following property BisimΦ, where the simulation relation Γ, 훼÷strm 퐴, ∀훽≤훼÷strm 퐴.Φ ⊢ ∀훽≤tail 훼÷strm 퐴.Φ is represented by Φ referring to two streams named 푠 and 푠 ′: Γ, 훼 ÷ strm 퐴 ⊢ ∀훽≤훼÷ strm 퐴.Φ 퐴 푠, 푠 ′ 퐴. 푠 푠 ′ 퐴 BisimΦ := (∀ : strm Φ ⇒ head = head : ) Analogous to strong induction on the naturals, we can use ⇒ (∀푠, 푠 ′: strm 퐴.Φ ⇒ Φ[tail푠/푠, tail푠 ′/푠 ′]) this application to derive the following simpler statement of ⇒ (∀푠, 푠 ′: strm 퐴.Φ ⇒ 푠 = 푠 ′ : strm 퐴) strong coinduction on streams: 푠, 푠 ′ 퐴. Γ, 훿÷퐴 ⊢ Φ[head 훿/훼] Where we use the shorthand ∀ : strm Φ to stand for mul- tiple quantifications of the same type ∀푠: strm 퐴.∀푠 ′: strm 퐴.Φ. Γ, 훼÷strm 퐴, ∀훽≤훼÷strm 퐴.Φ[훽/훼] ⊢ Φ[tail 훼/훼] The two assumptions confirm that Φ is a valid bisimulation Γ, 훼 ÷ strm 퐴 ⊢ Φ relation: Φ only relates streams with equal heads, and is 퐴 From this, We can derive the following special case of strong closed under tail projection. BisimΦ is derivable from strong coinduction, where we must show the first 푛 + 1 base cases coinduction in the 휆휇휇˜ equational theory. (for head 훽, tail(head 훽),...tail푛 (head 훽)) directly, and then take the 푛 + 1푡ℎ tail projection in the coinductive case: 7 Related Work Γ, 훽 ÷ 퐴 ⊢ Φ[head 훽/훼] ... Γ, 훽 ÷ 퐴 ⊢ Φ[tail푛 (head 훽)/훼] Our focus here primarily on theoretical foundations, rather Γ, 훼 ÷ strm 퐴, Φ ⊢ Φ[tail푛+1 훼/훼] than applications, of corecursion and coinduction. In particu- lar, this work serves as a foundation for coinduction based on Γ, 훼 ÷ strm 퐴 ⊢ Φ codata as found in practical languages like Agda, which sup- For example, the corresponding principle in 휆휇휇˜ can prove ports copatterns [2] on coinductively-defined types. For an that ∀푠:strm 퐴. merge (evens 푠)(odds 푠) = 푠 : strm 퐴 by step- introduction to related ideas on computational corecursion ping by 2. It suffices to show (via IntroR, SubstR, 휎휇) that based on more practical examples in programming, see [15]. 훼 ÷ strm 퐴 ⊢ ∀푠:strm 퐴.⟨merge (evens 푠)(odds 푠)||훼⟩ = ⟨푠||훼⟩ The corecursor presented here is a computational interpre- tation of the categorical model of corecursion in a coalgebra which follows from the strong coinduction principle above, [17]. A (weak) coalgebra for a functor 퐹 is defined by a mor- derived from 휎strm: phism 훼 : 퐴 → 퐹 (퐴) for some 퐴.A corecursive coalgebra 푀 훽 푀 훼 • For the first base case with ⟨head || ⟩/⟨ || ⟩, we extends this idea, by commuting with other morphisms of the have the following calculation from the definition of form 푋 → 퐹 (퐴+푋). Intuitively, the option 퐴+푋 in the result merge and evens for a generic 푠 (IntroL): corresponds to the multiple outputs in the corecursor pre- ⟨head(merge (evens 푠)(odds 푠))||훽⟩ = ⟨head(evens 푠)||훽⟩(merge) sented here. Note that we interpret the corecursive 퐴 + 푋 as = ⟨head푠||훽⟩(evens) multiple continuations, rather than a sum type, which maps • For the second base case where ⟨head(tail 푀)||훽⟩/⟨푀||훼⟩, more closely to lower-level implementations. This gives im- we have the following calculation for a generic푠 (IntroL): proved efficiency of corecursion over coiteration with sum types in call-by-value (recall section 4.2). ⟨head(tail(merge (evens 푠)(odds 푠)))||훽⟩ The coiterator, which we define as the restriction of the co- = ⟨head(merge (odds 푠)(tail(evens 푠)))||훽⟩(merge) recursor to never short-cut corecursion, corresponds exactly = ⟨head(odds 푠)||훽⟩(merge) to the Harper’s [23] strgen. In this sense, the corecursor is = ⟨head(tail푠)||훽⟩(odds) a conservative extension of the purely functional coiterator. Coiteration with control operators is considered in [5], which • For the coinductive step, we may use the hypothesis gives a call-by-name CPS translation for a stream coiterator ∀푠: strm 퐴.⟨merge (evens 푠)(odds 푠)||훼⟩ = ⟨푠||훼⟩ and primitive operation for scons. Here, the use of an ab- to show the same property after 2 tail projections on stract machine serves a similar role as CPS—making explicit a generic 푠 : strm 퐴, information- and control-flow—but allows us to use the same translation for both call-by-value and -name. An alternative 푠 푠 훼 푠 훼 ⟨tail(tail(merge (evens )(odds )))|| ⟩ = ⟨tail(tail )|| ⟩ approach to (co)recursive combinators is sized types [1, 24], A Computational Understanding of Classical (Co)Recursion PPDP ’20, September 8–10, 2020, Bologna, Italy which give the programmer control over recursion while still by (co)data types whose duality is made apparent in their ensuring termination, and have been used for both purely implementation in an abstract machine. The (co)inductive functional [3] and classical [13] coinductive types. principles are derived from the definition of types in terms Our investigation on evaluation strategy showed the (dual) of construction or destruction, using control flow instead of impact of call-by-value versus call-by-name evaluation [7, bisimulation to guide the coinductive hypothesis. In the end, 38] on the efficiency and strength of (co)induction. We show the logical dualities in computation—between data and co- how call-by-name evaluation is necessary for strong co- data; information flow and control flow—provide a unified induction in the presence of effects, dual to the fact that call- framework for using and reasoning with (co)inductive types. by-value evaluation is necessary for strong induction. We believe that this connection also holds for efficiency and op- Acknowledgments timization, as well. For example, previous work has showed This work is supported by the National Science Foundation that for function types—which are a form of non-corecursive under Grant No. 1719158. codata type—optimizations of function arity are improved by call-by-name evaluation [12, 14]. Though counterintuitive, the improvements to arity are owed to the stronger equa- tional theory (specifically, the 휂 law of the 휆-calculus) which [1] Andreas Abel. 2006. A Polymorphic Lambda Calculus with Sized Higher- Order Types. Ph.D. Thesis. Ludwig-Maximilians-Universität München. is possible by call-by-name evaluation. We speculate there [2] Andreas Abel, Brigitte Pientka, David Thibodeau, and Anton Setzer. may be similar optimizations for corecursion on coinductive 2013. Copatterns: Programming Infinite Structures by Observations. types made possible by a strong call-by-name theory. In Proceedings of the 40th Annual ACM SIGPLAN-SIGACT Symposium In contrast to having a monolithic evaluation strategy, an- on Principles of Programming Languages (Rome, Italy) (POPL ’13). ACM, other approach is use a hybrid evaluation strategy as done by New York, NY, USA, 27–38. https://doi.org/10.1145/2429069.2429075 [3] Andreas M. Abel and Brigitte Pientka. 2013. Wellfounded Recursion call-by-push-value [29] or polarized languages [31, 39]. With with Copatterns: A Unified Approach to Termination and Productivity. a hybrid approach, we could define one language which has In Proceedings of the 18th ACM SIGPLAN International Conference both efficient (co)recursors and strong (co)inductive princi- on Functional Programming (Boston, Massachusetts, USA) (ICFP ’13). ples. Polarity also allows for incorporating other evaluation ACM, New York, NY, USA, 185–196. https://doi.org/10.1145/2500365. strategies, such as call-by-need which shares the work of 2500591 [4] Zena M. Ariola, Aaron Bohannon, and Amr Sabry. 2009. Sequent computations, while keeping the strong equational theory Calculi and Abstract Machines. ACM Transactions on Programming [10, 30]. We leave to future work an investigation on the Languages and Systems 31, 4, Article 13 (May 2009), 48 pages. https: polarized version of the (co)inductive calculus and abstract //doi.org/10.1145/1516507.1516508 machine presented here. [5] Gilles Barthe and Tarmo Uustalu. 2002. CPS Translating Inductive and Our notions of strong (co)induction—which are founded Coinductive Types. In Proceedings of the 2002 ACM SIGPLAN Work- shop on Partial Evaluation and Semantics-Based Program Manipulation on dual forms of data flow and control flow—allow for lo- (Portland, Oregon) (PEPM ’02). Association for Computing Machinery, cal reasoning about valid applications of the (co)inductive New York, NY, USA, 131–142. https://doi.org/10.1145/503032.503043 hypothesis, which leads to a compositional development of [6] Alberto Carraro, Thomas Ehrhard, and Antonino Salibra. 2012. The (co)inductive proofs. Similarly, Paco [25] aims to aid the de- Stack Calculus. In Proceedings Seventh Workshop on Logical and Se- velopment of coinductive proofs through both compositional- mantic Frameworks, with Applications (Rio de Janeiro, Brazil) (LSFA 2012). 93–108. https://doi.org/10.4204/EPTCS.113.10 ity (local, not global, correctness criteria) and incrementality [7] Pierre-Louis Curien and Hugo Herbelin. 2000. The Duality of Computa- (new knowledge may be accumulated as the proof is devel- tion. In Proceedings of the Fifth ACM SIGPLAN International Conference oped). We showed how the strong version our equational the- on Functional Programming (ICFP ’00). ACM, New York, NY, USA, ory encompasses well-known principles of strong induction 233–243. https://doi.org/10.1145/351240.351262 and bisimulation of corecursive processes. We conjecture [8] Paul Downen and Zena M. Ariola. 2014. Compositional Semantics for Composable Continuations: From Abortive to Delimited Control. that Paco’s coinductive principles can also be encoded as an In Proceedings of the 19th ACM SIGPLAN International Conference on application of strong coinduction—giving a computational Functional Programming (Gothenburg, Sweden) (ICFP ’14). ACM, New model for its proofs—where accumulated knowledge may be York, NY, USA, 109–122. https://doi.org/10.1145/2628136.2628147 represented as the accumulator of a corecursive process. [9] Paul Downen and Zena M. Ariola. 2014. The Duality of Construction. In Programming Languages and Systems: 23rd European Symposium on Programming, ESOP 2014, Held as Part of the European Joint Confer- 8 Conclusion ences on Theory and Practice of Software, ETAPS 2014. Lecture Notes in Computer Science, Vol. 8410. Springer Berlin Heidelberg, 249–269. This paper defines a language for providing a computational https://doi.org/10.1007/978-3-642-54833-8_14 foundation of (co)recursive programming and (co)inductive [10] Paul Downen and Zena M. Ariola. 2018. Beyond Polarity: Towards a reasoning. The impact of evaluation strategy is also illus- Multi-Discipline Intermediate Language with Sharing. In 27th EACSL Annual Conference on Computer Science Logic, CSL 2018, September 4-7, trated, where call-by-value and -name have (opposite) ad- 2018, Birmingham, UK (LIPIcs, Vol. 119). Schloss Dagstuhl - Leibniz- vantages for the efficiency of (co)recursion and strength Zentrum für Informatik, 21:1–21:23. https://doi.org/10.4230/LIPIcs. of (co)induction. These (co)recursion schemes are captured CSL.2018.21 PPDP ’20, September 8–10, 2020, Bologna, Italy P. Downen and Z.M. Ariola

[11] Paul Downen and Zena M. Ariola. 2018. A Tutorial on Computational [25] Chung-Kil Hur, Georg Neis, Derek Dreyer, and Viktor Vafeiadis. 2013. Classical Logic and the Sequent Calculus. Journal of Functional Pro- The Power of Parameterization in Coinductive Proof. In Proceedings gramming 28 (2018), e3. https://doi.org/10.1017/S0956796818000023 of the 40th Annual ACM SIGPLAN-SIGACT Symposium on Principles [12] Paul Downen, Zena M. Ariola, Simon Peyton Jones, and Richard A. of Programming Languages (Rome, Italy) (POPL ’13). Association for Eisenberg. 2020. Kinds Are Calling Conventions. Proceedings of the Computing Machinery, New York, NY, USA, 193–206. https://doi.org/ ACM on Programming Languages 4, ICFP, Article 104 (Aug. 2020), 10.1145/2429069.2429093 29 pages. https://doi.org/10.1145/3408986 [26] Philip Johnson-Freyd, Paul Downen, and Zena M. Ariola. 2016. First [13] Paul Downen, Philip Johnson-Freyd, and Zena M. Ariola. 2015. Struc- Class Call Stacks: Exploring Head Reduction. In Proceedings of the tures for Structural Recursion. In Proceedings of the 20th ACM SIG- Workshop on Continuations, WoC 2016, London, UK, April 12th 2015 PLAN International Conference on Functional Programming (Vancou- (EPTCS, Vol. 212). 18–35. https://doi.org/10.4204/EPTCS.212 ver, BC, Canada) (ICFP ’15). ACM, New York, NY, USA, 127–139. [27] Philip Johnson-Freyd, Paul Downen, and Zena M. Ariola. 2017. Call- https://doi.org/10.1145/2784731.2784762 by-name Extensionality and Confluence. Journal of Functional Pro- [14] Paul Downen, Zachary Sullivan, Zena M. Ariola, and Simon Peyton gramming 27 (2017), e12. https://doi.org/10.1017/S095679681700003X Jones. 2019. Making a faster Curry with extensional types. In Proceed- [28] Jean-Louis Krivine. 2007. A Call-By-Name Lambda-Calculus Machine. ings of the 12th ACM SIGPLAN International Symposium on Haskell, Higher-Order and Symbolic Computation 20, 3 (2007), 199–207. https: Haskell@ICFP 2019, Berlin, Germany, August 18-23, 2019. ACM, 58–70. //doi.org/10.1007/s10990-007-9018-9 https://doi.org/10.1145/3331545.3342594 [29] Paul Blain Levy. 2001. Call-By-Push-Value. Ph.D. Dissertation. Queen [15] Paul Downen, Zachary Sullivan, Zena M. Ariola, and Simon Peyton Mary and Westfield College, University of London. Jones. 2019. Codata in Action. In Programming Languages and Systems [30] Dylan McDermott and Alan Mycroft. 2019. Extended Call-by-Push- - 28th European Symposium on Programming, ESOP 2019, Held as Part Value: Reasoning About Effectful Programs and Evaluation Order. In of the European Joint Conferences on Theory and Practice of Software, Programming Languages and Systems - 28th European Symposium on ETAPS 2019 (Prague, Czech Republic) (ESOP ’19). Springer International Programming, ESOP 2019, Held as Part of the European Joint Confer- Publishing, Cham, 119–146. https://doi.org/10.1007/978-3-030-17184- ences on Theory and Practice of Software, ETAPS 2019, Prague, Czech 1_5 Republic, April 6-11, 2019, Proceedings (Lecture Notes in Computer Sci- [16] Gerhard Gentzen. 1935. Untersuchungen über das logische Schließen. ence, Vol. 11423). Springer, 235–262. https://doi.org/10.1007/978-3-030- I. Mathematische Zeitschrift 39, 1 (1935), 176–210. https://doi.org/10. 17184-1_9 1007/BF01201353 [31] Guillaume Munch-Maccagnoni. 2013. Syntax and Models of a non- [17] Herman Geuvers. 1992. Inductive and Coinductive types with Iteration Associative Composition of Programs and Proofs. Ph.D. Dissertation. and Recursion. In Proceedings of the 1992 Workshop on Types for Proofs Université Paris Diderot. and Programs, Bastad. 193–217. [32] Koji Nakazawa and Tomoharu Nagai. 2014. Reduction System for [18] Jeremy Gibbons and Graham Hutton. 2005. Proof Methods for Core- Extensional Lambda-mu Calculus.. In Rewriting and Typed Lambda cursive Programs. Fundamenta Informaticae 66 (04 2005), 353–366. Calculi (LNCS). 349–363. [19] Jean-Yves Girard. 1987. Linear logic. Theoretical Computer Science 50, [33] Michel Parigot. 1992. 휆휇-Calculus: An Algorithmic of 1 (1987), 1–101. https://doi.org/10.1016/0304-3975(87)90045-4 Classical . In Logic Programming and Automated [20] Kurt Gödel. 1980. On a hitherto unexploited extension of the finitary Reasoning: International Conference (St. Petersburg, Russia) (LPAR ’92). standpoint. Journal of 9, 2 (1980), 133–142. https: Springer Berlin Heidelberg, Berlin, Heidelberg, 190–201. https://doi. //doi.org/10.1007/BF00247744 org/10.1007/BFb0013061 [21] Mike Gordon. 2017. Corecursion and coinduction: what they are and [34] Pierre-Marie Pédrot and Nicolas Tabareau. 2017. An Effectful Way how they relate to recursion and induction. https://www.cl.cam.ac. to Eliminate Addiction to Dependence. In Logic in Computer Science uk/archive/mjcg/Blog/WhatToDo/Coinduction.pdf (LICS), 2017 32nd Annual ACM/IEEE Symposium on. Reykjavik, Iceland, [22] Tatsuya Hagino. 1987. A Typed Lambda Calculus With Categorical 12. https://doi.org/10.1109/LICS.2017.8005113 Type Constructors. In Category Theory and Computer Science (Edin- [35] Crole Roy. 2003. Coinduction and bisimilarity. In Oregon Programming burgh, U.K.). Springer Berlin Heidelberg, Berlin, Heidelberg, 140–157. Languages Summer School (OPLSS). https://doi.org/10.1007/3-540-18508-9_24 [36] Jan Rutten. 2019. The Method of Coalgebra: Exercises in coinduction. [23] Robert Harper. 2016. Practical Foundations for Programming Languages (Feb. 2019), 1–261. (2nd ed.). Cambridge University Press, USA. [37] Davide Sangiorgi. 2011. Introduction to Bisimulation and Coinduction. [24] John Hughes, Lars Pareto, and Amr Sabry. 1996. Proving the Cor- Cambridge University Press, New York, NY, USA. rectness of Reactive Systems Using Sized Types. In Proceedings of [38] Philip Wadler. 2003. Call-By-Value is Dual to Call-By-Name. In Proceed- the 23rd ACM SIGPLAN-SIGACT Symposium on Principles of Program- ings of the Eighth ACM SIGPLAN International Conference on Functional ming Languages (St. Petersburg Beach, Florida, USA) (POPL ’96). As- Programming (Uppsala, Sweden). ACM, New York, NY, USA, 189–201. sociation for Computing Machinery, New York, NY, USA, 410–423. https://doi.org/10.1145/944705.944723 https://doi.org/10.1145/237721.240882 [39] Noam Zeilberger. 2009. The Logical Basis of Evaluation Order and Pattern-Matching. Ph.D. Dissertation. Carnegie Mellon University.