Library AdditionalTactics



A library of additional tactics.

Require Import List.
Require Import String.

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.

Extensions and variations of standard tactics


"unsimpl E" replaces all occurences of X in the goal by E, where X is the result that tactic simpl would give when used to reduce E.

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

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.

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.

Implementation note: 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


Tactic definitions


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



One mode of use for the above tactics is to wrap Coq's induction tactic such that it 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.

Tactics for working with lists and proof contexts


ltac_map applies a function F, with return type T and exactly one non-implicit argument, to everything in the context such that the application type checks. The tactic returns a list containing the results of the applications.

Implementation note: The check for duplicates in the accumulator (match acc with ...) is necessary to ensure that the tactic does not go into an infinite loop.

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_map_list tac xs applies tac to each element of xs, where xs is a Coq list.

Ltac ltac_map_list tac xs :=
  match xs with
    | List.nilidtac
    | 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.nilacc
      | 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.

ltac_fold_and_simpl is a wrapper for List.fold_right that does some preliminary simplification and removal of duplicates on the supplied list.

Ltac ltac_fold_and_simpl f start xs :=
  let xs := eval simpl in xs in
  let xs := ltac_remove_dups xs in
  let xs := eval simpl in (List.fold_right f start xs) in
  xs.

This page has been generated by coqdoc