End Properties.
(* *********************************************************************** *)
(** * The [simpl_env] tactic *)
(** Rewriting hints. *)
Hint Rewrite cons_app_one cons_app_assoc      : rewr_list.
Hint Rewrite app_assoc app_nil_1 app_nil_2    : rewr_list.
Hint Rewrite in_nil_iff in_one_iff in_app_iff : rewr_list_in.
Hint Rewrite map_nil map_one map_cons map_app         : rewr_map.
Hint Rewrite dom_nil dom_one dom_cons dom_app dom_map : rewr_dom.
(** The [simpl_env] tactic rewrites association lists so that they are in the normal form described above.  Similar to the [simpl] tactic, we define "[in *]" and "[in H]" variants of the tactic. *)
Ltac simpl_env :=
autorewrite with rewr_list rewr_map rewr_dom.
Tactic Notation "simpl_env" "in" hyp(H) :=
autorewrite with rewr_list rewr_map rewr_dom in H.
Tactic Notation "simpl_env" "in" "*" :=
autorewrite with rewr_list rewr_map rewr_dom in *.
(* *********************************************************************** *)
(** * The [rewrite_env] tactic *)
(** The tactic [(rewrite_env E)] replaces an association list in the conclusion of the goal with [E].  Suitability for replacement is determined by whether [simpl_env] can put [E] and the chosen environment in the same normal form, up to convertibility's in Coq.  We also define an "[in H]" variant that performs the replacement in a hypothesis [H].  Implementation note: The tactic depends on appropriate morphisms being declared for finite set operations. *)
Tactic Notation "rewrite_env" constr(E) :=
match goal with
| |- context[?x] =>
change x with E
| |- context[?x] =>
replace x with E;
[ | try reflexivity; simpl_env; reflexivity ]
end.
Tactic Notation "rewrite_env" constr(E) "in" hyp(H) :=
match type of H with
| context[?x] =>
change x with E in H
| context[?x] =>
replace x with E in H;
[ | try reflexivity; simpl_env; reflexivity ]
end.
(* *********************************************************************** *)
(** * Induction *)
(** For convenience, we provide a tactic for reasoning by induction on the structure of an association list.  Compared to regular [list] induction, in the "[cons]" case, this tactic automatically destructs the pair at the head of the list and ensures that the list is formed using [one] and [app]. *)

Axiom alist_ind : forall (A : Type) (P : list (atom * A) -> Type),
(P nil) ->
(forall x a xs, P xs -> P (x ~ a ++ xs)) ->
(forall xs, P xs).