(* This file is distributed under the terms of the MIT License, also known as the X11 Licence.  A copy of this license is in the README file that accompanied the original distribution of this file.  Based on code written by: Brian Aydemir Aaron Bohannon Arthur Charg\'eraud  With contributions from: Edsko de Vries: uniq_reorder_1, uniq_reorder_2, binds_In_inv *)
(** remove printing ~ *)
(** A library for association lists, i.e., lists of pairs *)
(* *********************************************************************** *)
(** * Implementation *)
(** We implement association lists as lists of key-value pairs.  We use [eq] as the equality on both keys and values.  This is evident primarily in the definitions of [binds] and [maps].  (Implementation note: We can generalize the implementation to arbitrary equivalence relations.  For now, we have chosen not to, in order to keep the implementation simple and to optimize for what we expect is the common case.)  Note that our library has an implicit convention for the "normal form" of an association list.  This normal form requires that a list be built only from [nil] (the empty list), [one] (the singleton list), and [app] (concatenation).  Additionally, concatenations should be associated to the right and the list should not contain any [nil] terms, unless it is the empty list itself.  This allows association lists to be written in a slightly more uniform manner when compared to using both [cons] and [app] to build them.  The downsides are that Coq's [simpl] tactic will simplify instances of [one] down to [cons] and that there are instances in which one needs to write association lists that are not in normal form (e.g., some concatenations will need to be associated to the left).  The [simpl_env] and [rewrite_env] tactics below are designed to minimize the impact of these downsides.  A [Strategy] declaration can be used to prevent Coq's tactics from simplifying [one], if one so desires. *)
(* Implementation note (BEA, XXX): Very little support for - Inversion on association lists when [one] is [opaque]. - No real support for [get]. - No real support for [maps]. - No support for permutations. *)
Module Type ENVIRONMENT.
(* *********************************************************************** *)
(** * Basic definitions *)
(** Implicit arguments are enabled for the following definitions. *)
Set Implicit Arguments.
(** [one] constructs an association list consisting of exactly one binding.  We define an infix notation for it and ensure that the arguments to [app] are interpreted in the right scope, i.e., [list_scope].  Implementation note: The level associated with the notation gives it a higher precedence than the "++" notation for [app].  This should eliminate the need for parentheses.  See the definition below of [uniq], for example. *)
Definition one (C : Type) (item : C) : list C := cons item nil.
Notation "x ~ a" := (one (x, a)) (at level 50) : list_scope.
Arguments Scope app [ type_scope list_scope list_scope ].
Open Scope list_scope.
(** [dom] computes the domain of an association list, i.e., the set consisting of its keys. *)
Fixpoint dom
(C : Type) (E : list (atom*C))
: atoms :=
match E with
| nil => empty
| (x, _) :: E' => add x (dom E')
end.
(** [get] looks up a key in an association list. *)
Fixpoint get
(C : Type) (x : atom) (E : list (atom*C))
: option C :=
match E with
| nil => None
| (y, c) :: F => if eq_atom_dec x y then Some c else get x F
end.
(** [binds] is a ternary predicate that holds when a key-value pair appears somewhere in the given association list. *)
Definition binds
(A : Type) (x : atom) (a : A) (E : list (atom*A))
: Prop :=
List.In (x, a) E.
(** [maps] is a ternary predicate that holds when the first binding in the list for the given key is to the given value. *)
Definition maps
(A : Type) (x : atom) (a : A) (E : list (atom*A))
: Prop :=
get x E = Some a.
(** [disjoint] is a binary predicate that holds when the domains of two association lists are disjoint. *)
Definition disjoint
(A B : Type) (E : list (atom*A)) (F : list (atom*B))
: Prop :=
inter (dom E) (dom F) [<=] empty.
(** [map] applies a function to each of the values in an association list. *)
Definition map
(A B : Type) (f : A -> B) (E : list (atom*A))
: list (atom*B) :=
List.map (fun b => match b with (x, a) => (x, f a) end) E.
(** [uniq] is unary predicate that holds if and only if each key is bound at most once in the given association list.  Note that [uniq] is defined in terms of [one], not [cons]. *)
Inductive uniq (A : Type) : list (atom*A) -> Prop :=
| uniq_nil :
uniq nil
| uniq_push : forall x a E,
uniq E ->
~ In x (dom E) ->
uniq (x ~ a ++ E).
(** Unless stated otherwise, in the remainder of this file, implicit arguments will not be declared by default. *)
Unset Implicit Arguments.
(* *********************************************************************** *)
(** * List properties *)
(** The following properties are used mainly for rewriting association lists into the normal form described above.  See the [simpl_env] and [rewrite_env] tactics below. *)
Section ListProperties.
Variable  X : Type.
Variables x y : X.
Variables l l1 l2 l3 : list X.

(* Specifications: *)
Axiom cons_app_one :
cons x l = one x ++ l.
Axiom cons_app_assoc :
(cons x l1) ++ l2 = cons x (l1 ++ l2).
Axiom app_assoc :
(l1 ++ l2) ++ l3 = l1 ++ (l2 ++ l3).
Axiom app_nil_1 :
nil ++ l = l.
Axiom app_nil_2 :
l ++ nil = l.
Axiom in_nil_iff :
List.In x nil <-> False.
Axiom in_one_iff :
List.In x (one y) <-> x = y.
Axiom in_app_iff :
List.In x (l1 ++ l2) <-> List.In x l1 \/ List.In x l2.