aboutsummaryrefslogtreecommitdiffhomepage
path: root/doc/sphinx/addendum/program.rst
blob: b685e68e43bc66f86c942755cf5815fb701b5527 (plain)
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
.. include:: ../preamble.rst
.. include:: ../replaces.rst

.. this should be just "_program", but refs to it don't work

.. _programs:

Program
========

:Author: Matthieu Sozeau

We present here the |Program| tactic commands, used to build
certified |Coq| programs, elaborating them from their algorithmic
skeleton and a rich specification :cite:`sozeau06`. It can be thought of as a
dual of :ref:`Extraction <extraction>`. The goal of |Program| is to
program as in a regular functional programming language whilst using
as rich a specification as desired and proving that the code meets the
specification using the whole |Coq| proof apparatus. This is done using
a technique originating from the “Predicate subtyping” mechanism of
PVS :cite:`Rushby98`, which generates type-checking conditions while typing a
term constrained to a particular type. Here we insert existential
variables in the term, which must be filled with proofs to get a
complete |Coq| term. |Program| replaces the |Program| tactic by Catherine
Parent :cite:`Parent95b` which had a similar goal but is no longer maintained.

The languages available as input are currently restricted to |Coq|’s
term language, but may be extended to OCaml, Haskell and
others in the future. We use the same syntax as |Coq| and permit to use
implicit arguments and the existing coercion mechanism. Input terms
and types are typed in an extended system (Russell) and interpreted
into |Coq| terms. The interpretation process may produce some proof
obligations which need to be resolved to create the final term.


.. _elaborating-programs:

Elaborating programs
---------------------

The main difference from |Coq| is that an object in a type T : Set can
be considered as an object of type { x : T | P} for any wellformed P :
Prop. If we go from T to the subset of T verifying property P, we must
prove that the object under consideration verifies it. Russell will
generate an obligation for every such coercion. In the other
direction, Russell will automatically insert a projection.

Another distinction is the treatment of pattern-matching. Apart from
the following differences, it is equivalent to the standard match
operation (see :ref:`extendedpatternmatching`).


+ Generation of equalities. A match expression is always generalized
  by the corresponding equality. As an example, the expression:

  ::

   match x with
   | 0 => t
   | S n => u
   end.

  will be first rewritten to:

  ::

   (match x as y return (x = y -> _) with
   | 0 => fun H : x = 0 -> t
   | S n => fun H : x = S n -> u
   end) (eq_refl n).

  This permits to get the proper equalities in the context of proof
  obligations inside clauses, without which reasoning is very limited.

+ Generation of inequalities. If a pattern intersects with a previous
  one, an inequality is added in the context of the second branch. See
  for example the definition of div2 below, where the second branch is
  typed in a context where ∀ p, _ <> S (S p).
+ Coercion. If the object being matched is coercible to an inductive
  type, the corresponding coercion will be automatically inserted. This
  also works with the previous mechanism.


There are options to control the generation of equalities and
coercions.

.. opt:: Program Cases

   This controls the special treatment of pattern-matching generating equalities
   and inequalities when using |Program| (it is on by default). All
   pattern-matchings and let-patterns are handled using the standard algorithm
   of |Coq| (see :ref:`extendedpatternmatching`) when this option is
   deactivated.

.. opt:: Program Generalized Coercion

   This controls the coercion of general inductive types when using |Program|
   (the option is on by default). Coercion of subset types and pairs is still
   active in this case.

.. _syntactic_control:

Syntactic control over equalities
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To give more control over the generation of equalities, the
typechecker will fall back directly to |Coq|’s usual typing of dependent
pattern-matching if a return or in clause is specified. Likewise, the
if construct is not treated specially by |Program| so boolean tests in
the code are not automatically reflected in the obligations. One can
use the dec combinator to get the correct hypotheses as in:

.. coqtop:: none

   Require Import Program Arith.

.. coqtop:: all

   Program Definition id (n : nat) : { x : nat | x = n } :=
     if dec (leb n 0) then 0
     else S (pred n).

The let tupling construct :g:`let (x1, ..., xn) := t in b` does not
produce an equality, contrary to the let pattern construct :g:`let ’(x1,
..., xn) := t in b`. Also, :g:`term :>` explicitly asks the system to
coerce term to its support type. It can be useful in notations, for
example:

.. coqtop:: all

   Notation " x `= y " := (@eq _ (x :>) (y :>)) (only parsing).

This notation denotes equality on subset types using equality on their
support types, avoiding uses of proof-irrelevance that would come up
when reasoning with equality on the subset types themselves.

The next two commands are similar to their standard counterparts
:cmd:`Definition` and :cmd:`Fixpoint`
in that they define constants. However, they may require the user to
prove some goals to construct the final definitions.


.. _program_definition:

Program Definition
~~~~~~~~~~~~~~~~~~

.. cmd:: Program Definition @ident := @term

   This command types the value term in Russell and generates proof
   obligations. Once solved using the commands shown below, it binds the
   final |Coq| term to the name ``ident`` in the environment.

   .. exn:: @ident already exists.
      :name: @ident already exists. (Program Definition)

   .. cmdv:: Program Definition @ident : @type := @term

      It interprets the type ``type``, potentially generating proof
      obligations to be resolved. Once done with them, we have a |Coq|
      type |type_0|. It then elaborates the preterm ``term`` into a |Coq|
      term |term_0|, checking that the type of |term_0| is coercible to
      |type_0|, and registers ``ident`` as being of type |type_0| once the
      set of obligations generated during the interpretation of |term_0|
      and the aforementioned coercion derivation are solved.

      .. exn:: In environment … the term: @term does not have type @type. Actually, it has type ...


   .. cmdv:: Program Definition @ident @binders : @type := @term

      This is equivalent to:

      :g:`Program Definition ident : forall binders, type := fun binders => term`.

      .. TODO refer to production in alias

See also: Sections :ref:`vernac-controlling-the-reduction-strategies`, :tacn:`unfold`

.. _program_fixpoint:

Program Fixpoint
~~~~~~~~~~~~~~~~

.. cmd:: Program Fixpoint @ident @params {? {@order}} : @type := @term

The optional order annotation follows the grammar:

.. productionlist:: orderannot
   order      : measure `term` (`term`)? | wf `term` `term`

+ :g:`measure f ( R )` where :g:`f` is a value of type :g:`X` computed on
  any subset of the arguments and the optional (parenthesised) term
  ``(R)`` is a relation on ``X``. By default ``X`` defaults to ``nat`` and ``R``
  to ``lt``.

+ :g:`wf R x` which is equivalent to :g:`measure x (R)`.

The structural fixpoint operator behaves just like the one of |Coq| (see
:cmd:`Fixpoint`), except it may also generate obligations. It works
with mutually recursive definitions too.

.. coqtop:: reset none

   Require Import Program Arith.

.. coqtop:: all

   Program Fixpoint div2 (n : nat) : { x : nat | n = 2 * x \/ n = 2 * x + 1 } :=
     match n with
     | S (S p) => S (div2 p)
     | _ => O
     end.

Here we have one obligation for each branch (branches for :g:`0` and
``(S 0)`` are automatically generated by the pattern-matching
compilation algorithm).

.. coqtop:: all

   Obligation 1.

.. coqtop:: reset none

   Require Import Program Arith.

One can use a well-founded order or a measure as termination orders
using the syntax:

.. coqtop:: in

   Program Fixpoint div2 (n : nat) {measure n} : { x : nat | n = 2 * x \/ n = 2 * x + 1 } :=
     match n with
     | S (S p) => S (div2 p)
     | _ => O
     end.



.. caution:: When defining structurally recursive functions, the generated
   obligations should have the prototype of the currently defined
   functional in their context. In this case, the obligations should be
   transparent (e.g. defined using :g:`Defined`) so that the guardedness
   condition on recursive calls can be checked by the kernel’s type-
   checker. There is an optimization in the generation of obligations
   which gets rid of the hypothesis corresponding to the functional when
   it is not necessary, so that the obligation can be declared opaque
   (e.g. using :g:`Qed`). However, as soon as it appears in the context, the
   proof of the obligation is *required* to be declared transparent.

   No such problems arise when using measures or well-founded recursion.

.. _program_lemma:

Program Lemma
~~~~~~~~~~~~~

.. cmd:: Program Lemma @ident : @type

   The Russell language can also be used to type statements of logical
   properties. It will generate obligations, try to solve them
   automatically and fail if some unsolved obligations remain. In this
   case, one can first define the lemma’s statement using :g:`Program
   Definition` and use it as the goal afterwards. Otherwise the proof
   will be started with the elaborated version as a goal. The
   :g:`Program` prefix can similarly be used as a prefix for
   :g:`Variable`, :g:`Hypothesis`, :g:`Axiom` etc...

.. _solving_obligations:

Solving obligations
--------------------

The following commands are available to manipulate obligations. The
optional identifier is used when multiple functions have unsolved
obligations (e.g. when defining mutually recursive blocks). The
optional tactic is replaced by the default one if not specified.

.. cmd:: {? Local|Global} Obligation Tactic := @tactic
   :name: Obligation Tactic

   Sets the default obligation solving tactic applied to all obligations
   automatically, whether to solve them or when starting to prove one,
   e.g. using :g:`Next`. :g:`Local` makes the setting last only for the current
   module. Inside sections, local is the default.

.. cmd:: Show Obligation Tactic

   Displays the current default tactic.

.. cmd:: Obligations {? of @ident}

   Displays all remaining obligations.

.. cmd:: Obligation num {? of @ident}

   Start the proof of obligation num.

.. cmd:: Next Obligation {? of @ident}

   Start the proof of the next unsolved obligation.

.. cmd:: Solve Obligations {? of @ident} {? with @tactic}

   Tries to solve each obligation of ``ident`` using the given ``tactic`` or the default one.

.. cmd:: Solve All Obligations {? with @tactic}

   Tries to solve each obligation of every program using the given
   tactic or the default one (useful for mutually recursive definitions).

.. cmd:: Admit Obligations {? of @ident}

   Admits all obligations (of ``ident``).

   .. note:: Does not work with structurally recursive programs.

.. cmd:: Preterm {? of @ident}

   Shows the term that will be fed to the kernel once the obligations
   are solved. Useful for debugging.

.. opt:: Transparent Obligations

   Control whether all obligations should be declared as transparent
   (the default), or if the system should infer which obligations can be
   declared opaque.

.. opt:: Hide Obligations

   Control whether obligations appearing in the
   term should be hidden as implicit arguments of the special
   constantProgram.Tactics.obligation.

.. opt:: Shrink Obligations

   *Deprecated since 8.7*

   This option (on by default) controls whether obligations should have
   their context minimized to the set of variables used in the proof of
   the obligation, to avoid unnecessary dependencies.

The module :g:`Coq.Program.Tactics` defines the default tactic for solving
obligations called :g:`program_simpl`. Importing :g:`Coq.Program.Program` also
adds some useful notations, as documented in the file itself.

.. _program-faq:

Frequently Asked Questions
---------------------------


.. exn:: Ill-formed recursive definition.

  This error can happen when one tries to define a function by structural
  recursion on a subset object, which means the |Coq| function looks like:

  ::

     Program Fixpoint f (x : A | P) := match x with A b => f b end.

  Supposing ``b : A``, the argument at the recursive call to ``f`` is not a
  direct subterm of ``x`` as ``b`` is wrapped inside an ``exist`` constructor to
  build an object of type ``{x : A | P}``.  Hence the definition is
  rejected by the guardedness condition checker.  However one can use
  wellfounded recursion on subset objects like this:

  ::

     Program Fixpoint f (x : A | P) { measure (size x) } :=
       match x with A b => f b end.

  One will then just have to prove that the measure decreases at each
  recursive call. There are three drawbacks though:

    #. A measure function has to be defined;
    #. The reduction is a little more involved, although it works well
       using lazy evaluation;
    #. Mutual recursion on the underlying inductive type isn’t possible
       anymore, but nested mutual recursion is always possible.

.. bibliography:: ../biblio.bib
   :keyprefix: p-