(** A library of additional tactics. *)

Require Export String.
Open Scope string_scope.


(* *********************************************************************** *)
(** * Extensions of the standard library *)

(** "[remember c as x in |-]" replaces the term [c] by the identifier
    [x] in the conclusion of the current goal and introduces the
    hypothesis [x=c] into the context.  This tactic differs from a
    similar one in the standard library in that the replacmement is
    made only in the conclusion of the goal; the context is left
    unchanged. *)

Tactic Notation "remember" constr(c) "as" ident(x) "in" "|-" :=
  let x := fresh x in
  let H := fresh "Heq" x in
  (set (x := c); assert (H : x = c) by reflexivity; clearbody x).

(** "[unsimpl E]" replaces all occurence of [X] by [E], where [X] is
    the result that tactic [simpl] would give when used to evaluate
    [E]. *)

Tactic Notation "unsimpl" constr(E) :=
  let F := (eval simpl in E) in change F with E.

(** The following tactic calls the [apply] tactic with the first
    hypothesis that succeeds, "first" meaning the hypothesis that
    comes earlist in the context (i.e., higher up in the list). *)

Ltac apply_first_hyp :=
  match reverse goal with
    | H : _ |- _ => apply H
  end.


(* *********************************************************************** *)
(** * Variations on [auto] *)

(** The [auto*] and [eauto*] tactics are intended to be "stronger"
    versions of the [auto] and [eauto] tactics.  Similar to [auto] and
    [eauto], they each take an optional "depth" argument.  Note that
    if we declare these tactics using a single string, e.g., "auto*",
    then the resulting tactics are unusable since they fail to
    parse. *)

Tactic Notation "auto" "*" :=
  try solve [ congruence | auto | intuition auto ].

Tactic Notation "auto" "*" integer(n) :=
  try solve [ congruence | auto n | intuition (auto n) ].

Tactic Notation "eauto" "*" :=
  try solve [ congruence | eauto | intuition eauto ].

Tactic Notation "eauto" "*" integer(n) :=
  try solve [ congruence | eauto n | intuition (eauto n) ].


(* *********************************************************************** *)
(** * Delineating cases in proofs *)

(** This section was taken from the POPLmark Wiki
    ( http://alliance.seas.upenn.edu/~plclub/cgi-bin/poplmark/ ). *)

(** ** Tactic definitions *)

Ltac move_to_top x :=
  match reverse goal with
  | H : _ |- _ => try move x after 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_to_top x
  | 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.

(** ** Example

    One mode of use for the above tactics is to wrap Coq's [induction]
    tactic such that automatically inserts "case" markers into each
    branch of the proof.  For 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" ].
>>

    If you use such customized versions of the induction tactics, then
    the [Case] tactic will verify that you are working on the case
    that you think you are.  You may also use the [Case] tactic with
    the standard version of [induction], in which case no verification
    is done. *)