Skip to content

Commit ac73738

Browse files
authored
Merge pull request #577 from Tragicus/cs
CS app
2 parents e77a0be + b42f745 commit ac73738

File tree

14 files changed

+2226
-1
lines changed

14 files changed

+2226
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,4 @@ META
4848
apps/coercion/src/coq_elpi_coercion_hook.ml
4949
.filestoinstall
5050
apps/tc/src/coq_elpi_tc_hook.ml
51+
apps/cs/src/coq_elpi_cs_hook.ml

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export ELPIDIR
2121

2222
DEPS=$(ELPIDIR)/elpi.cmxa $(ELPIDIR)/elpi.cma
2323

24-
APPS=$(addprefix apps/, derive eltac NES locker coercion tc)
24+
APPS=$(addprefix apps/, derive eltac NES locker coercion cs tc)
2525

2626
ifeq "$(COQ_ELPI_ALREADY_INSTALLED)" ""
2727
DOCDEP=build

_CoqProject

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929
-R apps/coercion/tests elpi.apps.tc.coercion
3030
-I apps/coercion/src
3131

32+
# CS
33+
-R apps/cs/theories elpi.apps.cs
34+
-R apps/cs/tests elpi.apps.tc.cs
35+
-I apps/cs/src
36+
3237
# Type classes
3338
-R apps/tc/theories elpi.apps.tc
3439
-R apps/tc/tests elpi.apps.tc.tests

apps/cs/Makefile

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# detection of coq
2+
ifeq "$(COQBIN)" ""
3+
COQBIN := $(shell which coqc >/dev/null 2>&1 && dirname `which coqc`)
4+
endif
5+
ifeq "$(COQBIN)" ""
6+
$(error Coq not found, make sure it is installed in your PATH or set COQBIN)
7+
else
8+
$(info Using coq found in $(COQBIN), from COQBIN or PATH)
9+
endif
10+
export COQBIN := $(COQBIN)/
11+
12+
all: build test
13+
14+
build: Makefile.coq
15+
@$(MAKE) --no-print-directory -f Makefile.coq
16+
17+
test: Makefile.test.coq
18+
@$(MAKE) --no-print-directory -f Makefile.test.coq
19+
20+
theories/%.vo: force
21+
@$(MAKE) --no-print-directory -f Makefile.coq $@
22+
tests/%.vo: force build Makefile.test.coq
23+
@$(MAKE) --no-print-directory -f Makefile.test.coq $@
24+
examples/%.vo: force build Makefile.test.coq
25+
@$(MAKE) --no-print-directory -f Makefile.test.coq $@
26+
27+
Makefile.coq Makefile.coq.conf: _CoqProject
28+
@$(COQBIN)/coq_makefile -f _CoqProject -o Makefile.coq
29+
@$(MAKE) --no-print-directory -f Makefile.coq .merlin
30+
Makefile.test.coq Makefile.test.coq.conf: _CoqProject.test
31+
@$(COQBIN)/coq_makefile -f _CoqProject.test -o Makefile.test.coq
32+
33+
clean: Makefile.coq Makefile.test.coq
34+
@$(MAKE) -f Makefile.coq $@
35+
@$(MAKE) -f Makefile.test.coq $@
36+
37+
.PHONY: force all build test
38+
39+
install:
40+
@$(MAKE) -f Makefile.coq $@

apps/cs/Makefile.coq.local

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CAMLPKGS+= -package coq-elpi.elpi
2+
3+
ifeq "$(shell which cygpath >/dev/null 2>&1)" ""
4+
OCAMLFINDSEP=:
5+
else
6+
OCAMLFINDSEP=;
7+
endif
8+
9+
OCAMLPATH:=../../src/$(OCAMLFINDSEP)$(OCAMLPATH)
10+
export OCAMLPATH

apps/cs/README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Canonical solution
2+
3+
The `canonical_solution` app enables to program Coq canonical structure solutions in Elpi.
4+
5+
This app is experimental.
6+
7+
## The cs predicate
8+
9+
The `cs` predicate lives in the database `cs.db`
10+
11+
```elpi
12+
% predicate [cs Ctx Lhs Rhs] used to unify Lhs with Rhs, with
13+
% - [Ctx] is the context
14+
% - [Lhs] and [Rhs] are the terms to unify
15+
:index (0 6 6)
16+
pred cs i:goal-ctx, o:term, o:term.
17+
```
18+
19+
By addings rules for this predicate one can recover from a CS instance search failure
20+
error, that is when `Lhs` and `Rhs` are not unifiable using a canonical structure registered
21+
by Coq.
22+
23+
## Simple example of canonical solution
24+
25+
This example declares a structure `S` with a projection `sort` and declares
26+
a canonical solution for `nat` in `S`.
27+
28+
```coq
29+
From elpi.apps Require Import cs.
30+
From Coq Require Import Bool.
31+
32+
Structure S : Type :=
33+
{ sort :> Type }.
34+
35+
Elpi Accumulate cs.db lp:{{
36+
37+
cs _ {{ sort lp:Sol }} {{ nat }} :-
38+
Sol = {{ Build_S nat }}.
39+
40+
}}.
41+
Elpi Typecheck canonical_solution.
42+
43+
Check eq_refl _ : (sort _) = nat.
44+
```

apps/cs/_CoqProject

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Hack to see Coq-Elpi even if it is not installed yet
2+
-Q ../../theories elpi
3+
-I ../../src
4+
-docroot elpi.apps
5+
6+
-R theories elpi.apps
7+
8+
src/evarconv_hacked.ml
9+
src/coq_elpi_cs_hook.mlg
10+
src/elpi_cs_plugin.mlpack
11+
12+
-I src/
13+
src/META.coq-elpi-cs
14+
15+
theories/cs.v

apps/cs/_CoqProject.test

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Hack to see Coq-Elpi even if it is not installed yet
2+
-Q ../../theories elpi
3+
-I ../../src
4+
-docroot elpi.apps
5+
6+
-R theories elpi.apps
7+
-R tests elpi.apps.cs.tests
8+
9+
tests/test_cs.v
10+
11+
-I src

apps/cs/src/META.coq-elpi-cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
package "plugin" (
3+
directory = "."
4+
requires = "coq-core.plugins.ltac coq-elpi.elpi"
5+
archive(byte) = "elpi_cs_plugin.cma"
6+
archive(native) = "elpi_cs_plugin.cmxa"
7+
plugin(byte) = "elpi_cs_plugin.cma"
8+
plugin(native) = "elpi_cs_plugin.cmxs"
9+
)
10+
directory = "."

apps/cs/src/coq_elpi_cs_hook.mlg

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
DECLARE PLUGIN "coq-elpi-cs.plugin"
2+
3+
{
4+
5+
open Elpi
6+
open Elpi_plugin
7+
open Coq_elpi_arg_syntax
8+
open Coq_elpi_vernacular
9+
module Evarconv = Evarconv
10+
module Evarconv_hacked = Evarconv_hacked
11+
12+
13+
let elpi_cs_hook program env sigma lhs rhs =
14+
let (lhead, largs) = EConstr.decompose_app sigma lhs in
15+
let (rhead, rargs) = EConstr.decompose_app sigma rhs in
16+
if (EConstr.isConst sigma lhead && Structures.Structure.is_projection (fst (EConstr.destConst sigma lhead))) ||
17+
(EConstr.isConst sigma rhead && Structures.Structure.is_projection (fst (EConstr.destConst sigma rhead)))
18+
then begin
19+
let loc = API.Ast.Loc.initial "(unknown)" in
20+
let atts = [] in
21+
(*let sigma, ty = Typing.type_of env sigma lhs in*)
22+
let sigma, (ty, _) = Evarutil.new_type_evar env sigma Evd.univ_flexible in
23+
let { Coqlib.eq } = Coqlib.build_coq_eq_data () in
24+
let sigma, eq = EConstr.fresh_global env sigma eq in
25+
let t = EConstr.mkApp (eq,[|ty;lhs;rhs|]) in
26+
let sigma, goal = Evarutil.new_evar env sigma t in
27+
let goal_evar, _ = EConstr.destEvar sigma goal in
28+
let query ~depth state =
29+
let state, (loc, q), gls =
30+
Coq_elpi_HOAS.goals2query sigma [goal_evar] loc ~main:(Coq_elpi_HOAS.Solve [])
31+
~in_elpi_tac_arg:Coq_elpi_arg_HOAS.in_elpi_tac_econstr ~depth state in
32+
let state, qatts = atts2impl loc Summary.Stage.Interp ~depth state atts q in
33+
let state = API.State.set Coq_elpi_builtins.tactic_mode state true in
34+
state, (loc, qatts), gls
35+
in
36+
match Interp.get_and_compile program with
37+
| None -> None
38+
| Some (cprogram, _) ->
39+
match Interp.run ~static_check:false cprogram (`Fun query) with
40+
| API.Execute.Success solution ->
41+
let gls = Evar.Set.singleton goal_evar in
42+
let sigma, _, _ = Coq_elpi_HOAS.solution2evd sigma solution gls in
43+
let ty_evar, _ = EConstr.destEvar sigma ty in
44+
Some (Evd.remove (Evd.remove sigma ty_evar) goal_evar)
45+
| API.Execute.NoMoreSteps
46+
| API.Execute.Failure -> None
47+
| exception (Coq_elpi_utils.LtacFail (level, msg)) -> None
48+
end
49+
else None
50+
51+
let add_cs_hook =
52+
let cs_hook_program = Summary.ref ~name:"elpi-cs" None in
53+
let cs_hook env sigma proj pat =
54+
Feedback.msg_info (Pp.str "run");
55+
match !cs_hook_program with
56+
| None -> None
57+
| Some h -> elpi_cs_hook h env sigma proj pat in
58+
let name = "elpi-cs" in
59+
Evarconv_hacked.register_hook ~name cs_hook;
60+
let inCs =
61+
let cache program =
62+
cs_hook_program := Some program;
63+
Feedback.msg_info (Pp.str "activate");
64+
65+
Evarconv_hacked.activate_hook ~name in
66+
let open Libobject in
67+
declare_object
68+
@@ superglobal_object_nodischarge "ELPI-CS" ~cache ~subst:None in
69+
fun program -> Lib.add_leaf (inCs program)
70+
71+
}
72+
73+
VERNAC COMMAND EXTEND ElpiCS CLASSIFIED AS SIDEFF
74+
| #[ atts = any_attribute ] [ "Elpi" "CSFallbackTactic" qualified_name(p) ] -> {
75+
let () = ignore_unknown_attributes atts in
76+
add_cs_hook (snd p) }
77+
| #[ atts = any_attribute ] [ "Elpi" "Override" "CS" qualified_name(p) ] -> {
78+
Evarconv.set_evar_conv Evarconv_hacked.evar_conv_x }
79+
80+
END

0 commit comments

Comments
 (0)