@@ -457,41 +457,111 @@ Check is_list_to_is_list_inv :
457457## Writing a new derivation
458458
459459A 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
467472From elpi.apps.derive Extra Dependency "derive_hook.elpi" as derive_hook.
468473From mypkg Extra Dependency "myder.elpi" as myder.
469474
470475From elpi Require Import elpi.
471476From 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
473486Elpi 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
479500Elpi Command derive.myder.
480501Elpi Accumulate File derive_hook.
481502Elpi Accumulate File myder.
482503Elpi Accumulate Db derive.mydb.db.
483504Elpi 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}}.
490514Elpi 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