Advertisement

Friends with Benefits

Implementing Corecursion in Foundational Proof Assistants
Conference paper
Part of the Lecture Notes in Computer Science book series (LNCS, volume 10201)

Abstract

We introduce AmiCo, a tool that extends a proof assistant, Isabelle/HOL, with flexible function definitions well beyond primitive corecursion. All definitions are certified by the assistant’s inference kernel to guard against inconsistencies. A central notion is that of friends: functions that preserve the productivity of their arguments and that are allowed in corecursive call contexts. As new friends are registered, corecursion benefits by becoming more expressive. We describe this process and its implementation, from the user’s specification to the synthesis of a higher-order definition to the registration of a friend. We show some substantial case studies where our approach makes a difference.

Keywords

Proof Obligation Proof Assistant Proof Method Uniqueness Principle Type Constructor 
These keywords were added by machine and not by the authors. This process is experimental and the keywords may be updated as the learning algorithm improves.

1 Introduction

Codatatypes and corecursion are emerging as a major methodology for programming with infinite objects. Unlike in traditional lazy functional programming, codatatypes support total (co)programming [1, 8, 30, 68], where the defined functions have a simple set-theoretic semantics and productivity is guaranteed. The proof assistants Agda [19], Coq [12], and Matita [7] have been supporting this methodology for years.

By contrast, proof assistants based on higher-order logic (HOL), such as HOL4 [64], HOL Light [32], and Isabelle/HOL [56], have traditionally provided only datatypes. Isabelle/HOL is the first of these systems to also offer codatatypes. It took two years, and about 24 000 lines of Standard ML, to move from an understanding of the mathematics [18, 67] to an implementation that automates the process of checking high-level user specifications and producing the necessary corecursion and coinduction theorems [16].

There are important differences between Isabelle/HOL and type theory systems such as Coq in the way they handle corecursion. Consider the codatatype of streams given by
where Open image in new window (written infix) is the constructor, and Open image in new window and Open image in new window are the head and tail selectors, respectively. In Coq, a definition such as
which introduces the function Open image in new window , is accepted after a syntactic check that detects the Open image in new window -guardedness of the corecursive call. In Isabelle, this check is replaced by a deeper analysis. The Open image in new window command [16] transforms a user specification into a blueprint object: the coalgebra Open image in new window . Then Open image in new window is defined as Open image in new window , where Open image in new window is the fixed primitive corecursive combinator for Open image in new window . Finally, the user specification is derived as a theorem from the definition and the characteristic equation of the corecursor.

Unlike in type theories, where (co)datatypes and (co)recursion are built-in, the HOL philosophy is to reduce every new construction to the core logic. This usually requires a lot of implementation work but guarantees that definitions introduce no inconsistencies. Since codatatypes and corecursion are derived concepts, there is no a priori restriction on the expressiveness of user specifications other than expressiveness of HOL itself.

Consider a variant of Open image in new window , where the function Open image in new window adds 1 to each element of a stream:
Coq’s syntactic check fails on Open image in new window . After all, Open image in new window could explore the tail of its argument before it produces a constructor, hence blocking productivity and leading to underspecification or inconsistency.
Isabelle’s bookkeeping allows for more nuances. Suppose Open image in new window has been defined as
When analyzing Open image in new window ’s specification, the Open image in new window command synthesizes its definition as a blueprint Open image in new window . This definition can then be proved to be friendly, hence acceptable in corecursive call contexts when defining other functions. Functions with friendly definitions are called friendly, or friends. These functions preserve productivity by consuming at most one constructor when producing one.

Our previous work [17] presented the category theory underlying friends, based on more expressive blueprints than the one shown above for primitive corecursion. We now introduce a tool, AmiCo, that automates the process of applying and incrementally improving corecursion.

To demonstrate AmiCo’s expressiveness and convenience, we used it to formalize eight case studies in Isabelle, featuring a variety of codatatypes and corecursion styles (Sect. 2). A few of these examples required ingenuity and suggest directions for future work. Most of the examples fall in the executable framework of Isabelle, which allows for code extraction to Haskell via Isabelle’s code generator. One of them pushes the boundary of executability, integrating friends in the quantitative world of probabilities.

At the low level, the corecursion state summarizes what the system knows at a given point, including the set of available friends and a corecursor up to friends (Sect. 3). Polymorphism complicates the picture, because some friends may be available only for specific instances of a polymorphic codatatype. To each corecursor corresponds a coinduction principle up to friends and a uniqueness theorem that can be used to reason about corecursive functions. All of the constructions and theorems are derived from first principles, without requiring new axioms or extensions of the logic. This foundational approach prevents the introduction of inconsistencies, such as those that have affected the termination and productivity checkers of Agda and Coq in recent years.

The user interacts with our tool via the following commands to the proof assistant (Sect. 4). The Open image in new window command defines a function Open image in new window by extracting a blueprint  Open image in new window from a user’s specification, defining Open image in new window using Open image in new window and a corecursor, and deriving the original specification from the characteristic property of the corecursor. Moreover, Open image in new window supports mixed recursion–corecursion specifications, exploiting proof assistant infrastructure for terminating (well-founded) recursion. Semantic proof obligations, notably termination, are either discharged automatically or presented to the user. Specifying the Open image in new window option to Open image in new window additionally registers Open image in new window as a friend, enriching the corecursor state. Another command, Open image in new window , registers existing functions as friendly. Friendliness amounts to the relational parametricity [60, 69] of a selected part of the definition [17], which in this paper we call a surface. The tool synthesizes the surface, and the parametricity proof is again either discharged automatically or presented to the user.

AmiCo is a significant piece of engineering, at about 7 000 lines of Standard ML code (Sect. 5). It subsumes a crude prototype [17] based on a shell script and template files that automated the corecursor derivation but left the blueprint and surface synthesis problems to the user. Our tool is available as part of the official Isabelle2016-1 release. The formalized examples and case studies are provided in an archive [14].

The contributions of this paper are the following:

More details, including thorough descriptions and proofs of correctness for the surface synthesis algorithm and the mixed recursion–corecursion pipeline, are included in a technical report [15]. Although our tool works for Isabelle, the same methodology is immediately applicable to any prover in the HOL family (including HOL4, HOL Light, HOL Zero [6], and HOL-Omega [34]), whose users represent about half of the proof assistant community. Moreover, a similar methodology is in principle applicable to provers based on type theory, such as Agda, Coq, and Matita (Sect. 6).

Conventions. We recall the syntax relevant for this paper, relying on the standard set-theoretic interpretation of HOL [27].

We fix infinite sets of type variables Open image in new window and term variables Open image in new window and a higher-order signature, consisting of a set of type constructors including Open image in new window and the binary constructors for functions ( Open image in new window ), products ( Open image in new window ), and sums (+). Types Open image in new window are defined using type variables and applying type constructors, normally written postfix. Isabelle /HOL supports Haskell-style type classes, with Open image in new window expressing class membership (e.g.,  Open image in new window ).

Moreover, we assume a set of polymorphic constants Open image in new window with declared types, including equality Open image in new window , left and right product projections Open image in new window and Open image in new window , and left and right sum embeddings Open image in new window and Open image in new window . Terms t are built from constants Open image in new window and variables x by means of typed Open image in new window -abstraction and application. Polymorphic constants and terms will be freely used in contexts that require a less general type.

2 Motivating Examples

We apply AmiCo to eight case studies to demonstrate its benefits—in particular, the flexibility that friends provide and reasoning by uniqueness (of solutions to corecursive equations). The first four examples demonstrate the flexibility that friends provide. The third one also features reasoning by uniqueness. The fourth example crucially relies on a form of nested corecursion where the operator under definition must be recognized as a friend. The fifth through seventh examples mix recursion with corecursion and discuss the associated proof techniques. The last example, about a probabilistic process calculus, takes our tool to its limits: We discuss how to support corecursion through monadic sequencing and mix unbounded recursion with corecursion. All eight formalizations are available online [14], together with our earlier stream examples [17].

Since all examples are taken from the literature, we focus on the formalization with AmiCo. No detailed understanding is needed to see that they fit within the friends framework. Background information can be found in the referenced works.

Remarkably, none of the eight examples work with Coq’s or Matita’s standard mechanisms. Sized types in Agda [4] can cope with the first six but fail on the last two: In one case a function must inspect an infinite list unboundedly deeply, and in the other case the codatatype cannot even be defined in Agda. The Dafny verifier, which also provides codatatypes [46], supports only the seventh case study.

2.1 Coinductive Languages

Rutten [62] views formal languages as infinite tries, i.e., prefix trees branching over the alphabet with boolean labels at the nodes indicating whether the path from the root denotes a word in the language. The type Open image in new window features corecursion through the right-hand side of the function arrow ( Open image in new window ).

Traytel [66] has formalized tries in Isabelle using a codatatype, defined regular operations on them as corecursive functions, and proved by coinduction that the defined operations form a Kleene algebra. Because Isabelle offered only primitive corecursion when this formalization was developed, the definition of concatenation, iteration, and shuffle product was tedious, spanning more than a hundred lines.

Corecursion up to friends eliminates this tedium. The following extract from an Isabelle formalization is all that is needed to define the main operations on languages:
Concatenation ( Open image in new window ) and shuffle product ( Open image in new window ) are corecursive up to alternation (+), and iteration ( Open image in new window ) is corecursive up to concatenation ( Open image in new window ). All four definitions use an alternative Open image in new window -based syntax for performing corecursion under the right-hand side of Open image in new window , instead of applying the functorial action Open image in new window (composition) associated with Open image in new window .

The Open image in new window command is provided by AmiCo, whereas Open image in new window and Open image in new window (Sect. 3.2) has been part of Isabelle since 2013. The Open image in new window option registers the defined functions as friends and automatically discharges the emerging proof obligations, which ensure that friends consume at most one constructor to produce one constructor.

Proving equalities on tries conveniently works by coinduction up to congruence (Sect. 3.7). Already before Open image in new window existence, Traytel was able to write automatic one-line proofs such as
The Open image in new window proof method [16] instantiates the bisimulation witness of the given coinduction rule before applying it backwards. Without Open image in new window , the rule +.coinduct of coinduction up to congruence had to be stated and proved manually, including the manual inductive definition of the congruence closure under +.

Overall, the usage of Open image in new window compressed Traytel’s development from 750 to 600 lines of Isabelle text. In Agda, Abel [3] has formalized Traytel’s work up to proving the recursion equation Open image in new window for iteration ( Open image in new window ) in 219 lines of Agda text, which correspond to 125 lines in our version. His definitions are as concise as ours, but his proofs require more manual steps.

2.2 Knuth–Morris–Pratt String Matching

Building on the trie view of formal languages, van Laarhoven [44] discovered a concise formulation of the Knuth–Morris–Pratt algorithm [41] for finding one string in another:

Here, we overload the stream constructor Open image in new window for finite lists; Open image in new window and Open image in new window are the selectors. In our context, Open image in new window is the most interesting definition because it corecurses through Open image in new window Since there is no constructor guard, Open image in new window would appear not to be productive. However, the constructor is merely hidden in Open image in new window and can be pulled out by unrolling the definition of Open image in new window as follows.

As the first step, we register Open image in new window defined by Open image in new window as a friend, using the Open image in new window command provided by our tool. The registration of an existing function as a friend requires us to supply an equation with a constructor-guarded right-hand side and to prove the equation and the parametricity of the destructor-free part of the right-hand side, called the surface (Sect. 3.4). Then the definition of Open image in new window corecurses through  Open image in new window Finally, we derive the original specification by unrolling the definition. We can use the derived specification in the proofs, because proofs in HOL do not depend on the actual definition (unlike in type theory).

2.3 The Stern–Brocot Tree

The next application involves infinite trees of rational numbers. It is based on Hinze’s work on the Stern–Brocot and Bird trees [33] and the Isabelle formalization by Gammie and Lochbihler [25]. It illustrates reasoning by uniqueness (Sect. 3.7).

The Stern–Brocot tree contains all the rational numbers in their lowest terms. It is an infinite binary tree Open image in new window of formal fractions Open image in new window Each node is labeled with the mediant of its rightmost and leftmost ancestors, where Open image in new window Gammie and Lochbihler define the tree via an iterative helper function.
Using AmiCo, we can directly formalize Hinze’s corecursive specification of the tree, where Open image in new window and Open image in new window The tree is corecursive up to the two friends Open image in new window and Open image in new window
Without the iterative detour, the proofs, too, become more direct as the statements need not be generalized for the iterative helper function. For example, Hinze relies on the uniqueness principle to show that a loopless linearization Open image in new window of the tree yields Dijkstra’s Open image in new window function [23] given bywhere all arithmetic operations are lifted to streams elementwise—e.g., Open image in new window zips two streams. We define Open image in new window and Open image in new window as follows. To avoid the mutual corecursion, we inline Open image in new window in Open image in new window for the definition with Open image in new window after having registered the arithmetic operations as friends:
Hinze proves that Open image in new window equals Open image in new window by showing that both satisfy the corecursion equation Open image in new window where Open image in new window This equation yields the loopless algorithm, because Open image in new window satisfies it as well, where Open image in new window is defined by

Our tool generates a proof rule for uniqueness of solutions to the recursion equation (Sect. 3.7). We conduct the equivalence proofs using this rule.

For another example, all rational numbers also occur in the Bird tree given by
It satisfies Open image in new window , where Open image in new window corecursively swaps all subtrees. Again, we prove this identity by showing that both sides satisfy the corecursion equation Open image in new window This equation does not correspond to any function defined with Open image in new window but we can derive its uniqueness principle using our proof method Open image in new window without defining the function. The Isabelle proof is quite concise:

No coinduction is needed: The identities are proved by expanding the definitions a finite number of times (once each here). We also show that Open image in new window by uniqueness, where Open image in new window swaps the subtrees only at levels of odd depth.

Gammie and Lochbihler manually derive each uniqueness rule using a separate coinduction proof. For Open image in new window alone, the proof requires 25 lines. With AmiCo’s Open image in new window proof method, such proofs are automatic.

2.4 Breadth-First Tree Labeling

Abel and Pientka [4] demonstrate the expressive power of sized types in Agda with the example of labeling the nodes of an infinite binary tree in breadth-first order, which they adapted from Jones and Gibbons [39]. The function Open image in new window takes a stream of streams of labels as input and labels the nodes at depth i according to a prefix of the ith input stream. It also outputs the streams of unused labels. Then Open image in new window ties the knot by feeding the unused labels back into Open image in new window
Because Open image in new window returns a pair, we define the two projections separately and derive the original specification for Open image in new window trivially from the definitions. One of the corecursive calls to Open image in new window occurs in the context of Open image in new window itself—it is “self-friendly” (Sect. 4.2).

For comparison, Abel’s and Pientka’s formalization in Agda is of similar size, but the user must provide some size hints for the corecursive calls.

2.5 Stream Processors

Stream processors are a standard example of mixed fixpoints:

When defining functions on these objects, we previously had to break them into a recursive and a corecursive part, using Isabelle’s Open image in new window command for the latter [16]. Since our tool supports mixed recursion–corecursion, we can now express functions on stream processors more directly.

We present two functions. The first one runs a stream processor:
The second function, Open image in new window composes two stream processors:

The selector Open image in new window in the noncorecursive friend Open image in new window is legal, because Open image in new window also adds a constructor. In both cases, the Open image in new window command emits a termination proof obligation, which we discharged in two lines, using the same techniques as when defining recursive functions. This command is equivalent to Open image in new window , except that it lets the user discharge proof obligations instead of applying some standard proof automation.

2.6 A Calculator

Next, we formalize a calculator example by Hur et al. [37]. The calculator inputs a number, computes the double of the sum of all inputs, and outputs the current value of the sum. When the input is 0, the calculator counts down to 0 and starts again. Hur et al. implement two versions, Open image in new window and Open image in new window in a programming language embedded deeply in Coq and prove that Open image in new window simulates Open image in new window using parameterized coinduction.

We model the calculator in a shallow fashion as a function from the current sum to a stream processor for Open image in new window s. Let Open image in new window abbreviate Open image in new window We can write the program directly as a function and very closely to its specification [37, Fig. 2]. In Open image in new window and Open image in new window the corecursion goes through the friends Open image in new window and Open image in new window and the constructor guard is hidden in the abbreviation Open image in new window

Our task is to prove that Open image in new window simulates Open image in new window In fact, the two can even be proved to be bisimilar. In our shallow embedding, bisimilarity coincides with equality. We can prove Open image in new window by coinduction with the rule generated for the friends Open image in new window and Open image in new window

2.7 Lazy List Filtering

A classic example requiring a mix of recursion and corecursion is filtering on lazy lists. Given the polymorphic type of lazy lists
the task is to define the function Open image in new window that retains only the elements that satisfy the given predicate. Paulson [58] defined Open image in new window using an inductive search predicate. His development culminates in a proof ofIn Dafny, Leino [45] suggests a definition that mixes recursion and corecursion. We can easily replicate Leino’s definition in Isabelle, where Open image in new window converts lazy lists to sets:

The nonexecutability of the infinite Open image in new window quantifier in the ‘if’ condition is unproblematic in HOL, which has no built-in notion of computation. Lochbihler and Hölzl [48] define Open image in new window as a least fixpoint in the prefix order on Open image in new window Using five properties, they substantiate that fixpoint induction leads to shorter proofs than Paulson’s approach.

We show how to prove three of their properties using our definition, namely (1) andWe start with (2). We prove the interesting direction, Open image in new window , by induction on Open image in new window where the inductive cases are solved automatically. For (3), the Open image in new window direction is also a simple induction on Open image in new window The other direction requires two nested inductions: first on Open image in new window and then a well-founded induction on the termination argument for the recursion in Open image in new window Finally, we prove (1) using the uniqueness principle. We first derive the uniqueness rule for Open image in new window by a coinduction with a nested induction; this approach reflects the mixed recursive-corecursive definition of Open image in new window which nests recursion inside corecursion.
(Our tool does not yet generate uniqueness rules for mixed recursive–corecursive definitions.) Then the proof of (1) is automatic:

Alternatively, we could have proved (1) by coinduction with a nested induction on the termination argument. The uniqueness principle works well because it incorporates both the coinduction and the induction. This underlines that uniqueness can be an elegant proof principle for mixed recursive–corecursive definitions, despite being much weaker than coinduction in the purely corecursive case. Compared with Lochbihler and Hölzl’s proofs by fixpoint induction, our proofs are roughly of the same length, but Open image in new window eliminates the need for the lengthy setup for the domain theory.

2.8 Generative Probabilistic Values

Our final example relies on a codatatype that fully exploits Isabelle’s modular datatype architecture built on bounded natural functors (Sect. 3.1) and that cannot be defined easily, if at all, in other systems. This example is covered in more detail in the report [15].

Lochbihler [47] proposes generative probabilistic values (GPVs) as a semantic domain for probabilistic input–output systems. Conceptually, each GPV chooses probabilistically between failing, terminating with a result of type Open image in new window and continuing by producing an output Open image in new window and transitioning into a reactive probabilistic value (RPV), which waits for a response Open image in new window of the environment before moving to the generative successor state. Lochbihler models GPVs as a codatatype Open image in new window He also defines a monadic language on GPVs similar to a coroutine monad and an operation Open image in new window for composing GPVs with environment converters. The definition of Open image in new window poses two challenges. First, it corecurses through the monadic sequencing operation Open image in new window Due to HOL restrictions, all type variables in a friend’s signature must show up in the resulting codatatype, which is not the case for Open image in new window To work around this, we define a copy Open image in new window with a phantom type parameter  Open image in new window register Open image in new window as a friend, and define Open image in new window in terms of its copy on Open image in new window Second, Open image in new window recurses in a non-well-founded manner through the environment converter. Since our tool supports only mixing with well-founded recursion, we mimic the tool’s internal behavior using a least fixpoint operator.

Initially, Lochbihler had manually derived the coinduction rule up to Open image in new window which our tool now generates. However, because of the copied type, our reformulation ended up roughly as complicated as the original. Moreover, we noted that coinduction up to congruence works only for equality; for user-defined predicates (e.g., typing judgments), the coinduction rule must still be derived manually. But even though this case study is not conclusive, it demonstrates the flexibility of the framework.

3 The Low Level: Corecursor States

Starting from the primitive corecursor provided by Isabelle [16], our tool derives corecursors up to larger and larger sets of friends. The corecursion state includes the set of friends Open image in new window and the corecursor Open image in new window . Four operations manipulate states:
  • Base gives the first nonprimitive corecursor by registering the first friends—the constructors (Sect. 3.3);

  • Step incorporates a new friend into the corecursor (Sect. 3.4);

  • Merge combines two existing sets of friends (Sect. 3.5);

  • Instantiate specializes the corecursor type (Sect. 3.6).

The operations Base and Step have already been described in detail and with many examples in our previous paper [17]. Here, we give a brief, self-contained account of them. Merge and Instantiate are new operations whose need became apparent in the course of implementation.

3.1 Bounded Natural Functors

The mathematics behind our tool assumes that the considered type constructors are both functors and relators, that they include basic functors such as identity, constant, sum, and product, and that they are closed under least and greatest fixpoints (initial algebras and final coalgebras). The tool satisfies this requirement by employing Isabelle’s infrastructure for bounded natural functors (BNFs) [16, 67]. For example, the codatatype Open image in new window is defined as the greatest solution to the fixpoint equation Open image in new window , where both the right-hand side Open image in new window and the resulting type Open image in new window are BNFs.

BNFs have both a functor and a relator structure. If Open image in new window is a unary type constructor, we assume the existence of polymorphic constants for the functorial action, or map function, Open image in new window and the relational action, or relator, Open image in new window , and similarly for n-ary type constructors. For finite lists, Open image in new window is the familiar map function, and given a relation r, Open image in new window relates two lists of the same length and with r-related elements positionwise. While the BNFs are functors on their covariant positions, the relator structure covers contravariant positions as well.

We assume that some of the polymorphic constants are known to be (relationally) parametric in some type variables, in the standard sense [60]. For example, if Open image in new window is a ternary relator and Open image in new window , then Open image in new window is parametric in Open image in new window if Open image in new window holds for all Open image in new window . In a slight departure from standard practice, if a term does not depend on a type variable Open image in new window , we consider it parametric in Open image in new window . The map function of a BNF is parametric in all its type variables. By contrast, Open image in new window is not parametric in Open image in new window .

3.2 Codatatypes and Primitive Corecursion

We fix a codatatype Open image in new window . In general, Open image in new window may depend on some type variables, but we leave this dependency implicit for now. While Open image in new window also may have multiple, curried constructors, it is viewed at the low level as a codatatype with a single constructor Open image in new window and a destructor Open image in new window :

The mutually inverse constructor and destructor establish the isomorphism between Open image in new window and Open image in new window . For streams, we have Open image in new window , Open image in new window , and Open image in new window . Low-level constructors and destructors combine several high-level constructors and destructors in one constant each. Internally, the Open image in new window command works on the low level, providing the high-level constructors as syntactic sugar [16].

In addition, the Open image in new window command derives a primitive corecursor Open image in new window characterized by the equation Open image in new window . The Open image in new window command, provided by Isabelle, reduces a primitively corecursive specification to a plain, acyclic definition expressed using this corecursor.

3.3 Corecursion up to Constructors

We call blueprints the arguments passed to corecursors. When defining a corecursive function Open image in new window , a blueprint for Open image in new window is produced, and Open image in new window is defined as the corecursor applied to the blueprint. The expressiveness of a corecursor is indicated by the codomain of its blueprint argument. The blueprint passed to the primitive corecursor must return an Open image in new window value—e.g., a pair Open image in new window for streams of natural numbers. The remaining corecursion structure is fixed: After producing m, we proceed corecursively with x. We cannot produce two numbers before proceeding corecursively—to do so, the blueprint would have to return Open image in new window .

Our first strengthening of the corecursor allows an arbitrary number of constructors before proceeding corecursively. This process takes a codatatype Open image in new window and produces an initial corecursion state Open image in new window , where Open image in new window is a set of known friends, Open image in new window is a BNF that incorporates the type signatures of known friends, and Open image in new window is a corecursor. We omit the set-of-friends index whenever it is clear from the context. The initial state knows only one friend, Open image in new window .
Let us define the type Open image in new window used for the corecursor. First, we let Open image in new window be the free monad of Open image in new window extended with Open image in new window -constant leaves:

Inhabitants of Open image in new window are (formal) expressions built from variable or constant leaf nodes ( Open image in new window or Open image in new window ) and a syntactic representation of the constants in Open image in new window . Writing Open image in new window for Open image in new window , we can build expressions such as Open image in new window and Open image in new window . The type Open image in new window , of guarded expressions, is similar to Open image in new window , except that it requires at least one Open image in new window guard on every path to a Open image in new window . Formally, Open image in new window is defined as Open image in new window , so that Open image in new window marks the guards. To simplify notation, we will pretend that Open image in new window .

Guarded variable leaves represent corecursive calls. Constant leaves allow us to stop the corecursion with an immediate result of type Open image in new window . The polymorphism of Open image in new window is crucial. If we instantiate Open image in new window to Open image in new window , we can evaluate formal expressions with the function Open image in new window given by Open image in new window , Open image in new window , and Open image in new window . We also write Open image in new window for other versions of the operator (e.g., for Open image in new window ).

The corecursor’s argument, the blueprint, returns guarded expressions consisting of one or more applications of Open image in new window before proceeding corecursively. Proceeding corecursively means applying the corecursor to all variable leaves and evaluating the resulting expression. Formally:

3.4 Adding New Friends

Corecursors can be strengthened to allow friendly functions to surround the context of the corecursive call. At the low level, we consider only uncurried functions.

A function Open image in new window is friendly if it consumes at most one constructor before producing at least one constructor. Friendliness is captured by a mixture of two syntactic constraints and the semantic requirement of parametricity of a certain term, called the surface. The syntactic constraints amount to requiring that Open image in new window is expressible using Open image in new window , irrespective of its actual definition.

Specifically, Open image in new window must be equal to Open image in new window for some blueprint Open image in new window that has the guarding constructor at the outermost position, and this object must be decomposable as Open image in new window for some Open image in new window . The convolution operator Open image in new window combines two functions Open image in new window and Open image in new window .

We call s the surface of Open image in new window because it captures Open image in new window ’s superficial layer while abstracting the application of the destructor. The surface s is more polymorphic than needed by the equation it has to satisfy. Moreover, s must be parametric in Open image in new window . The decomposition, together with parametricity, ensures that friendly functions apply Open image in new window at most once to their arguments and do not look any deeper—the “consumes at most one constructor” property.

The return type of blueprints corresponding to Open image in new window is Open image in new window , where Open image in new window extends Open image in new window with Open image in new window . The type Open image in new window allows all guarded expressions of the previous corecursor but may also refer to Open image in new window . The syntactic representations Open image in new window of old friends Open image in new window must be lifted to the type Open image in new window , which is straightforward. In the sequel, we will reuse the notation Open image in new window for the lifted syntactic representations. In addition to Open image in new window , new expressions are allowed to freely use the syntactic representation Open image in new window of the new friend  Open image in new window , defined as Open image in new window . Like for Open image in new window , we have Open image in new window . As before, we have Open image in new window .

Consider the corecursive specification of pointwise addition on streams of numbers, where Open image in new window is Open image in new window and Open image in new window :
To make sense of this specification, we take Open image in new window to be Open image in new window and define Open image in new window as Open image in new window , where the blueprint Open image in new window isTo register Open image in new window as friendly, we must decompose Open image in new window as Open image in new window . Expanding the definition of Open image in new window , we getIt is easy to see that the following term is a suitable surface s:In Sect. 4, we give more details on how the system synthesizes blueprints and surfaces.

3.5 Merging Corecursion States

Most formalizations are not linear. A module may import several other modules, giving rise to a directed acyclic graph of dependencies. We can reach a situation where the codatatype has been defined in module A; its corecursor has been extended with two different sets of friends Open image in new window and Open image in new window in modules B and C, each importing A; and finally module D, which imports B and C, requires a corecursor that mixes friends from Open image in new window and Open image in new window . To support this scenario, we need an operation that merges two corecursion states.

The return type of blueprints for Open image in new window is Open image in new window , where Open image in new window is the sum of the two input signatures Open image in new window and Open image in new window . By lifting the syntactic representations of old friends using overloading, we establish the invariant that for each Open image in new window of a corecursor state, there is a syntactic representation Open image in new window . The function Open image in new window is then defined in the usual way and constitutes the main ingredient in the definition of Open image in new window with the usual characteristic equation. For operations Open image in new window , two syntactic representations are available; we arbitrarily choose the one inherited from Open image in new window

3.6 Type Instantiation

We have so far ignored the potential polymorphism of Open image in new window . Consider Open image in new window . The operations on corecursor states allow friends of type Open image in new window but not Open image in new window . To allow friends for Open image in new window , we must keep track of specialized corecursors. First, we need an operation for instantiating corecursor states.

Once we have derived a specific corecursor for Open image in new window , we can extend it with friends of type Open image in new window . Such friends cannot be added to the polymorphic corecursor, but the other direction works: Any friend of a polymorphic corecursor is also a friend of a specialized corecursor. Accordingly, we maintain a Pareto optimal subset of corecursor state instances Open image in new window , where Open image in new window denotes that the type Open image in new window can be obtained from the type Open image in new window by applying a type substitution.

More specific corecursors are stored only if they have more friends: For each pair of corecursor instances for Open image in new window and Open image in new window contained in the Pareto set, we have Open image in new window whenever Open image in new window . All the corecursors in the Pareto set are kept up to date. If we add a friend to a corecursor instance for Open image in new window from the set via Step, it is also propagated to all instances Open image in new window of Open image in new window by applying Instantiate to the output of Step and combining the result with the existing corecursor state for Open image in new window via Merge. When analyzing a user specification, Open image in new window selects the most specific applicable corecursor.

Eagerly computing the entire Pareto set is exponentially expensive. Consider a codatatype Open image in new window and the friends Open image in new window for Open image in new window , Open image in new window for Open image in new window , and Open image in new window for Open image in new window . The set would contain eight corecursors, each with a different subset of Open image in new window as friends. To avoid such an explosion, we settle for a lazy derivation strategy. In the above example, the corecursor for Open image in new window , with Open image in new window as friends, is derived only if a definition needs it.

3.7 Reasoning Principles

The primary activity of a working formalizer is to develop proofs. To conveniently reason about nonprimitively corecursive functions, Open image in new window provides two reasoning principles: coinduction up to congruence and a uniqueness theorem.

Coinduction up to Congruence. Codatatypes are equipped with a coinduction principle. Coinduction reduces the task of proving equality between two inhabitants l and r of a codatatype to the task of exhibiting a relation R which relates l and r and is closed under application of destructors. A relation closed under destructors is called a bisimulation. The Open image in new window command derives a plain coinduction rule. The rule for Open image in new window follows:To reason about functions that are corecursive up to a set of friends, a principle of coinduction up to congruence of friends is crucial. For a corecursor with friends Open image in new window , our tool derives a rule that is identical to the standard rule except with Open image in new window instead of Open image in new window , where Open image in new window denotes the congruence closure of the relation R with respect to the friendly operations Open image in new window .
After registering a binary Open image in new window on Open image in new window as friendly, the introduction rules for the inductively defined congruence closure includeSince the tool maintains a set of incomparable corecursors, there is also a set of coinduction principles and a set of sets of introduction rules. The Open image in new window command orders the set of coinduction principles by increasing generality, which works well with Isabelle’s philosophy of applying the first rule that matches.
In some circumstances, it may be necessary to reason about the union of friends associated with several incomparable corecursors. To continue with the example from Sect. 3.6, suppose we want to prove a formula about Open image in new window by coinduction up to Open image in new window before the corresponding corecursor has been derived. Users can derive it and the associated coinduction principle by invoking a dedicated command:
Uniqueness Principles. It is sometimes possible to achieve better automation by employing a more specialized proof method than coinduction. Uniqueness principles exploit the property that the corecursor is the unique solution to a fixpoint equation:This rule can be seen as a less powerful version of coinduction, where the bisimulation relation has been preinstantiated. In category-theoretic terms, the existence and uniqueness of a solution means that we maintain on Open image in new window a completely iterative algebra [51] (whose signature is gradually incremented with each additional friend).
For concrete functions defined with Open image in new window , uniqueness rules can be made even more precise by instantiating the blueprint Open image in new window . For example, the pointwise addition on streams from Sect. 3.4
yields the following uniqueness principle:Reasoning by uniqueness is not restricted to functions defined with Open image in new window . Suppose Open image in new window is an arbitrary term depending on a list of free variables Open image in new window . The Open image in new window proof method, also provided by our tool, transforms proof obligations of the forminto Open image in new window . The higher-order functional H must be such that the equation Open image in new window would be a valid Open image in new window specification (but without nested calls to h or unguarded calls). Internally, Open image in new window extracts the blueprint Open image in new window from Open image in new window as if it would define h with Open image in new window and uses the uniqueness principle for Open image in new window instantiated with Open image in new window to achieve the described transformation.

4 The High Level: From Commands to Definitions

AmiCo’s two main commands Open image in new window (Sect. 4.1) and Open image in new window (Sect. 4.2) introduce corecursive functions and register friends. We describe synthesis algorithms for any codatatype as implemented in the tool. We also show how to capture the “consumes at most one constructor, produces at least one constructor” contract of friends.

4.1 Defining Corecursive Functions

The Open image in new window command reduces the user’s corecursive equation to non(co)recursive primitives, so as to guard against inconsistencies. To this end, the command engages in a chain of definitions and proofs. Recall the general context:

In general, Open image in new window may be polymorphic and Open image in new window may take more than one argument, but these are minor orthogonal concerns here. As before, we write Open image in new window for the type of formal expressions built from Open image in new window -leaves and friend symbols Open image in new window , and Open image in new window for Open image in new window -guarded formal expressions. For Open image in new window , we can evaluate the formal expressions into elements of Open image in new window , by replacing each Open image in new window with Open image in new window and omitting the Open image in new window and Open image in new window constructors. Finally, we write Open image in new window for the evaluation functions of various types of symbolic expressions to Open image in new window .

Consider the command
where Open image in new window is a term that may refer to Open image in new window and x. The first task of Open image in new window is to synthesize a blueprint object Open image in new window such thatholds for all Open image in new window . This equation states that the synthesized blueprint must produce, by evaluation, the concrete right-hand side of the user equation. The unknown function h represents corecursive calls, which will be instantiated to Open image in new window once Open image in new window is defined. To the occurrences of h in Open image in new window correspond occurrences of Open image in new window in b.
Equipped with a blueprint, we define Open image in new window and derive the user equation: Blueprint Synthesis. The blueprint synthesis proceeds by a straightforward syntactic analysis, similar to the one used for primitive corecursion [16]. We illustrate it with an example. Consider the definition of Open image in new window from Sect. 3.4. Ignoring currying, the function has type Open image in new window , with Open image in new window . The term Open image in new window is synthesized by processing the right-hand side of the corecursive equation for Open image in new window . After removing the syntactic sugar, we obtain the following term, highlighting the corecursive call:The blueprint is derived from this term by replacing the constructor guard Open image in new window and the friends with their syntactic counterparts and the corecursive call with a variable leaf:Synthesis will fail if after the indicated replacements the result does not have the desired type (here, Open image in new window ). If we omit ‘ Open image in new window ’ in the definition, the type of b becomes Open image in new window , reflecting the lack of a guard. Another cause of failure is the presence of unfriendly operators in the call context. Once Open image in new window has been produced, Open image in new window proves that Open image in new window satisfies the user equation we started with.
Mixed Recursion–Corecursion. If a self-call is not guarded, Open image in new window still gives it a chance, since it could be a terminating recursive call. As an example, the following definition computes all the odd numbers greater than 1 arising in the Collatz sequence:
The highlighted call is not guarded. Yet, it will eventually lead to a guarded call, since repeatedly halving a positive even number must at some point yield an odd number. The unguarded call yields a recursive specification of the blueprint  Open image in new window , which is resolved automatically by the termination prover.
By writing Open image in new window instead of Open image in new window , the user takes responsibility for proving termination. A manual proof was necessary for Open image in new window in Sect. 2.7, whose blueprint satisfies the recursion

Termination is shown by providing a suitable well-founded relation, which exists because Open image in new window is closer than Open image in new window to the next element that satisfies the predicate P.

Like the corecursive calls, the recursive calls may be surrounded only by friendly operations (or by parametric operators such as ‘case’, ‘if’, and ‘let’). Thus, the following specification is rejected—and rightly so, since the unfriendly Open image in new window cancels the corecursive guard that is reached when recursion terminates.

4.2 Registering New Friendly Operations

The command
defines Open image in new window and registers it as a friend. The domain is viewed abstractly as a type constructor Open image in new window applied to the codatatype  Open image in new window .

The command first synthesizes the blueprint Open image in new window , similarly to the case of plain corecursive definitions. However, this time the type \(\Sigma \) is not Open image in new window , but Open image in new window . Thus, Open image in new window mixes freely the type Open image in new window with the components Open image in new window of Open image in new window , which caters for self-friendship (as in the Open image in new window example from Sect. 2.4): Open image in new window can be defined making use of itself as a friend (in addition to the already registered friends).

The next step is to synthesize a surface s from the blueprint  Open image in new window . Recall from Sect. 3.4 that a corecursively defined operator is friendly if its blueprint Open image in new window can be decomposed as Open image in new window , where Open image in new window is parametric in Open image in new window .

Once the surface s has been synthesized, proved parametric, and proved to be in the desired relationship with b, the tool invokes the Step operation (Sect. 3.4), enriching the corecursion state with the function defined by Open image in new window as a new friend, called Open image in new window .

Alternatively, users can register arbitrary functions as friends:
The user must then prove the equation Open image in new window . The command extracts a blueprint from it and proceeds with the surface synthesis in the same way as Open image in new window   Open image in new window

Surface Synthesis Algorithm. The synthesis of the surface from the blueprint proceeds by the context-dependent replacement of some constants with terms. AmiCo performs the replacements in a logical-relation fashion, guided by type inference.

We start with Open image in new window and need to synthesize Open image in new window such that s is parametric in Open image in new window and Open image in new window . We traverse Open image in new window recursively and collect context information about the appropriate replacements. The technical report describes the algorithm in detail. Here, we illustrate it on an example.

Consider the definition of a function that interleaves a nonempty list of streams:
Here, Open image in new window is the type of nonempty lists with head and tail selectors Open image in new window and Open image in new window and Open image in new window is defined such that Open image in new window appends y to Open image in new window . We have Open image in new window and Open image in new window . The blueprint isFrom this, the tool synthesizes the surfaceWhen transforming the blueprint Open image in new window into the surface Open image in new window , the selectors Open image in new window and Open image in new window are replaced by suitable compositions. One of the other constants, Open image in new window , is composed with a mapping of Open image in new window . The treatment of constants is determined by their position relative to the input variables (here, Open image in new window ) and by whether the input is eventually consumed by a destructor-like operator on Open image in new window (here, Open image in new window and Open image in new window ). Bindings can also carry consumption information—from the outer context to within their scope—as in the following variant of Open image in new window :
The case expression is syntactic sugar for a Open image in new window combinator. The desugared blueprint and surface constants areThe case operator for streams is processed specially, because just like Open image in new window and Open image in new window it consumes the input. The expression in the scope of the inner Open image in new window of the blueprint contains two variables— Open image in new window and Open image in new window —that have Open image in new window in their type. Due to the outer context, they must be treated differently: Open image in new window as an unconsumed input (which tells us to process the surrounding constant Open image in new window ) and Open image in new window as a consumed input (which tells us to leave the surrounding constant Open image in new window unchanged). The selectors and case operators for Open image in new window can also be applied indirectly, via mapping (e.g., Open image in new window ).

5 Implementation in Isabelle/HOL

The implementation of AmiCo followed the same general strategy as that of most other definitional mechanisms for Isabelle:
  1. 1.

    We started from an abstract formalized example consisting of a manual construction of the Base and Step corecursors and the corresponding reasoning principles.

     
  2. 2.

    We streamlined the formal developments, eliminating about 1000 lines of Isabelle definitions and proofs—to simplify the implementation and improve performance.

     
  3. 3.

    We formalized the new Merge operation in the same style as Base and Step.

     
  4. 4.

    We developed Standard ML functions to perform the corecursor state operations for arbitrary codatatypes and friendly functions.

     
  5. 5.

    We implemented, also in Standard ML, the commands that process user specifications and interact with the corecursor state.

     

HOL’s type system cannot express quantification over arbitrary BNFs, thus the need for ML code to repeat the corecursor derivations for each new codatatype or friend. With the foundational approach, not only the corecursors and their characteristic theorems are produced but also all the intermediate objects and lemmas, to reach the highest level of trustworthiness. Assuming the proof assistant’s inference kernel is correct, bugs in our tool can lead at most to run-time failures, never to logical inconsistencies.

The code for step 4 essentially constructs the low-level types, terms, and lemma statements presented in Sect. 3 and proves the lemmas using dedicated tactics—ML programs that generalize the proofs from the formalization. In principle, the tactics always succeed. The code for step 5 analyses the user’s specification and synthesizes blueprints and surfaces, as exemplified in Sect. 4. It reuses Open image in new window parsing combinators [16] for recognizing map functions and other syntactic conveniences, such as the use of Open image in new window s as an alternative to Open image in new window for corecursing under Open image in new window , as seen in Sect. 2.1.

The archive accompanying this paper [14] contains instructions that explain where to find the code and the users’ manual and how to run the code.

6 Related Work and Discussion

This work combines the safety of foundational approaches to function definitions with an expressive flavor of corecursion and mixed recursion–corecursion. It continues a program of integrating category theory insight into proof assistant technology [16, 17, 18, 67]. There is a lot of related work on corecursion and productivity, both theoretical and applied to proof assistants and functional programming languages.

Theory of (Co)recursion. AmiCo incorporates category theory from many sources, notably Milius et al. [52] for corecursion up-to and Rot et al. [61] for coinduction up-to. Our earlier papers [17, 67] discuss further theoretical sources. AmiCo implements the first general, provably sound, and fully automatic method for mixing recursive and corecursive calls in function definitions. The idea of mixing recursion and corecursion appears in Bertot [11] for the stream filter, and a generalization is sketched in Bertot and Komendantskaya [13] for corecursion up to constructors. Leino’s Dafny tool [46] was the first to offer such a mixture for general codatatypes, which turned out to be unsound and was subsequently restricted to the sound but limited fragment of tail recursion.

Corecursion in Other Proof Assistants. Coq supports productivity by a syntactic guardedness check, based on the pioneering work of Giménez [26]. MiniAgda [2] and Agda implement a more flexible approach to productivity due to Abel et al. [3, 5], based on sized types and copatterns. Coq’s guardedness check allows, in our terminology, only the constructors as friends [21]. By contrast, Agda’s productivity checker is more expressive than AmiCo’s, because sized types can capture more precise contracts than the “consumes at most one constructor, produces at least one constructor” criterion. For example, a Fibonacci stream definition such as Open image in new window can be made to work in Agda, but is rejected by AmiCo because Open image in new window is not a friend. As mentioned in Sect. 2.4, this flexibility comes at a price: The user must encode the productivity argument in the function’s type, leading to additional proof obligations.

CIRC [50] is a theorem prover designed for automating coinduction via sound circular reasoning. It bears similarity with both Coq’s Paco and our AmiCo. Its freezing operators are an antidote to what we would call the absence of friendship: Equality is no longer a congruence, hence equational reasoning is frozen at unfriendly locations.

Foundational Function Definitions. AmiCo’s commands and proof methods fill a gap in Isabelle/HOL’s coinductive offering. They complement Open image in new window Open image in new window and Open image in new window [16], allowing users to define nonprimitive corecursive and mixed recursive–corecursive functions. Being foundational, our work offers a strong protection against inconsistency by reducing circular fixpoint definitions issued by the user to low-level acyclic definitions in the core logic. This approach has a long tradition.

Most systems belonging to the HOL family include a counterpart to the Open image in new window command of Isabelle, which synthesizes the argument to a primitive recursor. Isabelle/HOL is the only HOL system that also supports codatatypes and Open image in new window [16]. Isabelle/ZF, for Zermelo–Fraenkel set theory, provides Open image in new window and Open image in new window [57] commands, but no high-level mechanisms for defining corecursive functions.

For nonprimitively recursive functions over datatypes, Slind’s TFL package for HOL4 and Isabelle/HOL [63] and Krauss’s Open image in new window command for Isabelle/HOL [42] are the state of the art. Krauss developed the Open image in new window command for defining monadic functions [43]. Definitional mechanisms based on the Knaster–Tarski fixpoint theorems were also developed for (co)inductive predicates [31, 57]. HOLCF, a library for domain theory, offers a Open image in new window command for defining continuous functions [35].

Our handling of friends can be seen as a round trip between a shallow and a deep embedding that resembles normalization by evaluation [9] (but starting from the shallow side). Initially, the user specification contains shallow (semantic) friends. For identifying the involved corecursion as sound, the tool reifies the friends into deep (syntactic) friends, which make up the blueprint. Then the deep friends are “reflected” back into their shallow versions by the evaluation function Open image in new window . A similar technique is used by Myreen in HOL4 for verification and synthesis of functional programs [55].

In Agda, Coq, and Matita, the definitional mechanisms for (co)recursion are built into the system. In contrast, Lean axiomatizes only the recursor [54]. The distinguishing features of AmiCo are its dynamicity and high level of automation. The derived corecursors and coinduction principles are updated with new ones each time a friend is registered. This permits reuse both internally (resulting in lighter constructions) and at the user level (resulting in fewer proof obligations).

Code Extraction. Isabelle’s code generator [29] extracts Haskell code from an executable fragment of HOL, mapping HOL (co)datatypes to lazy Haskell datatypes and HOL functions to Haskell functions. Seven out of our eight case studies fall into this fragment; the extracted code is part of the archive [14]. Only the filter function on lazy lists is clearly not computable (Sect. 2.7). In particular, extraction works for Lochbihler’s probabilistic calculus (Sect. 2.8) which involves the type Open image in new window of discrete subprobability distributions. Verified data refinement in the code generator makes it possible to implement such BNFs in terms of datatypes, e.g., Open image in new window as associative lists similar to Erwig’s and Kollmansberger’s PFP library [24]. Thus, we can extract code for GPVs and their operations like inlining. Lochbihler and Züst [49] used an earlier version of the calculus to implement a core of the Transport Layer Security (TLS) protocol in HOL.

Certified Lazy Programming. Our tool and the examples are a first step towards a framework for friendship-based certified programming: Programs are written in the executable fragment, verified in Isabelle, and extracted to Haskell. AmiCo ensures that corecursive definitions are productive and facilitates coinductive proofs by providing strong coinduction rules. Productivity and termination of the extracted code are guaranteed if the whole program is specified in HOL exclusively with datatypes, codatatypes, recursive functions with the Open image in new window command, and corecursive functions with Open image in new window , and no custom congruence rules for higher-order operators have been used. The technical report [15, Sect. 6] explains why these restrictions are necessary.

If the restrictions are met, the program clearly lies within the executable fragment and the code extracted from the definitions yields the higher-order rewrite system which the termination prover and AmiCo have checked. In particular, these restrictions exclude the noncomputable filter function on lazy lists (Sect. 2.7), with the test Open image in new window

A challenge will be to extend these guarantees to Isabelle’s modular architecture. Having been designed with only partial correctness in mind, the code extractor can be customized to execute arbitrary (proved) equations—which can easily break productivity and termination. A similar issue occurs with Open image in new window which cares only about semantic properties of the friend to be. For example, we can specify the identity function Open image in new window on streams by Open image in new window and register it as a friend with the derived equation Open image in new window Consequently, AmiCo accepts the definition Open image in new window , but the extracted Haskell code diverges. To avoid these problems, we would have to (re)check productivity and termination on the equations used for extraction. In this scenario, AmiCo can be used to distinguish recursive from corecursive calls in a set of (co)recursive equations, and synthesize sufficient conditions for the function being productive and the recursion terminating, and automatically prove them (using Isabelle’s parametricity [36] and termination provers [20]).

AmiCo Beyond Higher-Order Logic. The techniques implemented in our tool are applicable beyond Isabelle/HOL. In principle, nothing stands in the way of AgdamiCo, AmiCoq, or MatitamiCo. Danielsson [22] and Thibodeau et al. [65] showed that similar approaches work in type theory; what is missing is a tool design and implementation. AmiCo relies on parametricity, which is now understood for dependent types [10].

In Agda, parametricity could be encoded with sized types, and AgdamiCo could be a foundational tool that automatically adds suitable sized types for justifying the definition and erases them from the end product. Coq includes a parametricity-tracking tool [40] that could form the basis of AmiCoq. The Paco library by Hur et al. [37] facilitates coinductive proofs based on parameterized coinduction [53, 70]. Recent work by Pous [59] includes a framework to combine proofs by induction and coinduction. An AmiCoq would catch up on the corecursion definition front, going beyond what is possible with the Open image in new window tactic [21]. On the proof front, AmiCoq would provide a substantial entry into Paco’s knowledge base: For any codatatype Open image in new window with destructor Open image in new window , all registered friends are, in Paco’s terminology, respectful up-to functions for the monotonic operator Open image in new window , whose greatest fixpoint is the equality on  Open image in new window .

A more lightweight application of our methodology would be an AmiCo for Haskell or for more specialized languages such as CoCaml [38]. In these languages, parametricity is ensured by the computational model. An automatic tool that embodies AmiCo’s principles could analyze a Haskell program and prove it total. For CoCaml, which is total, a tool could offer more flexibility when writing corecursive programs.

Surface Synthesis Beyond Corecursion. The notion of extracting a parametric component with suitable properties can be useful in other contexts than corecursion. In the programming-by-examples paradigm [28], one needs to choose between several synthesized programs whose behavior matches a set of input–output instances. These criteria tend to prefer programs that are highly parametric. A notion of degree of parametricity does not exist in the literature but could be expressed as the size of a parametric surface, for a suitable notion of surface, where Open image in new window is replaced by domain specific functions and Open image in new window by their left inverses.

Notes

Acknowledgment

Martin Desharnais spent months extending Isabelle’s Open image in new window command to generate a wealth of theorems, many of which were useful when implementing AmiCo. Lorenz Panny developed Open image in new window whose code provided valuable building blocks. Mathias Fleury, Mark Summerfield, Daniel Wand, and the anonymous reviewers suggested many textual improvements. We thank them all. Blanchette is supported by the European Research Council (ERC) starting grant Matryoshka (713999). Lochbihler is supported by the Swiss National Science Foundation (SNSF) grant “Formalising Computational Soundness for Protocol Implementations” (153217). Popescu is supported by the UK Engineering and Physical Sciences Research Council (EPSRC) starting grant “VOWS: Verification of Web-based Systems” (EP/N019547/1). The authors are listed in alphabetical order.

References

  1. 1.
    Abbott, M., Altenkirch, T., Ghani, N.: Containers: constructing strictly positive types. Theor. Comput. Sci. 342(1), 3–27 (2005)MathSciNetCrossRefzbMATHGoogle Scholar
  2. 2.
    Abel, A.: MiniAgda: integrating sized and dependent types. In: Bove, A., Komendantskaya, E., Niqui, M. (eds.) PAR 2010. EPTCS, vol. 43, pp. 14–28 (2010)Google Scholar
  3. 3.
    Abel, A.: Compositional coinduction with sized types. In: Hasuo, I. (ed.) CMCS 2016. LNCS, vol. 9608, pp. 5–10. Springer, Heidelberg (2016). doi: 10.1007/978-3-319-40370-0_2 CrossRefGoogle Scholar
  4. 4.
    Abel, A., Pientka, B.: Well-founded recursion with copatterns and sized types. J. Funct. Program. 26, e2 (2016)MathSciNetCrossRefGoogle Scholar
  5. 5.
    Abel, A., Pientka, B., Thibodeau, D., Setzer, A.: Copatterns: programming infinite structures by observations. In: Giacobazzi, R., Cousot, R. (eds.) POPL 2013, pp. 27–38. ACM (2013)Google Scholar
  6. 6.
    Adams, M.: Introducing HOL Zero. In: Fukuda, K., Hoeven, J., Joswig, M., Takayama, N. (eds.) ICMS 2010. LNCS, vol. 6327, pp. 142–143. Springer, Heidelberg (2010). doi: 10.1007/978-3-642-15582-6_25 CrossRefGoogle Scholar
  7. 7.
    Asperti, A., Ricciotti, W., Sacerdoti Coen, C., Tassi, E.: The Matita interactive theorem prover. In: Bjørner, N., Sofronie-Stokkermans, V. (eds.) CADE 2011. LNCS (LNAI), vol. 6803, pp. 64–69. Springer, Heidelberg (2011). doi: 10.1007/978-3-642-22438-6_7 CrossRefGoogle Scholar
  8. 8.
    Atkey, R., McBride, C.: Productive coprogramming with guarded recursion. In: Morrisett, G., Uustalu, T. (eds.) ICFP 2013, pp. 197–208. ACM (2013)Google Scholar
  9. 9.
    Berger, U., Schwichtenberg, H.: An inverse of the evaluation functional for typed lambda-calculus. In: LICS 1991, pp. 203–211. IEEE Computer Society (1991)Google Scholar
  10. 10.
    Bernardy, J.P., Jansson, P., Paterson, R.: Proofs for free: parametricity for dependent types. J. Funct. Program. 22(2), 107–152 (2012)MathSciNetCrossRefzbMATHGoogle Scholar
  11. 11.
    Bertot, Y.: Filters on coinductive streams, an application to Eratosthenes’ sieve. In: Urzyczyn, P. (ed.) TLCA 2005. LNCS, vol. 3461, pp. 102–115. Springer, Heidelberg (2005). doi: 10.1007/11417170_9 CrossRefGoogle Scholar
  12. 12.
    Bertot, Y., Casteran, P.: Interactive Theorem Proving and Program Development–Coq’Art: The Calculus of Inductive Constructions. Texts in Theoretical Computer Science. Springer, Heidelberg (2004)CrossRefzbMATHGoogle Scholar
  13. 13.
    Bertot, Y., Komendantskaya, E.: Inductive and coinductive components of corecursive functions in Coq. Electr. Notes Theor. Comput. Sci. 203(5), 25–47 (2008)MathSciNetCrossRefzbMATHGoogle Scholar
  14. 14.
    Blanchette, J.C., Bouzy, A., Lochbihler, A., Popescu, A., Traytel, D.: Archive associated with this paper. http://matryoshka.gforge.inria.fr/pubs/amico_material.tar.gz
  15. 15.
    Blanchette, J.C., Bouzy, A., Lochbihler, A., Popescu, A., Traytel, D.: Friends with benefits: implementing corecursion in foundational proof assistants. Technical report (2017). http://matryoshka.gforge.inria.fr/pubs/amico_report.pdf
  16. 16.
    Blanchette, J.C., Hölzl, J., Lochbihler, A., Panny, L., Popescu, A., Traytel, D.: Truly modular (co)datatypes for Isabelle/HOL. In: Klein, G., Gamboa, R. (eds.) ITP 2014. LNCS, vol. 8558, pp. 93–110. Springer, Heidelberg (2014). doi: 10.1007/978-3-319-08970-6_7 Google Scholar
  17. 17.
    Blanchette, J.C., Popescu, A., Traytel, D.: Foundational extensible corecursion: a proof assistant perspective. In: Fisher, K., Reppy, J.H. (eds.) ICFP 2015, pp. 192–204. ACM (2015)Google Scholar
  18. 18.
    Blanchette, J.C., Popescu, A., Traytel, D.: Witnessing (co)datatypes. In: Vitek, J. (ed.) ESOP 2015. LNCS, vol. 9032, pp. 359–382. Springer, Heidelberg (2015). doi: 10.1007/978-3-662-46669-8_15 CrossRefGoogle Scholar
  19. 19.
    Bove, A., Dybjer, P., Norell, U.: A brief overview of Agda – a functional language with dependent types. In: Berghofer, S., Nipkow, T., Urban, C., Wenzel, M. (eds.) TPHOLs 2009. LNCS, vol. 5674, pp. 73–78. Springer, Heidelberg (2009). doi: 10.1007/978-3-642-03359-9_6 CrossRefGoogle Scholar
  20. 20.
    Bulwahn, L., Krauss, A., Nipkow, T.: Finding lexicographic orders for termination proofs in Isabelle/HOL. In: Schneider, K., Brandt, J. (eds.) TPHOLs 2007. LNCS, vol. 4732, pp. 38–53. Springer, Heidelberg (2007). doi: 10.1007/978-3-540-74591-4_5 CrossRefGoogle Scholar
  21. 21.
    Chlipala, A.: Certified Programming with Dependent Types—A Pragmatic Introduction to the Coq Proof Assistant. MIT Press, Cambridge (2013)zbMATHGoogle Scholar
  22. 22.
    Danielsson, N.A.: Beating the productivity checker using embedded languages. In: Bove, A., Komendantskaya, E., Niqui, M. (eds.) PAR 2010. EPTCS, vol. 43, pp. 29–48 (2010)Google Scholar
  23. 23.
    Dijkstra, E.W.: An exercise for Dr. R. M. Burstall. In: Dijkstra, E.W. (ed.) Selected Writings on Computing: A Personal Perspective, pp. 215–216. Texts and Monographs in Computer Science. Springer, Heidelberg (1982)CrossRefGoogle Scholar
  24. 24.
    Erwig, M., Kollmansberger, S.: Probabilistic functional programming in Haskell. J. Funct. Programm. 16(1), 21–34 (2006)CrossRefzbMATHGoogle Scholar
  25. 25.
    Gammie, P., Lochbihler, A.: The Stern-Brocot tree. Archive of Formal Proofs (2015). https://www.isa-afp.org/entries/Stern_Brocot.shtml
  26. 26.
    Giménez, E.: Codifying guarded definitions with recursive schemes. In: Dybjer, P., Nordström, B., Smith, J. (eds.) TYPES 1994. LNCS, vol. 996, pp. 39–59. Springer, Heidelberg (1995). doi: 10.1007/3-540-60579-7_3 CrossRefGoogle Scholar
  27. 27.
    Gordon, M.J.C., Melham, T.F.: Introduction to HOL: A Theorem Proving Environment for Higher Order Logic. Cambridge University Press, Cambridge (1993)zbMATHGoogle Scholar
  28. 28.
    Gulwani, S.: Programming by examples—and its applications in data wrangling. In: Dependable Software Systems Engineering. NATO Science for Peace and Security Series D: Information and Communication Security, vol. 45, pp. 137–158. IOS Press (2016)Google Scholar
  29. 29.
    Haftmann, F., Nipkow, T.: Code generation via higher-order rewrite systems. In: Blume, M., Kobayashi, N., Vidal, G. (eds.) FLOPS 2010. LNCS, vol. 6009, pp. 103–117. Springer, Heidelberg (2010). doi: 10.1007/978-3-642-12251-4_9 CrossRefGoogle Scholar
  30. 30.
    Hagino, T.: A categorical programming language. Ph.D. thesis, University of Edinburgh (1987)Google Scholar
  31. 31.
    Harrison, J.: Inductive definitions: automation and application. In: Thomas Schubert, E., Windley, P.J., Alves-Foss, J. (eds.) TPHOLs 1995. LNCS, vol. 971, pp. 200–213. Springer, Heidelberg (1995). doi: 10.1007/3-540-60275-5_66 CrossRefGoogle Scholar
  32. 32.
    Harrison, J.: HOL Light: an overview. In: Berghofer, S., Nipkow, T., Urban, C., Wenzel, M. (eds.) TPHOLs 2009. LNCS, vol. 5674, pp. 60–66. Springer, Heidelberg (2009). doi: 10.1007/978-3-642-03359-9_4 CrossRefGoogle Scholar
  33. 33.
    Hinze, R.: The Bird tree. J. Func. Programm. 19(5), 491–508 (2009)MathSciNetCrossRefzbMATHGoogle Scholar
  34. 34.
    Homeier, P.V.: The HOL-Omega logic. In: Berghofer, S., Nipkow, T., Urban, C., Wenzel, M. (eds.) TPHOLs 2009. LNCS, vol. 5674, pp. 244–259. Springer, Heidelberg (2009). doi: 10.1007/978-3-642-03359-9_18 CrossRefGoogle Scholar
  35. 35.
    Huffman, B.: HOLCF ’11: a definitional domain theory for verifying functional programs. Ph.D. thesis, Portland State University (2012)Google Scholar
  36. 36.
    Huffman, B., Kun\(\check{\rm c}\)ar, O.: Lifting and transfer: a modular design for quotients in Isabelle/HOL. In: Gonthier, G., Norrish, M. (eds.) CPP 2013. LNCS, vol. 8307, pp. 131–146. Springer, Heidelberg (2013). doi: 10.1007/978-3-319-03545-1_9
  37. 37.
    Hur, C.K., Neis, G., Dreyer, D., Vafeiadis, V.: The power of parameterization in coinductive proof. In: Giacobazzi, R., Cousot, R. (eds.) POPL 2013, pp. 193–206. ACM (2013)Google Scholar
  38. 38.
    Jeannin, J.-B., Kozen, D., Silva, A.: Language constructs for non-well-founded computation. In: Felleisen, M., Gardner, P. (eds.) ESOP 2013. LNCS, vol. 7792, pp. 61–80. Springer, Heidelberg (2013). doi: 10.1007/978-3-642-37036-6_4 CrossRefGoogle Scholar
  39. 39.
    Jones, G., Gibbons, J.: Linear-time breadth-first tree algorithms: an exercise in the arithmetic of folds and zips. Technical report 71, Computer Science Department, University of Auckland (1993)Google Scholar
  40. 40.
    Keller, C., Lasson, M.: Parametricity in an impredicative sort. In: Cégielski, P., Durand, A. (eds.) CSL 2012. LIPIcs, vol. 16, pp. 381–395. Schloss Dagstuhl–Leibniz-Zentrum für Informatik (2012)Google Scholar
  41. 41.
    Knuth, D.E., Morris, J.H., Pratt, V.R.: Fast pattern matching in strings. SIAM J. Comput. 6(2), 323–350 (1977)MathSciNetCrossRefzbMATHGoogle Scholar
  42. 42.
    Krauss, A.: Partial recursive functions in higher-order logic. In: Furbach, U., Shankar, N. (eds.) IJCAR 2006. LNCS (LNAI), vol. 4130, pp. 589–603. Springer, Heidelberg (2006). doi: 10.1007/11814771_48 CrossRefGoogle Scholar
  43. 43.
    Krauss, A.: Recursive definitions of monadic functions. In: Bove, A., Komendantskaya, E., Niqui, M. (eds.) PAR 2010. EPTCS, vol. 43, pp. 1–13 (2010)Google Scholar
  44. 44.
    van Laarhoven, T.: Knuth-Morris-Pratt in Haskell (2007). http://www.twanvl.nl/blog/haskell/Knuth-Morris-Pratt-in-Haskell
  45. 45.
    Leino, K.R.M.: Automating theorem proving with SMT. In: Blazy, S., Paulin-Mohring, C., Pichardie, D. (eds.) ITP 2013. LNCS, vol. 7998, pp. 2–16. Springer, Heidelberg (2013). doi: 10.1007/978-3-642-39634-2_2 CrossRefGoogle Scholar
  46. 46.
    Leino, K.R.M., Moskal, M.: Co-induction simply: automatic co-inductive proofs in a program verifier. In: Jones, C., Pihlajasaari, P., Sun, J. (eds.) FM 2014. LNCS, vol. 8442, pp. 382–398. Springer, Heidelberg (2014). doi: 10.1007/978-3-319-06410-9_27 CrossRefGoogle Scholar
  47. 47.
    Lochbihler, A.: Probabilistic functions and cryptographic oracles in higher order logic. In: Thiemann, P. (ed.) ESOP 2016. LNCS, vol. 9632, pp. 503–531. Springer, Heidelberg (2016). doi: 10.1007/978-3-662-49498-1_20 CrossRefGoogle Scholar
  48. 48.
    Lochbihler, A., Hölzl, J.: Recursive functions on lazy lists via domains and topologies. In: Klein, G., Gamboa, R. (eds.) ITP 2014. LNCS, vol. 8558, pp. 341–357. Springer, Heidelberg (2014). doi: 10.1007/978-3-319-08970-6_22 Google Scholar
  49. 49.
  50. 50.
    Lucanu, D., Goriac, E.-I., Caltais, G., Roşu, G.: CIRC: a behavioral verification tool based on circular coinduction. In: Kurz, A., Lenisa, M., Tarlecki, A. (eds.) CALCO 2009. LNCS, vol. 5728, pp. 433–442. Springer, Heidelberg (2009). doi: 10.1007/978-3-642-03741-2_30 CrossRefGoogle Scholar
  51. 51.
    Milius, S.: Completely iterative algebras and completely iterative monads. Inf. Comput. 196(1), 1–41 (2005)MathSciNetCrossRefzbMATHGoogle Scholar
  52. 52.
    Milius, S., Moss, L.S., Schwencke, D.: Abstract GSOS rules and a modular treatment of recursive definitions. Log. Meth. Comput. Sci. 9(3:28), 1–52 (2013)MathSciNetzbMATHGoogle Scholar
  53. 53.
    Moss, L.S.: Parametric corecursion. Theor. Comput. Sci. 260(1–2), 139–163 (2001)MathSciNetCrossRefzbMATHGoogle Scholar
  54. 54.
    de Moura, L., Kong, S., Avigad, J., van Doorn, F., von Raumer, J.: The Lean theorem prover (system description). In: Felty, A.P., Middeldorp, A. (eds.) CADE 2015. LNCS (LNAI), vol. 9195, pp. 378–388. Springer, Heidelberg (2015). doi: 10.1007/978-3-319-21401-6_26 CrossRefGoogle Scholar
  55. 55.
    Myreen, M.O.: Functional programs: conversions between deep and shallow embeddings. In: Beringer, L., Felty, A. (eds.) ITP 2012. LNCS, vol. 7406, pp. 412–417. Springer, Heidelberg (2012). doi: 10.1007/978-3-642-32347-8_29 CrossRefGoogle Scholar
  56. 56.
    Nipkow, T., Paulson, L.C., Wenzel, M.: Isabelle/HOL: A Proof Assistant for Higher-Order Logic. Springer, Heidelberg (2002)CrossRefzbMATHGoogle Scholar
  57. 57.
    Paulson, L.C.: A fixedpoint approach to implementing (co)inductive definitions. In: Bundy, A. (ed.) CADE 1994. LNCS, vol. 814, pp. 148–161. Springer, Heidelberg (1994). doi: 10.1007/3-540-58156-1_11 CrossRefGoogle Scholar
  58. 58.
    Paulson, L.C.: Mechanizing coinduction and corecursion in higher-order logic. J. Log. Comput. 7(2), 175–204 (1997)MathSciNetCrossRefzbMATHGoogle Scholar
  59. 59.
    Pous, D.: Coinduction all the way up. In: Grohe, M., Koskinen, E., Shankar, N. (eds.) LICS 2016, pp. 307–316. ACM (2016)Google Scholar
  60. 60.
    Reynolds, J.C.: Types, abstraction and parametric polymorphism. In: Mason, R.E.A. (ed.) IFIP 1983, pp. 513–523. North-Holland/IFIP (1983)Google Scholar
  61. 61.
    Rot, J., Bonsangue, M., Rutten, J.: Coalgebraic bisimulation-up-to. In: Emde Boas, P., Groen, F.C.A., Italiano, G.F., Nawrocki, J., Sack, H. (eds.) SOFSEM 2013. LNCS, vol. 7741, pp. 369–381. Springer, Heidelberg (2013). doi: 10.1007/978-3-642-35843-2_32 CrossRefGoogle Scholar
  62. 62.
    Rutten, J.J.M.M.: Automata and coinduction (an exercise in coalgebra). In: Sangiorgi, D., Simone, R. (eds.) CONCUR 1998. LNCS, vol. 1466, pp. 194–218. Springer, Heidelberg (1998). doi: 10.1007/BFb0055624 CrossRefGoogle Scholar
  63. 63.
    Slind, K.: Function definition in higher-order logic. In: Goos, G., Hartmanis, J., Leeuwen, J., Wright, J., Grundy, J., Harrison, J. (eds.) TPHOLs 1996. LNCS, vol. 1125, pp. 381–397. Springer, Heidelberg (1996). doi: 10.1007/BFb0105417 CrossRefGoogle Scholar
  64. 64.
    Slind, K., Norrish, M.: A brief overview of HOL4. In: Mohamed, O.A., Muñoz, C., Tahar, S. (eds.) TPHOLs 2008. LNCS, vol. 5170, pp. 28–32. Springer, Heidelberg (2008). doi: 10.1007/978-3-540-71067-7_6 CrossRefGoogle Scholar
  65. 65.
    Thibodeau, D., Cave, A., Pientka, B.: Indexed codata types. In: Sumii, E. (ed.) ICFP 2016. ACM (2016)Google Scholar
  66. 66.
    Traytel, D.: Formal languages, formally and coinductively. In: Kesner, D., Pientka, B. (eds.) FSCD. LIPIcs, vol. 52, pp. 31:1–31:17. Schloss Dagstuhl–Leibniz-Zentrum für Informatik (2016)Google Scholar
  67. 67.
    Traytel, D., Popescu, A., Blanchette, J.C.: Foundational, compositional (co)datatypes for higher-order logic: category theory applied to theorem proving. In: LICS 2012, pp. 596–605. IEEE Computer Society (2012)Google Scholar
  68. 68.
    Turner, D.A.: Elementary strong functional programming. In: Hartel, P.H., Plasmeijer, R. (eds.) FPLE 1995. LNCS, vol. 1022, pp. 1–13. Springer, Heidelberg (1995). doi: 10.1007/3-540-60675-0_35 CrossRefGoogle Scholar
  69. 69.
    Wadler, P.: Theorems for free! In: Stoy, J.E. (ed.) FPCA 1989, pp. 347–359. ACM (1989)Google Scholar
  70. 70.
    Winskel, G.: A note on model checking the modal \(\nu \)-calculus. Theor. Comput. Sci. 83(1), 157–167 (1991)MathSciNetCrossRefzbMATHGoogle Scholar

Copyright information

© Springer-Verlag GmbH Germany 2017

Authors and Affiliations

  1. 1.Vrije Universiteit AmsterdamAmsterdamThe Netherlands
  2. 2.Inria Nancy – Grand EstNancyFrance
  3. 3.Laboratoire d’informatiqueÉcole PolytechniquePalaiseauFrance
  4. 4.Department of Computer ScienceInstitute of Information SecurityETH ZürichSwitzerland
  5. 5.Department of Computer ScienceMiddlesex UniversityLondonUK
  6. 6.Institute of Mathematics Simion Stoilow of the Romanian AcademyBucharestRomania

Personalised recommendations