Built with Alectryon, running Coq+SerAPI v8.19.0+0.19.3. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑Ctrl+↓ to navigate, Ctrl+🖱️ to focus. On Mac, use ⌘ instead of Ctrl.
(** * Tactics for rewriting modulo associativity *)
[Loading ML file number_string_notation_plugin.cmxs (using legacy method) ... done]
Require Import Tactics.BinderApply.LocalOpen Scope path_scope.(** Throughout this file, we prefix with [idtac; ] all imperative tactics (those not returning constrs) which would otherwise start with [let] or [match]. This prevents them from being evaluated at the call site. See https://coq.inria.fr/bugs/show_bug.cgi?id=3498 for more details on this difference between tactics and tactic expressions. *)(** rewrite [lem] modulo associativity using: - [assoc_tac : unit] to associate the goal (in place) - [assoc_in_tac : hyp -> unit] to associate the hypothesis (in place) - [prepostcompose_any_tac : constr -> constr] to pre/post compose an arbitrary morphism onto the lemma - [rew_tac : hyp -> unit] to do the actual rewriting (in place). This tactic is called first with the non-associated version of the lemma, then with the associated version. *)LtacrewriteA_using_helper rew_tac lem prepostcompose_any_tac assoc_tac assoc_in_tac :=
idtac;
letlem' := prepostcompose_any_tac lem inletH := freshinpose proof lem' as H;
assoc_tac;
match goal with
| _ => rew_tac H
| _ => assoc_in_tac H;
rew_tac H
end;
clear H.(** This tactic is similar to the above, except that it passes both the unassociated lemma and the associated lemma to [repeat_rew_tac], which may then contain optimizations over a manual [repeat] such as being [rewrite ?lem, ?lem']. *)Ltacrepeat_rewriteA_using_helper repeat_rew_tac lem prepostcompose_any_tac assoc_tac assoc_in_tac :=
idtac;
letlem' := prepostcompose_any_tac lem inletH := freshinpose proof lem' as H;
assoc_in_tac H;
assoc_tac;
repeat_rew_tac lem' H;
clear H.ModuleExport Compose.(** ** Rewriting modulo associativity of composition ([o]) *)(** Since [f o g] is just a notation, we need to define a constant that isn't reduced by [cbv beta]. *)Local Definitioncompose {ABC} (g : B -> C) (f : A -> B) (x : A) : C := g (f x).Ltacto_compose T :=
match T with
| context G[?g o ?f] => letT' := context G[compose g f] in
to_compose T'
| ?T' => constr:(T')
end.(** Turns a lemma of type [f = g] into [forall h, h o f = h o g] *)Ltacprecompose_any H :=
letret := make_tac_under_binders_using_in ltac:(funH => (letH' := freshinrename H into H';
letT := type of H' inletT' := to_compose T inpose proof (funsrc (g : _ -> src) => @ap _ _ (funf => compose g f) _ _ (H' : T')) as H))
ltac:(idtac) H inletT := type of ret inletT' := (evalcbv beta in T) inconstr:(ret : T').(** Associates a type fully to the left *)Ltacleft_associate_compose_type T :=
let rec_tac := left_associate_compose_type inmatch to_compose T with
| foralla : ?A, @?P a => letret := constr:(foralla : A, letT' := P a inltac:(
letT'' := (evalunfold T' in T') inletret := rec_tac T'' inexact ret)) inevalcbv beta zeta in ret
| context T'[compose ?a (compose ?b?c)]
=> letT'' := context T'[compose (compose a b) c] in
rec_tac T''
| ?T' => constr:(T')
end.Ltacleft_associate_compose_in_type_of H :=
letT := type of H inletT' := left_associate_compose_type T inconstr:(H : T').Ltacleft_associate_compose :=
idtac;
(lazymatch goal with
| [ |- ?G ] => letG' := left_associate_compose_type G inchange G'
end).Ltacleft_associate_compose_in H :=
idtac;
(lazymatchtype of H with
| ?T => letT' := left_associate_compose_type T inchange T' in H
end).Ltacafter_rewrite :=
repeatmatch goal with
| [ |- context G[compose ?g?f] ] => letG' := context G[g o f] inchange G'
| _ =>
match goal with
| [ |- context G[@compose ?A?B?C?g] ] => letG' := context G[funf : A -> B => g o f] inchange G'
| [ |- context G[@compose ?A?B?C] ] => letG' := context G[fun (g : B -> C) (f : A -> B) => g o f] inchange G'
| _ => progresscbv delta [compose]
end;
idtac"Warning: could not fully restore pre-rewrite state.""Try introducing more things or removing binders."end.Tactic Notation"rewriteoA"constr(lem) :=
rewriteA_using_helper ltac:(funlem' => rewrite lem') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"rewriteoA""->"constr(lem) :=
rewriteA_using_helper ltac:(funlem' => rewrite -> lem') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"rewriteoA""<-"constr(lem) :=
rewriteA_using_helper ltac:(funlem' => rewrite <- lem') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"rewriteoA""!"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => progressrewrite?lem', ?lem'') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"rewriteoA""?"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => rewrite?lem', ?lem'') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"rewriteoA""->""!"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => progressrewrite -> ?lem', -> ?lem'') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"rewriteoA""<-""!"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => progressrewrite <- ?lem', <- ?lem'') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"rewriteoA""->""?"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => rewrite -> ?lem', -> ?lem'') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"rewriteoA""<-""?"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => rewrite <- ?lem', <- ?lem'') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"erewriteoA"constr(lem) :=
rewriteA_using_helper ltac:(funlem' => erewrite lem') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"erewriteoA""->"constr(lem) :=
rewriteA_using_helper ltac:(funlem' => erewrite -> lem') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"erewriteoA""<-"constr(lem) :=
rewriteA_using_helper ltac:(funlem' => erewrite <- lem') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"erewriteoA""!"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => progresserewrite?lem', ?lem'') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"erewriteoA""?"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => erewrite?lem', ?lem'') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"erewriteoA""->""!"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => progresserewrite -> ?lem', -> ?lem'') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"erewriteoA""<-""!"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => progresserewrite <- ?lem', <- ?lem'') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"erewriteoA""->""?"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => erewrite -> ?lem', -> ?lem'') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"erewriteoA""<-""?"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => erewrite <- ?lem', <- ?lem'') lem ltac:(precompose_any) ltac:(left_associate_compose) ltac:(left_associate_compose_in); after_rewrite.Tactic Notation"rewrite∘A"constr(lem) := rewriteoA lem.Tactic Notation"rewrite∘A""->"constr(lem) := rewriteoA -> lem.Tactic Notation"rewrite∘A""<-"constr(lem) := rewriteoA <- lem.Tactic Notation"rewrite∘A""!"constr(lem) := rewriteoA !lem.Tactic Notation"rewrite∘A""?"constr(lem) := rewriteoA ? lem.Tactic Notation"rewrite∘A""->""!"constr(lem) := rewriteoA -> !lem.Tactic Notation"rewrite∘A""<-""!"constr(lem) := rewriteoA <- !lem.Tactic Notation"rewrite∘A""->""?"constr(lem) := rewriteoA -> ? lem.Tactic Notation"rewrite∘A""<-""?"constr(lem) := rewriteoA <- ? lem.Tactic Notation"erewrite∘A" open_constr(lem) := erewriteoA lem.Tactic Notation"erewrite∘A""->" open_constr(lem) := erewriteoA -> lem.Tactic Notation"erewrite∘A""<-" open_constr(lem) := erewriteoA <- lem.Tactic Notation"erewrite∘A""!" open_constr(lem) := erewriteoA !lem.Tactic Notation"erewrite∘A""?" open_constr(lem) := erewriteoA ? lem.Tactic Notation"erewrite∘A""->""!" open_constr(lem) := erewriteoA -> !lem.Tactic Notation"erewrite∘A""<-""!" open_constr(lem) := erewriteoA <- !lem.Tactic Notation"erewrite∘A""->""?" open_constr(lem) := erewriteoA -> ? lem.Tactic Notation"erewrite∘A""<-""?" open_constr(lem) := erewriteoA <- ? lem.EndCompose.ModuleExport Concat.(** ** Rewriting modulo associativity of concatenation ([@]) *)(** Turns a lemma of type [f = g] into [forall h, h @ f = h @ g] *)Ltacpreconcat_any H :=
letret := make_tac_under_binders_using_in ltac:(funH => (letH' := freshinrename H into H';
pose proof (fundst (g : dst = _) => @ap _ _ (funf => g @ f) _ _ H') as H))
ltac:(idtac) H inletT := type of ret inletT' := (evalcbv beta in T) inconstr:(ret : T').(** Associates a path fully to the left *)Ltacleft_associate_concat_in H :=
let rec_tac := left_associate_concat_in inletT := type of H inletT' := (evalcbv beta in T) inmatch T' with
| foralla : ?A, @?P a => letret := constr:(funa : A => letH' := H a inltac:(
letH'' := (evalunfold H' in H') inletret := rec_tac H'' inexact ret)) inletT := type of ret inletT' := (evalcbv beta zeta in T) inletret' := (evalcbv beta zeta in ret) inconstr:(ret' : T')
| context[@concat ?A1?x1?y1?z1?a (@concat ?A2?x2?y2?z2?b?c)] =>
(lazymatchevalpattern (@concat A1 x1 y1 z1 a (@concat A2 x2 y2 z2 b c)) in T' with
| ?P _ => letH' := constr:(transport P (concat_p_pp a b c) H) in
rec_tac H'
end)
| ?T' => constr:(H : T')
end.(** We really should just use [setoid_rewrite -> !concat_p_pp] here, to take care of binders, but we threw away Setoids. *)Ltacleft_associate_concat :=
repeatmatch goal with
| _ => rewrite -> !concat_p_pp
| [ |- foralla : ?A, _ ] => letH := freshinintro H;
left_associate_concat;
revert H
end.Ltacleft_associate_concat_in_hyp H :=
letH' := freshinrename H into H';
letH_rep := left_associate_concat_in H' inpose proof H_rep as H;
clear H'.Tactic Notation"rewrite@A"constr(lem) :=
rewriteA_using_helper ltac:(funlem' => rewrite lem') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"rewrite@A""->"constr(lem) :=
rewriteA_using_helper ltac:(funlem' => rewrite -> lem') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"rewrite@A""<-"constr(lem) :=
rewriteA_using_helper ltac:(funlem' => rewrite <- lem') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"rewrite@A""!"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => progressrewrite?lem', ?lem'') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"rewrite@A""?"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => rewrite?lem', ?lem'') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"rewrite@A""->""!"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => progressrewrite -> ?lem', -> ?lem'') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"rewrite@A""<-""!"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => progressrewrite <- ?lem', <- ?lem'') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"rewrite@A""->""?"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => rewrite -> ?lem', -> ?lem'') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"rewrite@A""<-""?"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => rewrite <- ?lem', <- ?lem'') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"erewrite@A"constr(lem) :=
rewriteA_using_helper ltac:(funlem' => erewrite lem') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"erewrite@A""->"constr(lem) :=
rewriteA_using_helper ltac:(funlem' => erewrite -> lem') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"erewrite@A""<-"constr(lem) :=
rewriteA_using_helper ltac:(funlem' => erewrite <- lem') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"erewrite@A""!"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => progresserewrite?lem', ?lem'') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"erewrite@A""?"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => erewrite?lem', ?lem'') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"erewrite@A""->""!"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => progresserewrite -> ?lem', -> ?lem'') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"erewrite@A""<-""!"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => progresserewrite <- ?lem', <- ?lem'') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"erewrite@A""->""?"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => erewrite -> ?lem', -> ?lem'') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"erewrite@A""<-""?"constr(lem) :=
repeat_rewriteA_using_helper ltac:(funlem'lem'' => erewrite <- ?lem', <- ?lem'') lem ltac:(preconcat_any) ltac:(left_associate_concat) ltac:(left_associate_concat_in_hyp).Tactic Notation"rewrite•A"constr(lem) := rewrite@A lem.Tactic Notation"rewrite•A""->"constr(lem) := rewrite@A -> lem.Tactic Notation"rewrite•A""<-"constr(lem) := rewrite@A <- lem.Tactic Notation"rewrite•A""!"constr(lem) := rewrite@A !lem.Tactic Notation"rewrite•A""?"constr(lem) := rewrite@A ? lem.Tactic Notation"rewrite•A""->""!"constr(lem) := rewrite@A -> !lem.Tactic Notation"rewrite•A""<-""!"constr(lem) := rewrite@A <- !lem.Tactic Notation"rewrite•A""->""?"constr(lem) := rewrite@A -> ? lem.Tactic Notation"rewrite•A""<-""?"constr(lem) := rewrite@A <- ? lem.Tactic Notation"erewrite•A" open_constr(lem) := erewrite@A lem.Tactic Notation"erewrite•A""->" open_constr(lem) := erewrite@A -> lem.Tactic Notation"erewrite•A""<-" open_constr(lem) := erewrite@A <- lem.Tactic Notation"erewrite•A""!" open_constr(lem) := erewrite@A !lem.Tactic Notation"erewrite•A""?" open_constr(lem) := erewrite@A ? lem.Tactic Notation"erewrite•A""->""!" open_constr(lem) := erewrite@A -> !lem.Tactic Notation"erewrite•A""<-""!" open_constr(lem) := erewrite@A <- !lem.Tactic Notation"erewrite•A""->""?" open_constr(lem) := erewrite@A -> ? lem.Tactic Notation"erewrite•A""<-""?" open_constr(lem) := erewrite@A <- ? lem.EndConcat.Sectionexamples.Sectioncompose.
A: Type f, g, h, i, j: A -> A
f o g = h -> i o f o (g o j) = i o h o j
A: Type f, g, h, i, j: A -> A
f o g = h -> i o f o (g o j) = i o h o j
A: Type f, g, h, i, j: A -> A H: f o g = h
i o f o (g o j) = i o h o j
A: Type f, g, h, i, j: A -> A H: f o g = h
i o h o j = i o h o j
reflexivity.Abort.
A: Type f, g, h, i, j: A -> A
f o g = h -> i o f o (g o f o g o j) = i o h o h o j
A: Type f, g, h, i, j: A -> A
f o g = h -> i o f o (g o f o g o j) = i o h o h o j
A: Type f, g, h, i, j: A -> A H: f o g = h
i o f o (g o f o g o j) = i o h o h o j
A: Type f, g, h, i, j: A -> A H: f o g = h
i o h o h o j = i o h o h o j
reflexivity.Abort.Endcompose.Sectionconcat.
A: Type a: A f, g, h, i, j: a = a
f @ g = h -> (i @ f) @ (g @ j) = (i @ h) @ j
A: Type a: A f, g, h, i, j: a = a
f @ g = h -> (i @ f) @ (g @ j) = (i @ h) @ j
A: Type a: A f, g, h, i, j: a = a H: f @ g = h
(i @ f) @ (g @ j) = (i @ h) @ j
A: Type a: A f, g, h, i, j: a = a H: f @ g = h
(i @ h) @ j = (i @ h) @ j
reflexivity.Abort.
A: Type a: A f, g, h, i, j: A = A
f @ g = h ->
(i @ f) @ (((g @ f) @ g) @ j) = ((i @ h) @ h) @ j
A: Type a: A f, g, h, i, j: A = A
f @ g = h ->
(i @ f) @ (((g @ f) @ g) @ j) = ((i @ h) @ h) @ j