(** printing \2/ $\cup$ #&cup;# *)
(** printing <2= $\subseteq$ #&sube;# *)
(** printing forall $\forall$ #&forall;# *)
(** printing -> $\rightarrow$ #&rarr;# *)
(** printing /\ $\land$ #&and;# *)
(** * Illustrating the [paco] library  This tutorial shows how to use our [paco] library to reason about coinductive predicates in Coq.  By coinductive predicates we mean objects that one can define using [CoInductive] and whose type ends in [Prop].  The library implements _parameterized coinduction_, as described in our draft paper entitled #<a href=" http://plv.mpi-sws.org/paco/"># _The Power of Parameterization in Coinductive Proof_ #</a>#.  How does parameterized coinduction compare to Coq's existing support for coinductive proofs?  For proofs by _induction_, Coq provides a tactic called [fix], but proofs done directly with [fix] are required to satisfy a _syntactic guardedness_ criterion.  Fortunately, Coq also generates induction _lemmas_ for every inductive definition, which eliminate the need to ever use the low-level [fix] tactic and worry about guardedness.  For proofs by coinduction, Coq provides a tactic [cofix] analogous to [fix], i.e., also based on a syntactic guardedness criterion.  However, Coq does not generate any lemmas for coinductive definitions.  Consequently, to reason about such definitions, the user must use the low-level [cofix] tactic.  Due to its syntactic nature, [cofix] is problematic in several ways (please see the paper linked above for detailed discussion of these points):  - It is non-compositional. - It is inefficient. - It is not user-friendly. - It interacts poorly with builtin automation tactics.   The [paco] library provides a tactic, [pcofix], which can be seen as a replacement for Coq's builtin [cofix] tactic (in the case of predicates) that does not involve any syntactic guardedness criterion and thus avoids all of these problems.  In addition, like Coq's [cofix], [pcofix] provides built-in support for _incremental_ proofs, i.e., proofs in which the coinduction hypothesis is extended gradually as the proof progresses.  We believe this combination of compositionality, incrementality, robustness, and ease of use makes [pcofix] a superior alternative to [cofix] for proofs about coinductive predicates.  The rest of this tutorial illustrates the use of the [paco] library with the help of three examples. *)(* *)
(** ** Example: stream equality  The first example involves streams of natural numbers and an equality thereon.  We prove a particular equality via [cofix], and then explain how that proof can be turned into one via [pcofix]. *)
(** We start by defining a type of streams of natural numbers. *)
CoInductive stream :=
| cons : nat -> stream -> stream.
(** The following, seemingly useless, lemma is a common trick for working with corecursive terms such as our streams.  (It will be used in the example proofs.)  For details, see for instance #<a href="http://adam.chlipala.net/cpdt/html/Coinductive.html">Adam Chlipala's book on Certified Programming with Dependent Types</a>#. *)
Definition sunf s :=
match s with cons n s' => cons n s' end.
(** In order to state our example equality, we define an enumeration stream and a map operation for streams. *)
CoFixpoint enumerate n : stream :=
cons n (enumerate (S n)).
CoFixpoint map f s : stream :=
match s with cons n s' => cons (f n) (map f s') end.
(** *** A proof using [cofix]  We will now prove, using [cofix], that for any [n] the stream [enumerate n] is equal to the stream [cons n (map S (enumerate n))]. *)
(** First, we define an equality [seq] on streams.  Usually, one would do this as follows.  [CoInductive seq : stream -> stream -> Prop :=] #<br># [  | seq_fold : forall n s1 s2 (R : seq s1 s2), seq (cons n s1) (cons n s2).]  Instead, we define the generating function, [seq_gen], beforehand, and then define [seq] as its greatest fixed point using [CoInductive].  The reason is simply that we need [seq_gen] later when using [paco].  If applying parameterized coinduction to an existing development where the generating function is not explicit, it can always easily be made explicit.  Note that, albeit the use of [Inductive], the definition of [seq_gen] is not recursive. *)
Inductive seq_gen seq : stream -> stream -> Prop :=
| _seq_gen : forall n s1 s2 (R : seq s1 s2 : Prop), seq_gen seq (cons n s1) (cons n s2).
Hint Constructors seq_gen.
CoInductive seq : stream -> stream -> Prop :=
| seq_fold : forall s1 s2, seq_gen seq s1 s2 -> seq s1 s2.
(** Second, we do the actual proof. *)

Theorem example : forall n, seq (enumerate n) (cons n (map S (enumerate n))).