1
+ From elpi Require Export elpi.
2
+
3
+ Elpi Tactic rewrite.
4
+ Elpi Accumulate lp:{{
5
+ % Second argument is a type of the form forall x1 x2 x3... P = Q.
6
+ % First argument is a term of that type.
7
+ % This tactic finds a subterm of the goal that Q unifies with
8
+ % and rewrites all instances of that subterm from right to left.
9
+ pred rewrite i:list argument, i:term, i:term, o:goal, o:list sealed-goal.
10
+
11
+ % The copy predicate used below is discussed in the tutorial here:
12
+ % https://lpcic.github.io/coq-elpi/tutorial_coq_elpi_tactic.html#let -s-code-set-in -elpi
13
+
14
+ rewrite Strong Eqpf {{@eq lp:S lp:P lp:Q }} (goal _ _ GoalType _ _ as G) GL :-
15
+ % First, introduce a rule that causes "copy" to act as a function
16
+ % sending a type T to the same type, but with all
17
+ % subterms of T unifiable with Q to be replaced with a fresh constant x.
18
+ pi x\
19
+ (pi J\ copy J x :- Strong = [str "strong"| _], coq.unify-leq Q J ok) =>
20
+ (pi J\ copy J x :- [] = Strong, Q = J) =>
21
+ % Apply this copy function to the goal type.
22
+ (copy GoalType (A x),
23
+ % If the subterm Q did indeed appear in the goal,
24
+ % then pattern match on the given equality assumption P = Q,
25
+ % causing Q to be replaced with P everywhere.
26
+ if (occurs x (A x))
27
+ (refine (match
28
+ Eqpf {{ fun a (e : @eq lp:S lp:P a) => lp:(A a) }}
29
+ % We only want to create one hole,
30
+ % the one corresponding to the
31
+ % contents of the (single) branch of the match .
32
+ [Hole_])
33
+ G GL
34
+ )
35
+ (coq.ltac.fail _ "Couldn't unify")).
36
+
37
+ solve (goal _ _ _ _ [trm Eq | Strong] as G) GL :-
38
+ coq.typecheck Eq Ty ok,
39
+ coq.saturate Ty Eq Eq',
40
+ coq.typecheck Eq' Ty' ok,
41
+ rewrite Strong Eq' Ty' G GL.
42
+ }}.
43
+
44
+ Tactic Notation "eltac.rewrite" ident(T) := elpi rewrite ltac_term:(T).
45
+ Tactic Notation "eltac.rewrite" uconstr(T) := elpi rewrite ltac_term:(T).
46
+ Tactic Notation "eltac.rewrite" uconstr(T) string(s) := elpi rewrite ltac_term:(T) ltac_string:(s).
0 commit comments