(*************************************************************************)
(**                                                                      *)
(** * Typing: preservation and progress                                  *)
(**                                                                      *)
(*************************************************************************)
(*************************************************************************)
(** * Typing contexts *)
(*************************************************************************)
(** We represent contexts as association lists (lists of pairs of keys and values) whose keys are [atom]s.   *)
(** For STLC, contexts bind [atom]s to [typ]s.  We define an abbreviation [ctx] for the type of these contexts.  Lists are defined in Coq's standard library, with the constructors [nil] and [cons].  The list library includes the [::] notation for cons as well as standard list operations such as append, map, and fold. The infix operation "++" is list append.  The Metatheory library extends this reasoning by instantiating the AssocList library to provide support for association lists whose keys are [atom]s.  Everything in this library is polymorphic over the type of objects bound in the context.  Look in AssocList for additional details about the functions and predicates that we mention below.  *)
(** Context equality *)
(** When reasoning about contexts, we often need to talk about bindings in the "middle" of an context. Therefore, it is common for lemmas and definitions to use list append in their statements. Unfortunately, list append is associative, so two Coq expressions may denote the same context even though they are not equal.  The tactic [simpl_env] reassociates all concatenations of contexts to the right.  *)
(** To make contexts easy to read, instead of building them from [nil] and [cons], we prefer to build them from the following components: - [nil]: The empty list. - [one]: Lists consisting of exactly one item. - [++]:  List append. *)
(** The simpl_env tactic actually puts lists built from only nil, one and [++] into a "normal form". This process reassociates all appends to the right, removes extraneous nils and converts cons to singleton lists with an append. *)
(* /FULL *)
(** Context operations. *)
(** The ternary predicate [binds] holds when a given binding is present somewhere in an context. *)
(** The function [dom] computes the domain of an context, returning a finite set of [atom]s. Note that we cannot use Coq's equality for finite sets, we must instead use a defined relation [=] for atom set equality. *)
(** The unary predicate [uniq] holds when each atom is bound at most once in an context. *)

Lemma uniq_demo : forall (x y : atom) (T : typ),
x <> y -> uniq ([(x,T)] ++ [(y, T)]).