Coral.Metalib.LibTactics
(* This file is distributed under the terms of the MIT License, also
known as the X11 Licence. A copy of this license is in the README
file that accompanied the original distribution of this file.
Based on code written by:
Brian Aydemir
Aaron Bohannon
Arthur Charg\'eraud *)
known as the X11 Licence. A copy of this license is in the README
file that accompanied the original distribution of this file.
Based on code written by:
Brian Aydemir
Aaron Bohannon
Arthur Charg\'eraud *)
A library of additional tactics.
Implementation note: We want string_scope to be available for
the Case tactics below, but we want "++" to denote list
concatenation.
Open Scope string_scope.
Open Scope list_scope.
(* *********************************************************************** *)
Variations on built-in tactics
Tactic Notation "unsimpl" constr(E) :=
let F := (eval simpl in E) in change F with E.
fold any not folds all occurrences of not in the goal. It's
useful for "cleaning up" after the intuition tactic.
Tactic Notation "fold" "any" "not" :=
repeat (
match goal with
| H: context [?P → False] |- _ ⇒
fold (¬ P) in H
| |- context [?P → False] ⇒
fold (¬ P)
end).
The following tactics call (e)apply with the first hypothesis
that succeeds, "first" meaning the hypothesis that comes earliest
in the context, i.e., higher up in the list.
Ltac apply_first_hyp :=
match reverse goal with
| H : _ |- _ ⇒ apply H
end.
Ltac eapply_first_hyp :=
match reverse goal with
| H : _ |- _ ⇒ eapply H
end.
These tactics are the same as above, but are tailored for proofs by
well-founded induction.
Ltac apply_first_lt_hyp :=
match reverse goal with
| H : ∀ m:nat, m < ?a → ?b |- _ ⇒ apply H
end.
Ltac eapply_first_lt_hyp :=
match reverse goal with
| H : ∀ m:nat, m < ?a → ?b |- _ ⇒ eapply H
end.
(* *********************************************************************** *)
Tactic Notation "assert_eq" ident(x) constr(v) :=
let H := fresh in
assert (x = v) as H by reflexivity;
clear H.
Tactic Notation "Case_aux" ident(x) constr(name) :=
first [
set (x := name); move x at top
| assert_eq x name
| fail 1 "because we are working on a different case." ].
Ltac Case name := Case_aux case name.
Ltac SCase name := Case_aux subcase name.
Ltac SSCase name := Case_aux subsubcase name.
Ltac SSSCase name := Case_aux subsubsubcase name.
Ltac SSSSCase name := Case_aux subsubsubsubcase name.
Example
Tactic Notation "induction" "nat" ident(n) := induction n; [ Case "O" | Case "S" ]. Tactic Notation "sub" "induction" "nat" ident(n) := induction n; [ SCase "O" | SCase "S" ]. Tactic Notation "sub" "sub" "induction" "nat" ident(n) := induction n; [ SSCase "O" | SSCase "S" ].
induction nat n. (* or [induction n] *) Case "O". ... Case "S". ...
(* *********************************************************************** *)
Tactics for working with lists and proof contexts
Ltac ltac_map F :=
let rec map acc :=
match goal with
| H : _ |- _ ⇒
let FH := constr:(F H) in
match acc with
| context [FH] ⇒ fail 1
| _ ⇒ map (List.cons FH acc)
end
| _ ⇒ acc
end
in
let rec ret T :=
match T with
| _ → ?T' ⇒ ret T'
| ?T' ⇒ T'
end
in
let T := ret ltac:(type of F) in
let res := map (@List.nil T) in
eval simpl in res.
Ltac ltac_map_list tac xs :=
match xs with
| List.nil ⇒ idtac
| List.cons ?x ?xs ⇒ tac x; ltac_map_list tac xs
end.
ltac_remove_dups takes a list and removes duplicate items from
it. The supplied list must, after simplification via simpl, be
built from only nil and cons. Duplicates are recognized only
"up to syntax," i.e., the limitations of Ltac's context
check.
Ltac ltac_remove_dups xs :=
let rec remove xs acc :=
match xs with
| List.nil ⇒ acc
| List.cons ?x ?xs ⇒
match acc with
| context [x] ⇒ remove xs acc
| _ ⇒ remove xs (List.cons x acc)
end
end
in
match type of xs with
| List.list ?A ⇒
let xs := eval simpl in xs in
let xs := remove xs (@List.nil A) in
eval simpl in (List.rev xs)
end.