ladder-calculus/coq-Fsub/Metatheory.v

95 lines
3.2 KiB
Coq

(** Library for programming languages metatheory.
Authors: Brian Aydemir and Arthur Charguéraud, with help from
Aaron Bohannon, Benjamin Pierce, Jeffrey Vaughan, Dimitrios
Vytiniotis, Stephanie Weirich, and Steve Zdancewic. *)
Require Export AdditionalTactics.
Require Export Atom.
Require Export Environment.
(* ********************************************************************** *)
(** * Notations *)
(** Decidable equality on atoms and natural numbers may be written
using natural notation. *)
Notation "x == y" :=
(eq_atom_dec x y) (at level 67) : metatheory_scope.
Notation "i === j" :=
(Peano_dec.eq_nat_dec i j) (at level 67) : metatheory_scope.
(** Common set operations may be written using infix notation. *)
Notation "E `union` F" :=
(AtomSet.F.union E F)
(at level 69, right associativity, format "E `union` '/' F")
: set_scope.
Notation "x `in` E" :=
(AtomSet.F.In x E) (at level 69) : set_scope.
Notation "x `notin` E" :=
(~ AtomSet.F.In x E) (at level 69) : set_scope.
(** The empty set may be written similarly to informal practice. *)
Notation "{}" :=
(AtomSet.F.empty) : metatheory_scope.
(** It is useful to have an abbreviation for constructing singleton
sets. *)
Notation singleton := (AtomSet.F.singleton).
(** Open the notation scopes declared above. *)
Open Scope metatheory_scope.
Open Scope set_scope.
(* ********************************************************************** *)
(** * Tactic for working with cofinite quantification *)
(** Consider a rule [H] (equivalently, hypothesis, constructor, lemma,
etc.) of the form [(forall L ..., ... -> (forall y, y `notin` L ->
P) -> ... -> Q)], where [Q]'s outermost constructor is not a
[forall]. There may be multiple hypotheses of with the indicated
form in [H].
The tactic [(pick fresh x and apply H)] applies [H] to the current
goal, instantiating [H]'s first argument (i.e., [L]) with the
finite set of atoms [L']. In each new subgoal arising from a
hypothesis of the form [(forall y, y `notin` L -> P)], the atom
[y] is introduced as [x], and [(y `notin` L)] is introduced using
a generated name.
If we view [H] as a rule that uses cofinite quantification, the
tactic can be read as picking a sufficiently fresh atom to open a
term with. *)
Tactic Notation
"pick" "fresh" ident(atom_name)
"excluding" constr(L)
"and" "apply" constr(H) :=
let L := beautify_fset L in
first [apply (@H L) | eapply (@H L)];
match goal with
| |- forall _, _ `notin` _ -> _ =>
let Fr := fresh "Fr" in intros atom_name Fr
| |- forall _, _ `notin` _ -> _ =>
fail 1 "because" atom_name "is already defined"
| _ =>
idtac
end.
(* ********************************************************************** *)
(** * Automation *)
(** These hints should discharge many of the freshness and inequality
goals that arise in programming language metatheory proofs, in
particular those arising from cofinite quantification. *)
Hint Resolve notin_empty notin_singleton notin_union.
Hint Extern 4 (_ `notin` _) => simpl_env; notin_solve.
Hint Extern 4 (_ <> _ :> atom) => simpl_env; notin_solve.