File: coinductive.rst

package info (click to toggle)
coq-doc 8.16.1-1
  • links: PTS, VCS
  • area: non-free
  • in suites: bookworm
  • size: 42,788 kB
  • sloc: ml: 219,673; sh: 4,035; python: 3,372; ansic: 2,529; makefile: 728; lisp: 279; javascript: 87; xml: 24; sed: 2
file content (204 lines) | stat: -rw-r--r-- 7,905 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
Coinductive types and corecursive functions
=============================================

.. _coinductive-types:

Coinductive types
------------------

The objects of an inductive type are well-founded with respect to the
constructors of the type. In other words, such objects contain only a
*finite* number of constructors. Coinductive types arise from relaxing
this condition, and admitting types whose objects contain an infinity of
constructors. Infinite objects are introduced by a non-ending (but
effective) process of construction, defined in terms of the constructors
of the type.

More information on coinductive definitions can be found in
:cite:`Gimenez95b,Gim98,GimCas05`.

.. cmd:: CoInductive @inductive_definition {* with @inductive_definition }
         CoInductive @record_definition {* with @record_definition }

   This command introduces a coinductive type.
   The syntax of the command is the same as the command :cmd:`Inductive`.
   No principle of induction is derived from the definition of a coinductive
   type, since such principles only make sense for inductive types.
   For coinductive types, the only elimination principle is case analysis.

   This command supports the :attr:`universes(polymorphic)`,
   :attr:`universes(template)`, :attr:`universes(cumulative)`,
   :attr:`private(matching)`, :attr:`bypass_check(universes)`,
   :attr:`bypass_check(positivity)` and :attr:`using` attributes.

   When record syntax is used, this command also supports the
   :attr:`projections(primitive)` :term:`attribute`.

.. example::

   The type of infinite sequences of natural numbers, usually called streams,
   is an example of a coinductive type.

   .. coqtop:: in

      CoInductive Stream : Set := Seq : nat -> Stream -> Stream.

   The usual destructors on streams :g:`hd:Stream->nat` and :g:`tl:Str->Str`
   can be defined as follows:

   .. coqtop:: in

      Definition hd (x:Stream) := let (a,s) := x in a.
      Definition tl (x:Stream) := let (a,s) := x in s.

Definitions of coinductive predicates and blocks of mutually
coinductive definitions are also allowed.

.. example::

   The extensional equality on streams is an example of a coinductive type:

   .. coqtop:: in

      CoInductive EqSt : Stream -> Stream -> Prop :=
        eqst : forall s1 s2:Stream,
                 hd s1 = hd s2 -> EqSt (tl s1) (tl s2) -> EqSt s1 s2.

   In order to prove the extensional equality of two streams :g:`s1` and :g:`s2`
   we have to construct an infinite proof of equality, that is, an infinite
   object of type :g:`(EqSt s1 s2)`. We will see how to introduce infinite
   objects in Section :ref:`cofixpoint`.

Caveat
~~~~~~

The ability to define coinductive types by constructors, hereafter called
*positive coinductive types*, is known to break subject reduction. The story is
a bit long: this is due to dependent pattern-matching which implies
propositional η-equality, which itself would require full η-conversion for
subject reduction to hold, but full η-conversion is not acceptable as it would
make type checking undecidable.

Since the introduction of primitive records in Coq 8.5, an alternative
presentation is available, called *negative coinductive types*. This consists
in defining a coinductive type as a primitive record type through its
projections. Such a technique is akin to the *copattern* style that can be
found in e.g. Agda, and preserves subject reduction.

The above example can be rewritten in the following way.

.. coqtop:: none

   Reset Stream.

.. coqtop:: all

   Set Primitive Projections.
   CoInductive Stream : Set := Seq { hd : nat; tl : Stream }.
   CoInductive EqSt (s1 s2: Stream) : Prop := eqst {
     eqst_hd : hd s1 = hd s2;
     eqst_tl : EqSt (tl s1) (tl s2);
   }.

Some properties that hold over positive streams are lost when going to the
negative presentation, typically when they imply equality over streams.
For instance, propositional η-equality is lost when going to the negative
presentation. It is nonetheless logically consistent to recover it through an
axiom.

.. coqtop:: all

   Axiom Stream_eta : forall s: Stream, s = Seq (hd s) (tl s).

More generally, as in the case of positive coinductive types, it is consistent
to further identify extensional equality of coinductive types with propositional
equality:

.. coqtop:: all

   Axiom Stream_ext : forall (s1 s2: Stream), EqSt s1 s2 -> s1 = s2.

As of Coq 8.9, it is now advised to use negative coinductive types rather than
their positive counterparts.

.. seealso::
   :ref:`primitive_projections` for more information about negative
   records and primitive projections.

.. index::
   single: cofix

Co-recursive functions: cofix
-----------------------------

.. insertprodn term_cofix cofix_body

.. prodn::
   term_cofix ::= let cofix @cofix_body in @term
   | cofix @cofix_body {? {+ with @cofix_body } for @ident }
   cofix_body ::= @ident {* @binder } {? : @type } := @term

The expression
":n:`cofix @ident__1 @binder__1 : @type__1 with … with @ident__n @binder__n : @type__n for @ident__i`"
denotes the :math:`i`-th component of a block of terms defined by a mutual guarded
corecursion. It is the local counterpart of the :cmd:`CoFixpoint` command. When
:math:`n=1`, the ":n:`for @ident__i`" clause is omitted.

.. _cofixpoint:

Top-level definitions of corecursive functions
-----------------------------------------------

.. cmd:: CoFixpoint @cofix_definition {* with @cofix_definition }

   .. insertprodn cofix_definition cofix_definition

   .. prodn::
      cofix_definition ::= @ident_decl {* @binder } {? : @type } {? := @term } {? @decl_notations }

   This command introduces a method for constructing an infinite object of a
   coinductive type. For example, the stream containing all natural numbers can
   be introduced by applying the following method to the number :g:`O` (see
   Section :ref:`coinductive-types` for the definition of :g:`Stream`, :g:`hd`
   and :g:`tl`):

   .. coqtop:: all

      CoFixpoint from (n:nat) : Stream := Seq n (from (S n)).

   Unlike recursive definitions, there is no decreasing argument in a
   corecursive definition. To be admissible, a method of construction must
   provide at least one extra constructor of the infinite object for each
   iteration. A syntactical guard condition is imposed on corecursive
   definitions in order to ensure this: each recursive call in the
   definition must be protected by at least one constructor, and only by
   constructors. That is the case in the former definition, where the single
   recursive call of :g:`from` is guarded by an application of :g:`Seq`.
   On the contrary, the following recursive function does not satisfy the
   guard condition:

   .. coqtop:: all

      Fail CoFixpoint filter (p:nat -> bool) (s:Stream) : Stream :=
        if p (hd s) then Seq (hd s) (filter p (tl s)) else filter p (tl s).

   The elimination of corecursive definition is done lazily, i.e. the
   definition is expanded only when it occurs at the head of an application
   which is the argument of a case analysis expression. In any other
   context, it is considered as a canonical expression which is completely
   evaluated. We can test this using the command :cmd:`Eval`, which computes
   the normal forms of a term:

   .. coqtop:: all

      Eval compute in (from 0).
      Eval compute in (hd (from 0)).
      Eval compute in (tl (from 0)).

   As in the :cmd:`Fixpoint` command, the :n:`with` clause allows simultaneously
   defining several mutual cofixpoints.

   If :n:`@term` is omitted, :n:`@type` is required and Coq enters proof mode.
   This can be used to define a term incrementally, in particular by relying on the :tacn:`refine` tactic.
   In this case, the proof should be terminated with :cmd:`Defined` in order to define a :term:`constant`
   for which the computational behavior is relevant.  See :ref:`proof-editing-mode`.