Skip to content

Commit 3ab3e9c

Browse files
committed
finish doc
1 parent fd6e2b6 commit 3ab3e9c

File tree

1 file changed

+76
-6
lines changed

1 file changed

+76
-6
lines changed

apps/derive/README.md

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -457,41 +457,111 @@ Check is_list_to_is_list_inv :
457457
## Writing a new derivation
458458

459459
A derivation is made of:
460-
- a data base to carry some state
461460
- a file implementing the derivation
461+
- a data base to carry some state
462462
- a stand alone command
463463
- a hook in the main derive procedure
464464

465+
At the light of that, here a typical derivation file `myder.v`.
466+
The first section
467+
loads the standard derive code and declares the dependency the external file
468+
`myder.elpi`. The file `derive_hook.elpi` contains a few data types needed
469+
in order to register the derivation in the main derive loop.
465470

466471
```coq
467472
From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook.
468473
From mypkg Extra Dependency "myder.elpi" as myder.
469474
470475
From elpi Require Import elpi.
471476
From elpi.apps Require Import derive.
477+
```
478+
479+
The database is typically a predicate `myder` linking a type name to some
480+
concept previously derived. We also need to know if we did already derive a
481+
type, hence we declare a second predicate `myder-done` (we could reuse the
482+
former, but sometimes this is not easy, so here we are pedantic).
483+
We like to prefix these data bases name with `derive.`.
472484

485+
```coq
473486
Elpi Db derive.mydb.db lp:{{
474-
pred mydb o:gref, o:gref. % [mydb T D] links a type T to a derived concept D
487+
% [myder T D] links a type T to a derived concept D
488+
pred myder o:gref, o:gref.
489+
490+
% [myder-done T] mean T was already derived
491+
pred myder-done o:gref.
475492
}}.
476493
```
477494

495+
Then we build a standalone derivation accessible via the name `derive.myder`
496+
which accumulates the external files declared before, the data base and
497+
an entry point
498+
478499
```coq
479500
Elpi Command derive.myder.
480501
Elpi Accumulate File derive_hook.
481502
Elpi Accumulate File myder.
482503
Elpi Accumulate Db derive.mydb.db.
483504
Elpi Accumulate lp:{{
484-
main [str I, str O] :- !, coq.locate I GR, derive.myder.main GR O _.
485-
main [str I] :- !, coq.locate I GR, derive.myder.main GR "prefix_" _.
505+
main [str I] :- !, coq.locate I GR,
506+
coq.gref->id GR Tname,
507+
Prefix is Tname ^ "_",
508+
derive.myder.main GR Prefix _.
486509
main _ :- usage.
487510
488-
usage :- coq.error "Usage: derive.myder <object name> [<output prefix>]".
511+
pred usage.
512+
usage :- coq.error "Usage: derive.myder <object name>".
489513
}}.
490514
Elpi Typecheck.
515+
```
491516

517+
This is enough to run the derivation via something like
518+
`Elpi derive.myder nat.`. In order to have `derive` run it one has to
519+
accumulate some code on top of `derive` itself.
492520

493-
```
521+
```coq
522+
Elpi Accumulate derive Db derive.myder.db.
523+
Elpi Accumulate derive File myder.
524+
Elpi Accumulate derive lp:{{
525+
526+
dep1 "myder" "somedep".
527+
dep1 "myder" "someotherdep".
528+
derivation
529+
(indt T) Prefix % inputs
530+
(derive "myder" % name (for dep1)
531+
(derive.myder.main (indt T) Prefix) % code to run
532+
(myder-done (indt T)) % idempotency test
533+
).
494534
535+
}}.
536+
```
495537

538+
First, one declares via `dep1`
539+
the derivations that should run before, here `somedep`
540+
and `someotherdep`. `derive` will compute a topological order and ensure
541+
dependencies are run first.
542+
Then one declares a derivation for a gref and a prefix. One can restrict
543+
which grefs can be derived, here for example we make `myder` only available
544+
on `indt` (inductive types, and not definitions or constructors).
545+
`Prefix` is a string, typically passed to the main code.
546+
The the `(derive ...)` tuple carrier the name of the derivation, already used
547+
in `dep1` and two predicates, one to run the derivation and one to
548+
test if the derivation was already run.
549+
The types for `dep1`, `derivation` and `derive` are declared in
550+
`derive_hook.elpi`.
551+
552+
Finally, one is expected to `Import` the `myder.v` file in a derivation
553+
group, for example `better_std.v` would look like so:
496554

555+
```coq
556+
From elpi.apps Require Export derive.
557+
From elpi.apps Require Export
558+
derive.map
559+
derive.lens
560+
derive.lens_laws
561+
...
562+
myder (* new derivation *)
563+
.
564+
Elpi Typecheck derive.
565+
```
497566

567+
So when the user `Import`s `better_std` he gets a fully loaded `derive`.

0 commit comments

Comments
 (0)