File: records.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 (446 lines) | stat: -rw-r--r-- 17,878 bytes parent folder | download
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
.. _record-types:

Record types
------------

The :cmd:`Record` command defines types similar to :gdef:`records`
in programming languages. Those types describe tuples whose
components, called :gdef:`fields <field>`, can be accessed with
:gdef:`projections <projection>`. Records can also be used to describe
mathematical structures, such as groups or rings, hence the
synonym :cmd:`Structure`.

Defining record types
~~~~~~~~~~~~~~~~~~~~~

.. _record_grammar:

.. cmd:: {| Record | Structure } @record_definition
   :name: Record; Structure

   .. insertprodn record_definition field_spec

   .. prodn::
      record_definition ::= {? > } @ident_decl {* @binder } {? : @sort } {? := {? @ident } %{ {*; @record_field } {? ; } %} {? as @ident } }
      record_field ::= {* #[ {*, @attribute } ] } @name {? @field_spec } {? %| @natural }
      field_spec ::= {* @binder } @of_type
      | {* @binder } := @term
      | {* @binder } @of_type := @term

   Defines a non-recursive record type, creating projections for each field
   that has a name other than `_`. The field body and type can depend on previous
   fields, so the order of fields in the definition may matter.

   Use the :cmd:`Inductive` and :cmd:`CoInductive` commands to define recursive
   (inductive or coinductive) records.  These commands also permit defining
   mutually recursive records provided that all of
   the types in the block are records.  These commands automatically generate
   induction schemes.  Enable the :flag:`Nonrecursive Elimination Schemes` flag
   to enable automatic generation of elimination schemes for :cmd:`Record`.
   See :ref:`proofschemes-induction-principles`.

   The :cmd:`Class` command can be used to define records that are also
   :ref:`typeclasses`, which permit Coq to automatically infer the inhabitants of
   the record.

   :n:`{? > }`
     If specified, the constructor is declared as
     a coercion from the class of the last field type to the record name.
     See :ref:`coercions`.

   :n:`@ident_decl`
     The :n:`@ident` within is the record name.

   :n:`{* @binder }`
     :n:`@binder`\s may be used to declare the
     :term:`inductive parameters <inductive parameter>` of the record.

   :n:`: @sort`
     The sort the record belongs to.  The default is :n:`Type`.

   :n:`:= {? @ident }`
     :n:`@ident` is the name of the record constructor.  If omitted,
     the name defaults to :n:`Build_@ident` where :n:`@ident` is the record name.

   :n:`as {? @ident}`
     Specifies the name used to refer to the argument corresponding to the
     record in the type of projections.  If not specified, the name is the first
     letter of the record name converted to lowercase (see :ref:`example <record_as_clause>`).
     In constrast, :cmd:`Class` command uses the record name as the default
     (see :ref:`example <class_arg_name>`).

   In :n:`@record_field`:

     :n:`@attribute`, if specified, can only be :attr:`canonical`.

     :n:`@name` is the field name.  Since field names define projections, you can't
     reuse the same field name in two different records in the same module.  This
     :ref:`example <reuse_field_name>` shows how to reuse the same field
     name in multiple records.

     :n:`@field_spec` can be omitted only when the type of the field can be inferred
     from other fields. For example: the type of :n:`n` can be inferred from
     :n:`npos` in :n:`Record positive := { n; npos : 0 < n }`.

     :n:`| @natural`
       Specifies the priority of the field.  It is only allowed in :cmd:`Class` commands.

   In :n:`@field_spec`:

     :n:`:>` in :n:`@of_type`
       If specified, the field is declared as a coercion from the record name
       to the class of the field type. See :ref:`coercions`.
       Note that this currently does something else in :cmd:`Class` commands.

     - :n:`{+ @binder } : @of_type` is equivalent to
       :n:`: forall {+ @binder } , @of_type`

     - :n:`{+ @binder } := @term` is equivalent to
       :n:`:= fun {+ @binder } => @term`

     - :n:`{+ @binder } @of_type := @term` is equivalent to
       :n:`: forall {+ @binder } , @type := fun {+ @binder } => @term`

     :n:`:= @term`, if present, gives the value of the field, which may depend
     on the fields that appear before it.  Since their values are already defined,
     such fields cannot be specified when constructing a record.

   The :cmd:`Record` command supports the :attr:`universes(polymorphic)`,
   :attr:`universes(template)`, :attr:`universes(cumulative)`,
   :attr:`private(matching)` and :attr:`projections(primitive)` attributes.

   .. example:: Defining a record

      The set of rational numbers may be defined as:

      .. coqtop:: reset all

         Record Rat : Set := mkRat
          { negative : bool
          ; top : nat
          ; bottom : nat
          ; Rat_bottom_nonzero : 0 <> bottom
          ; Rat_irreducible :
              forall x y z:nat, (x * y) = top /\ (x * z) = bottom -> x = 1
          }.

      The :n:`Rat_*` fields depend on :n:`top` and :n:`bottom`.
      :n:`Rat_bottom_nonzero` is a proof that :n:`bottom` (the denominator)
      is not zero.  :n:`Rat_irreducible` is a proof that the fraction is in
      lowest terms.

.. _reuse_field_name:

   .. example:: Reusing a field name in multiple records

      .. coqtop:: in

         Module A. Record R := { f : nat }. End A.
         Module B. Record S := { f : nat }. End B.

      .. coqtop:: all

         Check {| A.f := 0 |}.
         Check {| B.f := 0 |}.

.. _record_as_clause:

   .. example:: Using the "as" clause in a record definition

      .. coqtop:: all

         Record MyRecord := { myfield : nat } as VarName.
         About myfield. (* observe the MyRecord variable is named "VarName" *)

         (* make "VarName" implicit without having to rename the variable,
            which would be necessary without the "as" clause *)
         Arguments myfield {VarName}.   (* make "VarName" an implicit parameter *)
         Check myfield.
         Check (myfield (VarName:={| myfield := 0 |})).

.. _class_arg_name:

   .. example:: Argument name for a record type created using :cmd:`Class`

      Compare to :cmd:`Record` in the previous example:

      .. coqtop:: all

         Class MyClass := { myfield2 : nat }.
         About myfield2. (* Argument name defaults to the class name and is marked implicit *)

   .. exn:: Records declared with the keyword Record or Structure cannot be recursive.

      The record name :token:`ident` appears in the type of its fields, but uses
      the :cmd:`Record` command. Use  the :cmd:`Inductive` or
      :cmd:`CoInductive` command instead.

   .. exn:: @ident already exists

      The fieldname :n:`@ident` is already defined as a global.

   .. warn:: @ident__1 cannot be defined because the projection @ident__2 was not defined

      The type of the projection :n:`@ident__1` depends on previous projections which
      themselves could not be defined.

   .. warn:: @ident cannot be defined.

      The projection cannot be defined.  This message is followed by an explanation
      of why it's not possible, such as:

      #. The :term:`body` of :token:`ident` uses an incorrect elimination for
         :token:`ident` (see :cmd:`Fixpoint` and :ref:`Destructors`).

   .. warn:: @ident__field cannot be defined because it is informative and @ident__record is not

      The projection for the named field :n:`@ident__field` can't be defined.
      For example, :n:`Record R:Prop := { f:nat }` generates the message
      "f cannot be defined ... and R is not".  Records of sort :n:`Prop`
      must be non-informative (i.e. indistinguishable).  Since :n:`nat`
      has multiple inhabitants, such as :n:`%{%| f := 0 %|%}` and
      :n:`%{%| f := 1 %|%}`, the record would be informative and therefore the
      projection can't be defined.

   .. seealso:: Coercions and records in section :ref:`coercions-classes-as-records`.

   .. todo below: Need a better description for Variant and primitive projections.
      Hugo says "the model to think about primitive projections is not fully stabilized".

   .. note:: Records exist in two flavors. In the first,
      a record :n:`@ident` with parameters :n:`{* @binder }`,
      constructor :n:`@ident__0`, and fields :n:`{* @name @field_spec }`
      is represented as a variant type with a single
      constructor: :n:`Variant @ident {* @binder } : @sort := @ident__0
      {* ( @name @field_spec ) }` and projections are defined by case analysis.
      In the second implementation, records have
      primitive projections: see :ref:`primitive_projections`.

   During the definition of the one-constructor inductive definition, all
   the errors of inductive definitions, as described in Section
   :ref:`gallina-inductive-definitions`, may also occur.

Constructing records
~~~~~~~~~~~~~~~~~~~~

   .. insertprodn term_record field_val

   .. prodn::
      term_record ::= %{%| {*; @field_val } {? ; } %|%}
      field_val ::= @qualid {* @binder } := @term

   Instances of record types can be constructed using either *record form*
   (:n:`@term_record`, shown here) or *application form* (see :n:`@term_application`)
   using the constructor.  The associated record definition is selected using the
   provided field names or constructor name, both of which are global.

   In the record form, the fields can be given in any order.  Fields that can be
   inferred by unification or by using obligations (see :ref:`programs`) may be omitted.

   In application form, all fields of the record must be passed, in order,
   as arguments to the constructor.

   .. example:: Constructing 1/2 as a record

      Constructing the rational :math:`1/2` using either the record or application syntax:

      .. coqtop:: in

         Theorem one_two_irred : forall x y z:nat, x * y = 1 /\ x * z = 2 -> x = 1.
         Admitted.

         (* Record form: top and bottom can be inferred from other fields *)
         Definition half :=
           {| negative := false;
              Rat_bottom_nonzero := O_S 1;
              Rat_irreducible := one_two_irred |}.

         (* Application form: use the constructor and provide values for all the fields
            in order.  "mkRat" is defined by the Record command *)
         Definition half' := mkRat true 1 2 (O_S 1) one_two_irred.

Accessing fields (projections)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

   .. insertprodn term_projection term_projection

   .. prodn::
      term_projection ::= @term0 .( @qualid {? @univ_annot } {* @arg } )
      | @term0 .( @ @qualid {? @univ_annot } {* @term1 } )

   The value of a field can be accessed using *projection form* (:n:`@term_projection`,
   shown here) or with *application form* (see :n:`@term_application`) using the
   projection function associated with the field.  Don't forget the parentheses for the
   projection form.
   Glossing over some syntactic details, the two forms are:

   - :n:`@qualid__record.( {? @ } @qualid__field {* @arg })`   (projection) and

   - :n:`{? @ } @qualid__field {* @arg } @qualid__record`   (application)

   where the :n:`@arg`\s are the parameters of the inductive type.  If :n:`@` is
   specified, all implicit arguments must be provided.

   In projection form, since the projected object is part of the notation, it is always
   considered an explicit argument of :token:`qualid`, even if it is
   formally declared as implicit (see :ref:`ImplicitArguments`).

   .. example:: Accessing record fields

      .. coqtop:: all

         (* projection form *)
         Eval compute in half.(top).

         (* application form *)
         Eval compute in top half.

   .. example:: Matching on records

      .. coqtop:: all

         Eval compute in (
           match half with
           | {| negative := false; top := n |} => n
           | _ => 0
           end).

   .. example:: Accessing anonymous record fields with match

      .. coqtop:: in

         Record T := const { _ : nat }.
         Definition gett x := match x with const n => n end.
         Definition inst := const 3.

      .. coqtop:: all

         Eval compute in gett inst.

Settings for printing records
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The following settings let you control the display format for record types:

.. flag:: Printing Records

   When this :term:`flag` is on (this is the default),
   use the record syntax (shown above) as the default display format.

You can override the display format for specified record types by adding entries to these tables:

.. table:: Printing Record @qualid

   This :term:`table` specifies a set of qualids which are displayed as records.  Use the
   :cmd:`Add` and :cmd:`Remove` commands to update the set of qualids.

.. table:: Printing Constructor @qualid

   This :term:`table` specifies a set of qualids which are displayed as constructors.  Use the
   :cmd:`Add` and :cmd:`Remove` commands to update the set of qualids.

.. flag:: Printing Projections

   Activates the projection form (dot notation) for printing projections (off by default).

   .. example::

      .. coqtop:: all

         Check top half.  (* off: application form *)
         Set Printing Projections.
         Check top half.  (* on:  projection form *)

.. _primitive_projections:

Primitive Projections
~~~~~~~~~~~~~~~~~~~~~

Note: the design of primitive projections is still evolving.

When the :flag:`Primitive Projections` flag is on or the
:attr:`projections(primitive)` attribute is supplied for a :cmd:`Record` definition, its
:g:`match` construct is disabled. To eliminate the record type, one must
use its defined primitive projections.

For compatibility, the parameters still appear when printing terms
even though they are absent in the actual AST manipulated by the kernel. This
can be changed by unsetting the :flag:`Printing Primitive Projection Parameters`
flag.

There are currently two ways to introduce primitive records types:

#. Through the :cmd:`Record` command, in which case the type has to be
   non-recursive. The defined type enjoys eta-conversion definitionally,
   that is the generalized form of surjective pairing for records:
   `r` ``= Build_``\ `R` ``(``\ `r`\ ``.(``\ |p_1|\ ``) …`` `r`\ ``.(``\ |p_n|\ ``))``.
   Eta-conversion allows to define dependent elimination for these types as well.
#. Through the :cmd:`Inductive` and :cmd:`CoInductive` commands, when
   the :term:`body` of the definition is a record declaration of the form
   ``Build_``\ `R` ``{`` |p_1| ``:`` |t_1|\ ``; … ;`` |p_n| ``:`` |t_n| ``}``.
   In this case the types can be recursive and eta-conversion is disallowed.
   Dependent elimination is not available for such types;
   you must use non-dependent case analysis for these.

For both cases the :flag:`Primitive Projections` :term:`flag` must be set or
the :attr:`projections(primitive)` :term:`attribute`  must be supplied.

.. flag:: Primitive Projections

   This :term:`flag` turns on the use of primitive projections when defining
   subsequent records (even through the :cmd:`Inductive` and :cmd:`CoInductive`
   commands). Primitive projections extend the Calculus of Inductive
   Constructions with a new binary term constructor `r.(p)` representing a
   primitive projection `p` applied to a record object `r` (i.e., primitive
   projections are always applied). Even if the record type has parameters,
   these do not appear in the internal representation of applications of the
   projection, considerably reducing the sizes of terms when manipulating
   parameterized records and type checking time. On the user level, primitive
   projections can be used as a replacement for the usual defined ones, although
   there are a few notable differences.

.. attr:: projections(primitive{? = {| yes | no } })
   :name: projections(primitive)

   This :term:`boolean attribute` can be used to override the value of the
   :flag:`Primitive Projections` :term:`flag` for the record type being
   defined.

.. flag:: Printing Primitive Projection Parameters

   This compatibility :term:`flag` reconstructs internally omitted parameters at
   printing time (even though they are absent in the actual AST manipulated
   by the kernel).

Reduction
+++++++++

The basic reduction rule of a primitive projection is
|p_i| ``(Build_``\ `R` |t_1| … |t_n|\ ``)`` :math:`{\rightarrow_{\iota}}` |t_i|.
However, to take the δ flag into account, projections can be in two states:
folded or unfolded. An unfolded primitive projection application obeys the rule
above, while the folded version delta-reduces to the unfolded version. This
allows to precisely mimic the usual unfolding rules of :term:`constants <constant>`.
Projections obey the usual ``simpl`` flags of the :cmd:`Arguments`
command in particular.
There is currently no way to input unfolded primitive projections at the
user-level, and there is no way to display unfolded projections differently
from folded ones.


Compatibility Projections and :g:`match`
++++++++++++++++++++++++++++++++++++++++

To ease compatibility with ordinary record types, each primitive projection is
also defined as an ordinary :term:`constant` taking parameters and an object of
the record type as arguments, and whose :term:`body` is an application of the
unfolded primitive projection of the same name. These constants are used when
elaborating partial applications of the projection. One can distinguish them
from applications of the primitive projection if the :flag:`Printing Primitive
Projection Parameters` flag is off: For a primitive projection application,
parameters are printed as underscores while for the compatibility projections
they are printed as usual.

Additionally, user-written :g:`match` constructs on primitive records are
desugared into substitution of the projections, they cannot be printed back as
:g:`match` constructs.