End CofiniteQuantification.
(*************************************************************************)
(** * Tactic support *)
(*************************************************************************)
(** When picking a fresh atom or applying a rule that uses cofinite quantification, choosing a set of atoms to be fresh for can be tedious.  In practice, it is simpler to use a tactic to choose the set to be as large as possible.  The tactic [gather_atoms] is used to collect together all the atoms in the context.  It relies on an auxiliary tactic, [gather_atoms_with] (from MetatheoryAtom), which maps a function that returns a finite set of atoms over all hypotheses with the appropriate type. *)
Ltac gather_atoms ::=
let A := gather_atoms_with (fun x : atoms => x) in
let B := gather_atoms_with (fun x : atom => singleton x) in
let C := gather_atoms_with (fun x : list (atom * typ) => dom x) in
let D := gather_atoms_with (fun x : exp => fv x) in
constr:(A `union` B `union` C `union` D).
(** A number of other, useful tactics are defined by the Metatheory library, and each depends on [gather_atoms].  By redefining [gather_atoms], denoted by the [::=] in its definition below, we automatically update these tactics so that they use the proper notion of "all atoms in the context."  For example, the tactic [(pick fresh x)] chooses an atom fresh for "everything" in the context.  It is the same as [(pick fresh x for L)], except where [L] has been computed by [gather_atoms].  The tactic [(pick fresh x and apply H)] applies a rule [H] that is defined using cofinite quantification.  It automatically instantiates the finite set of atoms to exclude using [gather_atoms]. *)
(** *** Example  Below, we reprove [subst_lc_c] using [(pick fresh and apply)]. Step through the proof below to see how [(pick fresh and apply)] works. *)

Lemma subst_lc_c_alternate_proof : forall (x : atom) u e,
lc_c e ->
lc_c u ->
lc_c ([x ~> u] e).