-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathviews.v
110 lines (89 loc) · 3.97 KB
/
views.v
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
(* begin hide *)
(**********************************************************************)
(* Equations *)
(* Copyright (c) 2009-2021 Matthieu Sozeau <[email protected]> *)
(**********************************************************************)
(* This file is distributed under the terms of the *)
(* GNU Lesser General Public License Version 2.1 *)
(**********************************************************************)
(* end hide *)
From Equations.Prop Require Import Equations.
From Stdlib Require Import List Syntax Arith Lia.
(** * Views using dependent pattern-matching
The standard notion of pattern-matching in type theory requires to
give a case for each constructor of the inductive type we are working
on, even if the function acts the same on a subset of distinct
constructors. The reason is that due to dependencies, it is not clear
that two branches for distinct constructors can be factorized in general:
the return types of branches could be unifiable or not, depending on the
branch body.
Rather than trying to internalise this notion in the pattern-matching
algorithm we propose the use of views to encode this phenomenon.
Suppose that we want to do case analysis on an inductive with
three constructors but only want to single out the [cone] constructor during
pattern-matching: *)
Inductive three := cone | ctwo | cthree.
(** The user can write a view function to implement this. First one needs to write
a discriminator for the inductive type, indicating which cases are to be merged together:
*)
Equations discr_three (c : three) : Prop :=
discr_three cone := False;
discr_three _ := True.
(** One can derive an inductive representing the view of [three] as [cone] and the two other
[ctwo] and [cthree] cases lumbed together. *)
Inductive three_two_view : three -> Set :=
| three_one : three_two_view cone
| three_other c : discr_three c -> three_two_view c.
(** This view is obviously inhabited for any element in [three]. *)
Equations three_viewc c : three_two_view c :=
three_viewc cone := three_one;
three_viewc c := three_other c I.
(** Using a [with] clause one can pattern-match on the view argument to
do case splitting on [three] using only two cases. In each branch,
one can see that the [three] variable is determined by the view pattern. *)
Equations onthree (c : three) : three :=
onthree c with three_viewc c :=
onthree ?(cone) three_one := cone;
onthree ?(c) (three_other c Hc) := c.
(** A similar example discriminating [10] from the rest of natural numbers. *)
Equations discr_10 (x : nat) : Prop :=
discr_10 10 := False;
discr_10 x := True.
(** First alternative: using an inductive view *)
Module View.
Inductive view_discr_10 : nat -> Set :=
| view_discr_10_10 : view_discr_10 10
| view_discr_10_other c : discr_10 c -> view_discr_10 c.
(** This view is obviously inhabited for any element in [three]. *)
Equations discr_10_view c : view_discr_10 c :=
discr_10_view 10 := view_discr_10_10;
discr_10_view c := view_discr_10_other c I.
Equations f (n:nat) : nat :=
f n with discr_10_view n :=
f ?(10) view_discr_10_10 := 0;
f ?(n) (view_discr_10_other n Hn) := n + 1.
Goal forall n, n <> 10 -> f n = n + 1.
intros n; apply f_elim.
(* 2 cases: 10 and not 10 *)
all:simpl; congruence.
Qed.
End View.
(** Second alternative: using the discriminator directly.
This currently requires massaging the eliminator a bit *)
Equations f (n:nat) : nat by struct n (* FIXME *) :=
{ f 10 := 0;
f x := brx x (I : discr_10 x) }
where brx (x : nat) (H : discr_10 x) : nat :=
brx x H := x + 1.
Lemma f_elim' : forall (P : nat -> nat -> Prop),
P 10 0 ->
(forall (x : nat) (H : discr_10 x), P x (x + 1)) ->
(forall n : nat, P n (f n)).
Proof.
intros. apply (f_elim P (fun x H r => P x r)); auto.
Defined.
Goal forall n, n <> 10 -> f n = n + 1.
intros n; apply f_elim'.
(* 2 cases: 10 and not 10 *)
all:simpl; congruence.
Qed.