Skip to content

Commit 6d5090f

Browse files
committed
recursive derive
1 parent b986f5f commit 6d5090f

File tree

4 files changed

+81
-56
lines changed

4 files changed

+81
-56
lines changed

apps/derive/elpi/derive.elpi

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ exists-indc I P :-
1010
std.exists KL P.
1111

1212
pred if-verbose i:prop.
13-
if-verbose P :- get-option "verbose" tt, !, P.
13+
if-verbose P :- (get-option "verbose" tt ; get-option "recursive" tt), !, P.
1414
if-verbose _.
1515

1616
pred dep o:string, o:string.
@@ -22,38 +22,38 @@ selected Name :- get-option "only" Map, !,
2222
Map => (get-option Name _; (get-option X _, dep X Name)).
2323
selected _.
2424

25-
pred validate-only i:list derive.
26-
validate-only LD :- get-option "only" Map, !, std.forall Map (known-option LD).
27-
validate-only _.
25+
pred validate-only i:gref, i:list derive.
26+
validate-only T LD :- get-option "only" Map, !, std.forall Map (known-option T LD).
27+
validate-only _ _.
2828

29-
pred known-option i:list derive, i:prop.
30-
known-option L (get-option X _) :-
29+
pred known-option i:gref, i:list derive, i:prop.
30+
known-option T L (get-option X _) :-
3131
if (std.mem! L (derive X _ _)) true
32-
(coq.error "Derivation" X "unknown or not applicable to the input").
33-
34-
pred chain i:list derive, o:list prop.
35-
chain [] [].
36-
chain [derive Name _ _|FS] CL :- not(selected Name), !,
37-
if-verbose (coq.say "Skipping derivation" Name "since the user did not select it"),
38-
chain FS CL.
39-
chain [derive Name _ AlreadyDone|FS] CL :- (pi x\ stop x :- !, fail) => AlreadyDone, !,
40-
if-verbose (coq.say "Skipping derivation" Name "since it has been already run"),
41-
chain FS CL.
42-
chain [derive Name F _|FS] CL :- get-option "only" _, !, % request this one
43-
if-verbose (coq.say "Derivation" Name),
32+
(coq.error "Derivation" X "unknown or not applicable to input" T).
33+
34+
pred chain i:gref, i:list derive, o:list prop.
35+
chain _ [] [].
36+
chain T [derive Name _ _|FS] CL :- not(selected Name), !,
37+
if-verbose (coq.say "Skipping derivation" Name "on" T "since the user did not select it"),
38+
chain T FS CL.
39+
chain T [derive Name _ AlreadyDone|FS] CL :- (pi x\ stop x :- !, fail) => AlreadyDone, !,
40+
if-verbose (coq.say "Skipping derivation" Name "on" T "since it has been already run"),
41+
chain T FS CL.
42+
chain T [derive Name F _|FS] CL :- get-option "only" _, !, % request this one
43+
if-verbose (coq.say "Derivation" Name "on" T),
4444
@dropunivs! => std.time (F C) Time,
45-
if-verbose (coq.say "Derivation" Name "took" Time),
46-
C => chain FS CS,
45+
if-verbose (coq.say "Derivation" Name "on" T "took" Time),
46+
C => chain T FS CS,
4747
std.append C CS CL.
48-
chain [derive Name F _|FS] CL :- % all are selected, we can fail
49-
if-verbose (coq.say "Derivation" Name),
48+
chain T [derive Name F _|FS] CL :- % all are selected, we can fail
49+
if-verbose (coq.say "Derivation" Name "on" T),
5050
(pi x\ stop x :- !, fail) => @dropunivs! => std.time (F C) Time, !,
51-
if-verbose (coq.say "Derivation" Name "took" Time),
52-
C => chain FS CS,
51+
if-verbose (coq.say "Derivation" Name "on" T "took" Time),
52+
C => chain T FS CS,
5353
std.append C CS CL.
54-
chain [derive F _ _|FS] CL :-
55-
if-verbose (coq.say "Derivation" F "failed, continuing"),
56-
chain FS CL.
54+
chain T [derive F _ _|FS] CL :-
55+
if-verbose (coq.say "Derivation" F "on" T "failed, continuing"),
56+
chain T FS CL.
5757

5858
pred toposort i:list derive, o:list derive.
5959
toposort L SL :-
@@ -85,20 +85,36 @@ topo L Deps SL :-
8585
pred export? i:prop, o:prop.
8686
export? (export M) (coq.env.export-module M).
8787

88+
pred indt-or-const i:gref.
89+
indt-or-const (indt _).
90+
indt-or-const (const _).
91+
8892
pred main i:gref, i:string, o:list prop.
89-
main T Prefix CL :-
93+
main T Prefix CL :- get-option "recursive" tt, !,
94+
coq.env.dependencies T _ AllDeps,
95+
coq.gref.set.elements AllDeps AllDepsL,
96+
std.filter AllDepsL indt-or-const Deps,
97+
main.aux Deps Prefix [] CL1,
98+
CL1 => main1 T Prefix CL2,
99+
std.append CL1 CL2 CL.
100+
pred main.aux i:list gref, i:string, i:list prop, o:list prop.
101+
main.aux [] _ X X.
102+
main.aux [T|TS] Prefix Acc CL :-
103+
(pi X\get-option "only" X :- !, fail) => Acc => main T Prefix CL1,
104+
main.aux TS Prefix {std.append CL1 Acc} CL.
105+
106+
main T Prefix CL :- main1 T Prefix CL.
107+
108+
pred main1 i:gref, i:string, o:list prop.
109+
main1 T Prefix CL :-
90110
std.findall (derivation T Prefix _) L,
91111
if (L = [])
92112
(coq.error "no derivation found, did you Import derive.std?")
93113
true,
94114
std.map L (x\r\ x = derivation _ _ r) DL,
95-
validate-only DL,
115+
validate-only T DL,
96116
toposort DL SortedDL,
97-
ModName is "Derive_Anonymous_" ^ {std.any->string {new_int}},
98-
coq.env.begin-module ModName none,
99-
chain SortedDL CL,
100-
coq.env.end-module ModPath,
101-
coq.env.import-module ModPath.
117+
chain T SortedDL CL.
102118

103119
pred decl+main i:indt-decl.
104120
decl+main DS :- std.do! [

apps/derive/examples/usage.v

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,14 @@
33
*)
44

55
From Coq Require Import Bool.
6-
From elpi.apps Require Import derive.std derive.legacy.
6+
From elpi.apps Require Import derive.std.
77
Set Uniform Inductive Parameters.
88

9-
(** The basic invocation is with just one argument, the inductive
10-
type name *)
11-
derive nat.
12-
13-
(** generated constants are prefixed with nat_ *)
14-
Check nat_eq_OK :
15-
forall x y, reflect (x = y) (nat_eq x y).
16-
17-
(** One can also prefix an Inductive declaration with derive. *)
9+
(** The best way to call derive is to prefix an Inductive declaration. *)
1810
derive
1911
Inductive tickle A := stop | more : A -> tickle -> tickle.
2012

21-
(** In this case the command is elaborated to:
13+
(** The command is elaborated to something like:
2214
2315
Module tickle.
2416
Inductive tickle A := stop | more : A -> tickle -> tickle.
@@ -27,23 +19,21 @@ Inductive tickle A := stop | more : A -> tickle -> tickle.
2719
Notation tickle := tickle.tickle.
2820
Notation stop := tickle.stop.
2921
Notation more := tickle.more.
22+
3023
*)
3124
Check more :
3225
forall A, A -> tickle A -> tickle A.
3326

3427
(** Some goodies *)
35-
Check tickle.eq : (* eq test *)
28+
Check tickle.eqb : (* eq test *)
3629
forall A, (A -> A -> bool) -> tickle A -> tickle A -> bool.
3730

38-
Check tickle.eq_OK : (* eq test correctness proof *)
39-
forall A f, (forall x y, reflect (x = y) (f x y)) -> forall x y, reflect (x = y) (tickle.eq A f x y).
31+
Check tickle.eqb_OK : (* eq test correctness proof *)
32+
forall A f, (forall x y, reflect (x = y) (f x y)) -> forall x y, reflect (x = y) (tickle.eqb A f x y).
4033

4134
Check tickle.map : (* map the container *)
4235
forall A B, (A -> B) -> tickle A -> tickle B.
4336

44-
Check tickle.isk_stop : (* recognize a constructor *)
45-
forall A, tickle A -> bool.
46-
4737
Check tickle.tickle_R : (* relator (binary parametricity translation) *)
4838
forall A B, (A -> B -> Type) -> tickle A -> tickle B -> Type.
4939

@@ -59,11 +49,8 @@ Check rtree.induction : (* this is the key *)
5949
(forall l, tickle.is_tickle (rtree A) P l -> P (Node A l)) ->
6050
forall x, rtree.is_rtree A PA x -> P x.
6151

62-
Check rtree.eq_OK nat nat_eq nat_eq_OK : (* proofs compose *)
63-
forall x y : rtree nat, reflect (x = y) (rtree.eq nat nat_eq x y).
64-
6552
(** You can also select which derivations you like *)
66-
#[only(lens_laws, eq)] derive
53+
#[verbose, only(lens_laws, eqb)] derive
6754
Record Box A := { contents : A; tag : nat }.
6855

6956
Check Box.eq :
@@ -81,3 +68,23 @@ Check Box._tag_contents_exchange : (* another one *)
8168
forall A (r : Box A) x y, set Box._tag x (set Box._contents y r) =
8269
set Box._contents y (set Box._tag x r).
8370

71+
(** Finally, one can derive an existing inductive typegenerated constants are
72+
prefixed with nat_ but won't be in the right
73+
place, which is where the type is defined. This means that two users
74+
may run derive for the same type in different files, leading to
75+
duplication. *)
76+
77+
derive nat.
78+
79+
Check nat_eq_OK :
80+
forall x y, reflect (x = y) (nat_eq x y).
81+
82+
(** Once can also run derive recursively, but this has the same bad effect,
83+
all generated concepts will be out of place *)
84+
85+
Inductive a := A.
86+
Inductive b := B : A -> B.
87+
88+
#[recursive] derive b.
89+
90+
Check b.eqb.

apps/derive/theories/derive.v

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ with-attributes P :-
7070
coq.parse-attributes A [
7171
att "verbose" bool,
7272
att "only" attmap,
73+
att "recursive" bool,
7374
] Opts, !,
7475
Opts => P.
7576

apps/derive/theories/derive/std.v

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ From elpi.apps Require Export
1717
derive.tag
1818
derive.fields
1919
derive.eqb
20+
derive.eqbcorrect
2021
derive.eqbOK
21-
.
22+
.
2223
Elpi Typecheck derive.
2324

2425
(* we derive the Coq prelude *)

0 commit comments

Comments
 (0)