@@ -48,11 +48,11 @@ From Equations Require Import Equations.
48
48
Indexed inductive types are particular kind of inductive definitions
49
49
that consist in defining not one single inductive type but a family
50
50
of linked inductive types.
51
- The most well-known example of indexed inductive types are vectors.
51
+ On of the most well-known examples of indexed inductive types are vectors.
52
52
Given a fixed parameter [A : Type], vectors define a familly of inductive
53
53
types [vec A n : Type] indexed by natural numbers [n : nat] representing
54
54
the lengths of the vectors.
55
- Vectors have two constructor .
55
+ The Vector type has two constructors .
56
56
The first constructor [vnil : vec A 0] represent the empty vector,
57
57
logically of size [0].
58
58
Given an element [a:A] and a vector [v : vec A n] of size [n], the
@@ -73,17 +73,20 @@ Arguments vcons {_} _ _ _.
73
73
For instance, in the definition of vectors the type [A] is a parameter
74
74
as it is constant in all the constructors, but [n:nat] is an index as
75
75
[vcons] relates two different types of the family, [vec A n] and [vec A (S n)].
76
+ Indices always appear after the [:] in an inductive type declaration.
76
77
77
78
Reasoning about indexed inductive types like vectors is a bit more
78
79
involved than for basic inductive types like lists as the indices can
79
80
matter.
80
81
Noticeably pattern matching on constructors of indexed inductive types
81
- like [vec n A ] may particularise the indices.
82
+ like [vec A n ] may particularise the indices.
82
83
For instance, matching a vector [v : vec A n] to [vnil] forces the
83
- value [n] to be [0] and to [vcons] to be of the form [S m] for some integer [m].
84
+ value [n] to be [0] while for [vcons] if forces [n] to be of the form
85
+ [S m] for some integer [m].
84
86
Consequently, when writing a function on an indexed inductive type,
85
- we must also specify the form of the indices when pattern matching.
86
-
87
+ pattern-matching on the inductive type has an effect on other arguments
88
+ of the function, specializing them.
89
+
87
90
For instance, consider the definition of [vmap] and [vapp] :
88
91
*)
89
92
@@ -93,10 +96,12 @@ vmap f _ (vcons a n v) := vcons (f a) n (vmap f n v).
93
96
94
97
Print vmap.
95
98
96
- Equations vapp {A} (n : nat) (v : vec A n ) (m : nat) (v' : vec A m) : vec A (n +m) :=
99
+ Equations vapp {A} (na : nat) (v : vec A na ) (m : nat) (v' : vec A m) : vec A (na +m) :=
97
100
vapp 0 vnil m v' := v';
98
101
vapp (S n) (vcons a n v) m v' := vcons a (n+m) (vapp n v m v').
99
102
103
+ (* Here the only two possibly well-typed patterns when considering the [vnil] and [vcons]
104
+ constructors are respectively with [na = 0] and [na = S n] for some fresh [n] variable. *)
100
105
101
106
(** Reasoning on indexed inductive is not very different from reasoning
102
107
on regular inductive types except that we have to account for indices,
@@ -144,7 +149,7 @@ Proof.
144
149
cbn.
145
150
(* We can now simplify *)
146
151
simp vmap vapp. now rewrite H.
147
- Abort .
152
+ Qed .
148
153
149
154
(** This is not a limitation of [Equations] itself. It is due to how the
150
155
[rewrite] tactic behind [simp] unifies terms.
@@ -179,7 +184,7 @@ vapp' (vcons a v) v' := vcons a (vapp' v v').
179
184
As an example, let's reprove [vmap_vapp] :
180
185
*)
181
186
182
- Definition vmap_vapp {A B n m }(f : A -> B) (v : vec A n) (v' : vec A m) :
187
+ Definition vmap_vapp' {A B n m }(f : A -> B) (v : vec A n) (v' : vec A m) :
183
188
vmap' f (vapp' v v') = vapp' (vmap' f v) (vmap' f v').
184
189
Proof .
185
190
funelim (vmap' f v).
@@ -195,6 +200,20 @@ Proof.
195
200
simp vmap' vapp'. f_equal. apply H.
196
201
Abort .
197
202
203
+ (** An alternative is to change the way [rewrite] looks for matching subterms
204
+ in the goal, using the keyed unification strategy. With this setting, [rewrite (e : t = u)]
205
+ looks for a syntactic match for the head of [t] in the goal but allows full
206
+ conversion between arguments of [t] and the arguments of the matched application
207
+ in the goal. This makes [simp] work up-to conversion of the indices.
208
+ We can then directly call [congruence] to solve the induction case. *)
209
+
210
+ #[local] Set Keyed Unification.
211
+
212
+ Definition vmap_vapp_simp {A B n m }(f : A -> B) (v : vec A n) (v' : vec A m) :
213
+ vmap' f (vapp' v v') = vapp' (vmap' f v) (vmap' f v').
214
+ Proof .
215
+ funelim (vmap' f v); simp vmap' vapp'; [reflexivity|congruence].
216
+ Qed .
198
217
199
218
(** ** 2. Advanced Dependent Pattern Matching
200
219
@@ -204,8 +223,8 @@ Abort.
204
223
can have advantages.
205
224
Most noticeably, it can be used to exclude invalid cases automatically.
206
225
For instance, consider the function tail that returns the last element.
207
- In the case of [list], the [tail] function had to return a term of type
208
- [option A] as were no insurance that the input would not be the empty list.
226
+ In the case of [list], the [tail] function has to return a term of type
227
+ [option A] as there is no guarantee that the input is not the empty list.
209
228
This is not necessary for vectors as we can use the index to ensure
210
229
there is at least one element by defining tail as a function of type
211
230
[vec A (S n) -> vec A n].
@@ -229,11 +248,13 @@ vtail (vcons a v) := v.
229
248
| |
230
249
]]
231
250
232
- it returns [a] added to the diagonal of vmap [ vtail v'], that is
251
+ it returns [a] added to the diagonal of [ vmap vtail v'], that is
233
252
[v'] where the first column has been forgotten.
234
253
235
- Note, that in this case, pattern match on [n] needs to be added to help
236
- Coq see it is strictly decreasing.
254
+ Note, that in this case, pattern matching on [n] needs to be added to help
255
+ Coq see it is a strictly decreasing structurally recursive definition on the index.
256
+ [vmap vtail v'] can otherwise not be recognized as a syntactic subterm of [v'].
257
+ An alternative definition using well founded-recursion is presented below.
237
258
*)
238
259
239
260
Equations diag {A n} (v : vec (vec A n) n) : vec A n :=
@@ -253,10 +274,10 @@ Proof.
253
274
(* We start by induction, simplify and use the induction hypothesis *)
254
275
funelim (diag v); simp vmap diag. 1: easy. rewrite H. f_equal.
255
276
(* We simplify the goal by collapsing the different [vmap] using [vmap_comp],
256
- and notice the proof boils down to commutativity if [vtail] and [vmap] *)
277
+ and notice the proof boils down to commutativity of [vtail] and [vmap] *)
257
278
rewrite ! vmap_comp. f_equal. apply vmap_cong.
258
279
(* There is left to prove by function elimination on [vtail] or [vmap] *)
259
- intro v2. funelim (vtail v2). simp vmap vtail. reflexivity.
280
+ intro v2. clear -v2. funelim (vtail v2). simp vmap vtail. reflexivity.
260
281
Qed .
261
282
262
283
@@ -266,75 +287,86 @@ Qed.
266
287
no-confusion properties to deduce which cases are impossible, enabling to
267
288
write concise code where all uninteresting cases are handled automatically.
268
289
269
- No confusion properties basically embodies both discrimination and injectivity
290
+ No- confusion properties basically embodies both discrimination and injectivity
270
291
of constructors: they assert which equations are impossible because the head
271
- constructors do not match, and if they do, simplify the equations.
292
+ constructors do not match, or if they do match, simplify to equations between the
293
+ constructor arguments.
272
294
273
- The cases above relies on the no-confusion property for [nat], that given
295
+ The cases above rely on the no-confusion property for [nat], that given
274
296
[n], [m] eturns [True] if [n] and [m] are both [0], [n = m] if they are both
275
297
of the form [S n], [S m], and [False] otherwise.
276
298
277
- [Equations] provides a [Derive] command to generate them automatically.
299
+ [Equations] provides a [Derive] command to generate this notion automatically
300
+ for each inductive type.
278
301
For instance, for [nat], it suffices to write:
279
302
*)
280
303
281
304
Derive NoConfusion for nat.
282
- Check NoConfusion_nat.
305
+ Print NoConfusion_nat.
283
306
284
- (** You may have noticed that we have derive the no confusion property for [nat]
307
+ (** You may have noticed that we have derived the no- confusion property for [nat]
285
308
after defining [tail] and [diag], even though it is supposed to be necessary.
286
309
This is because it is already defined for [nat] by default, so there was
287
310
actually no need to do derive it in this particular case.
288
311
289
312
[nat] is a very simple inductive type.
290
- In the general case, for index inductive types, they are two kind of no-confusion
313
+ In the general case, for indexed inductive types, there are two kind of no-confusion
291
314
properties that can be derived by [Equations]:
292
- - The [NoConfusion] property that enable to distinguish object with different indices.
293
- It takes as argument objects in the total space {n : nat & vec A n}:
315
+ - The [NoConfusion] property that enables to distinguish object with different indices.
316
+ It takes as argument objects in the total space {n : nat & vec A n} and it is used
317
+ to solve general equations between objects in potentially different instances of the
318
+ inductive family:
294
319
*)
295
320
Derive NoConfusion for vec.
296
321
Check NoConfusion_vec.
297
322
298
323
(**
299
- - The [NoConfusionHom] property that enables to disinguish objects with the
300
- same indices, which is useful for simplifying equations:
324
+ - The [NoConfusionHom] property that enables to distinguish objects with the
325
+ same indices (i.e., in the same instance of the inductive family), which
326
+ is useful for simplifying homogeneous equations:
301
327
*)
302
328
303
329
Derive NoConfusionHom for vec.
304
- Check NoConfusionHom_vec.
330
+ Print NoConfusionHom_vec.
305
331
306
- (** Though, the [NonConfusionHom] property is derivable for most index inductive types,
307
- it is not the case that is is derivable for all index inductive types.
308
- It only is when equality of constructors can be reduced to equality of forced
309
- argument, that is ???
332
+ (** Though, the [NoConfusionHom] property is derivable for many indexed inductive types,
333
+ it is not the case that is derivable for all indexed inductive types.
334
+ It is derivable only when equality of constructors can be reduced to equality
335
+ of the non-forced constructor arguments. For example on vectors, this
336
+ corresponds to the fact that
337
+ [vcons a n v = vcons a' n v' :> vec A (S n) <-> a = a' /\ v = v' :> vec A n].
310
338
311
339
If it is not possible to derive it, then [Equations] may need the indices to
312
- satify Uniqueness of Identity Proof , asserting that all proofs are equal, i.e.
313
- [UIP : forall (A : Type) (a b : A) (p q : a = b), p = q], to be able to
340
+ satify Uniqueness of Identity Proofs , asserting that all equality proofs are
341
+ equal, i.e. [UIP : forall (A : Type) (a b : A) (p q : a = b), p = q], to be able to
314
342
elaborate the definition to a Coq term.
315
343
316
- UIP holds for some types like [nat], but in the general case, this is an axiom.
317
- It is compatible with Coq and classical logical but inconsistent
318
- with univalence, so you may not want to admit it globally in your development.
344
+ UIP holds for types like [nat] where equality is decidable, but it is not provable
345
+ for all types. In particular, it is not provable for [Type] itself.
346
+ It can be assumed as an axiom, but be mindful that while this is consistent with Coq's
347
+ vanilla theory and classical logic axioms, it is inconsistent with univalence, so you
348
+ may not want to admit it globally in your development. Also, as for any axiom,
349
+ it will computation stuck: [Equations] definitions relying on it will only be
350
+ simplifiable using [simp] but no longer compute using e.g. [Eval compute].
351
+
319
352
Consequently, [Equations] offers both options: you can declare it only for the types
320
- for which you can prove it or need it, or or assume it globally:
353
+ for which you can prove it or need it, or assume it globally:
321
354
*)
322
355
323
- (* Assuming you can prove it *)
324
- Axiom uip_nat : UIP nat.
356
+ (** Assuming you can prove it, from e.g. decidability of equality *)
357
+ Definition uip_nat : UIP nat := eqdec_uip nat_EqDec .
325
358
Local Existing Instance uip_nat.
326
359
360
+ (** Dangerous, incompatible with univalence, and results in stuck computations. *)
327
361
Axiom uipa : forall A, UIP A.
328
362
Local Existing Instance uipa.
329
363
330
-
331
-
332
364
(** *** 2.3 The Tactic Depelim *)
333
365
334
366
(** [Equations] provide a tactic [depelim] to recursively simplify and invert
335
367
equations and simplify the goals, which is based on the [NoConfusion]
336
368
principles and [Equations] simplification engine.
337
- When index inductive types are involved, it often provides a better simplification
369
+ When indexed inductive types are involved, it often provides a better simplification
338
370
tactic than the default [inversion] tactic.
339
371
*)
340
372
@@ -353,11 +385,11 @@ Qed.
353
385
Goal forall (x : vec nat 2), (vcons 0 x = vcons 1 x) -> False.
354
386
intros x H. depelim H.
355
387
Qed .
356
-
388
+ End Foo.
357
389
358
390
(** ** 3. Unifying Indices and Inaccessible Patterns
359
391
360
- A particularity of indexed inductive type is that during pattern-matching
392
+ A particularity of indexed inductive types is that during pattern-matching
361
393
indices may be particularised to values like variables or terms of
362
394
the form [(f (...))], where [f] is not a constructor of an inductive type
363
395
like [O] or [S].
366
398
that is _parameterized_ by a value [x] of type [A] and _indexed_
367
399
by another value of type [A].
368
400
Its single constructor states that equality is reflexive, so the only way
369
- to build an object of [eq x y] is if [x] is definitionally equal to the
370
- variable [y].
401
+ to build an object of [eq x y] (in the empty context) is if [x] is
402
+ definitionally equal to the term [y].
371
403
372
404
[[
373
405
Inductive eq (A : Type) (x : A) : A -> Prop :=
@@ -376,22 +408,23 @@ Qed.
376
408
377
409
Pattern-matching on the equality then unifies the index [y] with the
378
410
parameter [x], that is to a variable.
379
- Consequently, we have determined the _value_ of the pattern [y], and it is
380
- no longer a candidate for refinement with available constructors like
411
+ Consequently, we have determined the _value_ of the pattern [y] to be [x],
412
+ and it is no longer a candidate for refinement with available constructors like
381
413
[0] or [S n].
382
414
Such a pattern is said to be "inaccessible", and needs to be indicated
383
- by writing [?(t)] to tell Equations not to refine it.
415
+ by writing [?(t)] to tell Equations not to refine it but rather check its
416
+ inferrability.
384
417
385
418
As an example, to prove the symmetry of equality we pattern
386
419
match on an equality [H : x = y], which unify [y] the variable [x]
387
420
that we indicate by writing [eq_sym x ?(x) eq_refl].
388
- The goal now being [x = x], it now holds by [eq_refl].
421
+ The goal now being [x = x], it holds by [eq_refl].
389
422
*)
390
423
391
424
Equations eq_sym {A} (x y : A) (H : x = y) : y = x :=
392
425
eq_sym x ?(x) eq_refl := eq_refl.
393
426
394
- (** In practice, when the values determined are variable as in [eq_sym],
427
+ (** In practice, when the values determined are variables as in [eq_sym],
395
428
the inaccessibility annotation is optional and we can simply write [x]
396
429
or a wild card [_] rather than [?(x)].
397
430
*)
@@ -413,9 +446,8 @@ Inductive Imf {A B} (f : A -> B) : B -> Type
413
446
(** Pattern-matching on [im : Imf f t] particularise [t] to be of the form
414
447
[f a] for some [a].
415
448
As [f] is not a constructor, [f a] is inaccessible and we need to write
416
- as [?(f a)] in the pattern matching to prevent [Equations] to refine [f]
417
- with available constructors.
418
- In this case, it is essential as [f a] is not a variable.
449
+ as [?(f a)] in the pattern matching to prevent [Equations] to try to
450
+ interpret [f] as a constructor.
419
451
As an example, we can write a function returning the [a] associated
420
452
to an object in the image :
421
453
*)
@@ -426,7 +458,7 @@ inv f ?(f s) (imf f s) := s.
426
458
(** Be careful that if you forget to mark inaccessible patterns, then [Equations]
427
459
will try to match on the patterns, creating potentially pointless branches.
428
460
It is fine in theory as the definition obtained will be logically equivalent
429
- provided elaboration succededs , but annoying if you want to extract the code as the definition will be more involved.
461
+ provided elaboration succeeded , but annoying if you want to extract the code as the definition will be more involved.
430
462
431
463
For instance, if we define [vmap''] by matching on [n] without marking the
432
464
pattern associated to [n] as inaccessible, we can see at extraction that [Equations]
@@ -440,3 +472,19 @@ vmap'' f (S n) (vcons a v) := vcons (f a) (vmap'' f n v).
440
472
441
473
Extraction vmap.
442
474
Extraction vmap''.
475
+
476
+ (** Using inaccessible patterns hence allows to separate explicitely the subjects of
477
+ pattern-matchings and the inferred indices in definitions. The following alternative
478
+ definition of the square matrix diagonal pattern-matches only on the [vec] argument,
479
+ but uses well-founded recursion on the index [n] to justify termination, as
480
+ [vmap vtail v'] is not a subterm of [v']. *)
481
+
482
+ Equations diag_wf {A n} (v : vec (vec A n) n) : vec A n by wf n :=
483
+ diag_wf (n:=?(O)) vnil := vnil ;
484
+ diag_wf (n:=?(S _)) (vcons (vcons a v) v') := vcons a (diag_wf (vmap vtail v')).
485
+
486
+ (* Again, one can observe the extractions of the two diagonal definitions to see
487
+ that [diag_wf] is more efficient, not needing to pattern-match on the indices first. *)
488
+
489
+ Extraction diag.
490
+ Extraction diag_wf.
0 commit comments