(** * LibTactics: A Collection of Handy General-Purpose Tactics *)
(* $Date: 2010-10-14 12:27:18 -0400 (Thu, 14 Oct 2010) $ *)
(* Chapter maintained by Arthur Chargueraud *)
(** This file contains a set of tactics that extends the set of builtin tactics provided with the standard distribution of Coq. It intends to overcome a number of limitations of the standard set of tactics, and thereby to help user to write shorter and more robust scripts.  Hopefully, Coq tactics will be improved as time goes by, and this file should ultimately be useless. In the meanwhile, serious Coq users will probably find it very useful.  The present file contains the implementation and the detailed documentation of those tactics. The SF reader need not read this file; instead, he/she is encouraged to read the chapter named UseTactics.v, which is gentle introduction to the most useful tactics from the LibTactic library. *)
(** The main features offered are: - More convenient syntax for naming hypotheses, with tactics for introduction and inversion that take as input only the name of hypotheses of type [Prop], rather than the name of all variables. - Tactics providing true support for manipulating N-ary conjunctions, disjunctions and existentials, hidding the fact that the underlying implementation is based on binary predicates. - Convenient support for automation: tactic followed with the symbol "~" or "*" will call automation on the generated subgoals. Symbol "~" stands for [auto] and "*" for [intuition eauto]. These bindings can be customized. - Forward-chaining tactics are provided to instantiate lemmas either with variable or hypotheses or a mix of both. - A more powerful implementation of [apply] is provided (it is based on [refine] and thus behaves better with respect to conversion). - An improved inversion tactic which substitutes equalities on variables generated by the standard inversion mecanism. Moreover, it supports the elimination of dependently-typed equalities (requires axiom [K], which is a weak form of Proof Irrelevance). - Tactics for saving time when writing proofs, with tactics to asserts hypotheses or sub-goals, and improved tactics for clearing, renaming, and sorting hypotheses. *)
(** External credits: - thanks to Xavier Leroy for providing the idea of tactic [forward], - thanks to Georges Gonthier for the implementation trick in [rapply], *)
Set Implicit Arguments.
(* ********************************************************************** *)
(** * Additional notations for Coq *)
(* ---------------------------------------------------------------------- *)
(** ** N-ary Existentials *)
(** [exists T1 ... TN, P] is a shorthand for [exists T1, ..., exists TN, P]. Note that [Coq.Program.Syntax] already defines exists for arity up to 4. *)
Notation "'exists' x1 ',' P" :=
(exists x1, P)
(at level 200, x1 ident,
right associativity) : type_scope.
Notation "'exists' x1 x2 ',' P" :=
(exists x1, exists x2, P)
(at level 200, x1 ident, x2 ident,
right associativity) : type_scope.
Notation "'exists' x1 x2 x3 ',' P" :=
(exists x1, exists x2, exists x3, P)
(at level 200, x1 ident, x2 ident, x3 ident,
right associativity) : type_scope.
Notation "'exists' x1 x2 x3 x4 ',' P" :=
(exists x1, exists x2, exists x3, exists x4, P)
(at level 200, x1 ident, x2 ident, x3 ident, x4 ident,
right associativity) : type_scope.
Notation "'exists' x1 x2 x3 x4 x5 ',' P" :=
(exists x1, exists x2, exists x3, exists x4, exists x5, P)
(at level 200, x1 ident, x2 ident, x3 ident, x4 ident, x5 ident,
right associativity) : type_scope.
Notation "'exists' x1 x2 x3 x4 x5 x6 ',' P" :=
(exists x1, exists x2, exists x3, exists x4, exists x5, exists x6, P)
(at level 200, x1 ident, x2 ident, x3 ident, x4 ident, x5 ident,
x6 ident,
right associativity) : type_scope.
Notation "'exists' x1 x2 x3 x4 x5 x6 x7 ',' P" :=
(exists x1, exists x2, exists x3, exists x4, exists x5, exists x6,
exists x7, P)
(at level 200, x1 ident, x2 ident, x3 ident, x4 ident, x5 ident,
x6 ident, x7 ident,
right associativity) : type_scope.
Notation "'exists' x1 x2 x3 x4 x5 x6 x7 x8 ',' P" :=
(exists x1, exists x2, exists x3, exists x4, exists x5, exists x6,
exists x7, exists x8, P)
(at level 200, x1 ident, x2 ident, x3 ident, x4 ident, x5 ident,
x6 ident, x7 ident, x8 ident,
right associativity) : type_scope.
Notation "'exists' x1 x2 x3 x4 x5 x6 x7 x8 x9 ',' P" :=
(exists x1, exists x2, exists x3, exists x4, exists x5, exists x6,
exists x7, exists x8, exists x9, P)
(at level 200, x1 ident, x2 ident, x3 ident, x4 ident, x5 ident,
x6 ident, x7 ident, x8 ident, x9 ident,
right associativity) : type_scope.
Notation "'exists' x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 ',' P" :=
(exists x1, exists x2, exists x3, exists x4, exists x5, exists x6,
exists x7, exists x8, exists x9, exists x10, P)
(at level 200, x1 ident, x2 ident, x3 ident, x4 ident, x5 ident,
x6 ident, x7 ident, x8 ident, x9 ident, x10 ident,
right associativity) : type_scope.
(* ********************************************************************** *)
(** * Tools for programming with Ltac *)
(* ---------------------------------------------------------------------- *)
(** ** Identity continuation *)
Ltac idcont tt :=
idtac.
(* ---------------------------------------------------------------------- *)
(** ** Untyped arguments for tactics *)
(** Any Coq value can be boxed into the type [Boxer]. This is useful to use Coq computations for implementing tactics. *)
Inductive Boxer : Type :=
| boxer : forall (A:Type), A -> Boxer.
(* ---------------------------------------------------------------------- *)
(** ** Optional arguments for tactics  *)
(** [ltac_no_arg] is a constant that can be used to simulate optional arguments in tactic definitions. Use [mytactic ltac_no_arg] on the tactic invokation, and use [match arg with ltac_no_arg => ..] or [match type of arg with ltac_No_arg  => ..] to test whether an argument was provided. *)
Inductive ltac_No_arg : Set :=
| ltac_no_arg : ltac_No_arg.
(* ---------------------------------------------------------------------- *)
(** ** Wildcard arguments for tactics  *)
(** [ltac_wild] is a constant that can be used to simulate wildcard arguments in tactic definitions. Notation is [__]. *)
Inductive ltac_Wild : Set :=
| ltac_wild : ltac_Wild.
Notation "'__'" := ltac_wild : ltac_scope.
(** [ltac_wilds] is another constant that is typically used to simulate a sequence of [N] wildcards, with [N] chosen appropriately depending on the context. Notation is [___]. *)
Inductive ltac_Wilds : Set :=
| ltac_wilds : ltac_Wilds.
Notation "'___'" := ltac_wilds : ltac_scope.
Open Scope ltac_scope.
(* ---------------------------------------------------------------------- *)
(** ** Position markers *)
(** [ltac_Mark] and [ltac_mark] are dummy definitions used as sentinel by tactics, to mark a certain position in the context or in the goal. *)
Inductive ltac_Mark : Type :=
| ltac_mark : ltac_Mark.
(** [gen_until_mark] repeats [generalize] on hypotheses from the context, starting from the bottom and stopping as soon as reaching an hypothesis of type [Mark]. If fails if [Mark] does not appear in the context. *)
Ltac gen_until_mark :=
match goal with H: ?T |- _ =>
match T with
| ltac_Mark => clear H
| _ => generalize H; clear H; gen_until_mark
end end.
(** [intro_until_mark] repeats [intro] until reaching an hypothesis of type [Mark]. It throws away the hypothesis [Mark]. It fails if [Mark] does not appear as an hypothesis in the goal. *)
Ltac intro_until_mark :=
match goal with
| |- (ltac_Mark -> _) => intros _
| _ => intro; intro_until_mark
end.
(* ---------------------------------------------------------------------- *)
(** ** List of arguments for tactics  *)
(** A datatype of type [list Boxer] is used to manipulate list of Coq values in ltac. Notation is [>> v1 v2 ... vN] for building a list containing the values [v1] through [vN]. *)
Notation "'>>'" :=
(@nil Boxer)
(at level 0)
: ltac_scope.
Notation "'>>' v1" :=
((boxer v1)::nil)
(at level 0, v1 at level 0)
: ltac_scope.
Notation "'>>' v1 v2" :=
((boxer v1)::(boxer v2)::nil)
(at level 0, v1 at level 0, v2 at level 0)
: ltac_scope.
Notation "'>>' v1 v2 v3" :=
((boxer v1)::(boxer v2)::(boxer v3)::nil)
(at level 0, v1 at level 0, v2 at level 0, v3 at level 0)
: ltac_scope.
Notation "'>>' v1 v2 v3 v4" :=
((boxer v1)::(boxer v2)::(boxer v3)::(boxer v4)::nil)
(at level 0, v1 at level 0, v2 at level 0, v3 at level 0,
v4 at level 0)
: ltac_scope.
Notation "'>>' v1 v2 v3 v4 v5" :=
((boxer v1)::(boxer v2)::(boxer v3)::(boxer v4)::(boxer v5)::nil)
(at level 0, v1 at level 0, v2 at level 0, v3 at level 0,
v4 at level 0, v5 at level 0)
: ltac_scope.
Notation "'>>' v1 v2 v3 v4 v5 v6" :=
((boxer v1)::(boxer v2)::(boxer v3)::(boxer v4)::(boxer v5)
::(boxer v6)::nil)
(at level 0, v1 at level 0, v2 at level 0, v3 at level 0,
v4 at level 0, v5 at level 0, v6 at level 0)
: ltac_scope.
Notation "'>>' v1 v2 v3 v4 v5 v6 v7" :=
((boxer v1)::(boxer v2)::(boxer v3)::(boxer v4)::(boxer v5)
::(boxer v6)::(boxer v7)::nil)
(at level 0, v1 at level 0, v2 at level 0, v3 at level 0,
v4 at level 0, v5 at level 0, v6 at level 0, v7 at level 0)
: ltac_scope.
Notation "'>>' v1 v2 v3 v4 v5 v6 v7 v8" :=
((boxer v1)::(boxer v2)::(boxer v3)::(boxer v4)::(boxer v5)
::(boxer v6)::(boxer v7)::(boxer v8)::nil)
(at level 0, v1 at level 0, v2 at level 0, v3 at level 0,
v4 at level 0, v5 at level 0, v6 at level 0, v7 at level 0,
v8 at level 0)
: ltac_scope.
Notation "'>>' v1 v2 v3 v4 v5 v6 v7 v8 v9" :=
((boxer v1)::(boxer v2)::(boxer v3)::(boxer v4)::(boxer v5)
::(boxer v6)::(boxer v7)::(boxer v8)::(boxer v9)::nil)
(at level 0, v1 at level 0, v2 at level 0, v3 at level 0,
v4 at level 0, v5 at level 0, v6 at level 0, v7 at level 0,
v8 at level 0, v9 at level 0)
: ltac_scope.
Notation "'>>' v1 v2 v3 v4 v5 v6 v7 v8 v9 v10" :=
((boxer v1)::(boxer v2)::(boxer v3)::(boxer v4)::(boxer v5)
::(boxer v6)::(boxer v7)::(boxer v8)::(boxer v9)::(boxer v10)::nil)
(at level 0, v1 at level 0, v2 at level 0, v3 at level 0,
v4 at level 0, v5 at level 0, v6 at level 0, v7 at level 0,
v8 at level 0, v9 at level 0, v10 at level 0)
: ltac_scope.
Notation "'>>' v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11" :=
((boxer v1)::(boxer v2)::(boxer v3)::(boxer v4)::(boxer v5)
::(boxer v6)::(boxer v7)::(boxer v8)::(boxer v9)::(boxer v10)
::(boxer v11)::nil)
(at level 0, v1 at level 0, v2 at level 0, v3 at level 0,
v4 at level 0, v5 at level 0, v6 at level 0, v7 at level 0,
v8 at level 0, v9 at level 0, v10 at level 0, v11 at level 0)
: ltac_scope.
Notation "'>>' v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12" :=
((boxer v1)::(boxer v2)::(boxer v3)::(boxer v4)::(boxer v5)
::(boxer v6)::(boxer v7)::(boxer v8)::(boxer v9)::(boxer v10)
::(boxer v11)::(boxer v12)::nil)
(at level 0, v1 at level 0, v2 at level 0, v3 at level 0,
v4 at level 0, v5 at level 0, v6 at level 0, v7 at level 0,
v8 at level 0, v9 at level 0, v10 at level 0, v11 at level 0,
v12 at level 0)
: ltac_scope.
Notation "'>>' v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12 v13" :=
((boxer v1)::(boxer v2)::(boxer v3)::(boxer v4)::(boxer v5)
::(boxer v6)::(boxer v7)::(boxer v8)::(boxer v9)::(boxer v10)
::(boxer v11)::(boxer v12)::(boxer v13)::nil)
(at level 0, v1 at level 0, v2 at level 0, v3 at level 0,
v4 at level 0, v5 at level 0, v6 at level 0, v7 at level 0,
v8 at level 0, v9 at level 0, v10 at level 0, v11 at level 0,
v12 at level 0, v13 at level 0)
: ltac_scope.
(** The tactic [list_boxer_of] inputs a term [E] and returns a term of type "list boxer", according to the following rules: - if [E] is already of type "list Boxer", then it returns [E]; - otherwise, it returns the list [(boxer E)::nil]. *)
Ltac list_boxer_of E :=
match type of E with
| List.list Boxer => constr:(E)
| _ => constr:((boxer E)::nil)
end.
(* ---------------------------------------------------------------------- *)
(** ** Databases of lemmas  *)
(** Use the hint facility to implement a database mapping terms to terms. To declare a new database, use a definition: [Definition mydatabase := True.]  Then, to map [mykey] to [myvalue], write the hint: [Hint Extern 1 (Register mydatabase mykey) => Provide myvalue.]  Finally, to query the value associated with a key, run the tactic [ltac_database_get mydatabase mykey]. This will leave at the head of the goal the term [myvalue]. It can then be named and exploited using [intro]. *)
Definition ltac_database (D:Boxer) (T:Boxer) (A:Boxer) := True.
Notation "'Register' D T" := (ltac_database (boxer D) (boxer T) _)
(at level 69, D at level 0, T at level 0).

Lemma ltac_database_provide : forall (A:Boxer) (D:Boxer) (T:Boxer),
ltac_database D T A.