Definition empty : gen_env A := nil.Definition single x v := (x, v) :: nil.Fixpoint singles xs vs : gen_env A :=
  match xs, vs with
    | x :: xs, v :: vs => (x, v) :: (singles xs vs)
    | _, _ => nil
  end.Definition concat E F := F ++ E.Fixpoint get x E : option A :=
  match E with
    | nil => None
    | (y, v) :: E' => if eq_keys_dec x y then Some v else get x E'
  end.Fixpoint dom E : list TVar :=
  match E with
    | nil => nil
    | (x, _) :: E' => x :: (dom E')
  end.Fixpoint img E : list A :=
  match E with
    | nil => nil
    | (_, v) :: E' => v :: (img E')
  end.Definition belongs x E :=
  List.In x (dom E).Definition all_belongs xs E :=
  forall x, List.In x xs -> belongs x E.Definition notin x E := 
  ~ belongs x E.Definition all_notin xs E :=
  forall x, List.In x xs -> notin x E.Fixpoint map f E : gen_env B :=
  match E with
    | nil => nil
    | (x, v) :: E' => (x, f v) :: map f E'
  end.Fixpoint update_one E x v : gen_env A :=
  match E with
    | nil => nil
    | (y, v') :: E' =>
      if eq_keys_dec x y then (y, v) :: E'
        else (y, v') :: (update_one E' x v)
  end.Fixpoint update E F : gen_env A :=
  match F with
    | nil => E
    | (x, v) :: F' => update_one (update E F') x v
  end.Fixpoint remove x E : gen_env A :=
  match E with
    | nil => nil
    | (y, v) :: E => if eq_keys_dec x y then E else (y, v) :: (remove x E)
  end.Fixpoint all_remove xs E : gen_env A :=
  match xs with
    | nil => E
    | x :: xs => all_remove xs (remove x E)
  end.Inductive ok : gen_env A -> Prop :=
| ok_nil : ok nil
| ok_cons : forall x v F, ok F ∧ notin x F -> ok (concat F (single x v))
.Inductive ok : gen_env A -> Prop :=
| ok_nil : ok nil
| ok_cons : forall x v F, ok F ∧ notin x F -> ok (concat F (single x v))
.Inductive ok : gen_env A -> Prop :=
| ok_nil : ok nil
| ok_cons : forall x v F, ok F ∧ notin x F -> ok (concat F (single x v))
.(** [x ∶ v] is the notation for a singleton environment mapping x to v. *)

Notation "x '∶' v" := (single x v)
  (at level 63) : gen_env_scope.(** [xs ∷ vs] is the notation for an environment mapping xs to vs. *)

Notation "xs '∷' vs" := (singles xs vs)
  (at level 63) : gen_env_scope.(** [E & F] is the notation for concatenation of E and F. *)

Notation "E '&' F" := (concat E F) 
  (at level 65, left associativity) : gen_env_scope.(** [E ∖ { x } ] is the notation for removing x from E. *)

Notation "E '∖' '{' x '}'" := (remove x E) 
  (at level 64, left associativity) : gen_env_scope.(** [E ∖ xs ] is the notation for removing xs from E. *)

Notation "E '∖' xs" := (all_remove xs E) 
  (at level 64, left associativity) : gen_env_scope.(** [E '[' x '<-' v ']' ] is the notation for updating x in E with v. *)

Notation "E '[' x '<-' v ']'" := (update_one E x v) 
  (at level 65, left associativity) : gen_env_scope.(** [E ::= F] is the notation for updating of E with F. *)

Notation "E '::=' F" := (update E F) 
  (at level 65, left associativity) : gen_env_scope.(** [x ∈ E] to be read x is bound in E. *)

Notation "x '∈' E" := (belongs x E)
  (at level 67) : gen_env_scope.(** [xs ⊂ E] to be read xs are bound in E. *)

Notation "xs '⊂' E" := (all_belongs xs E)
  (at level 67) : gen_env_scope.(** [x '∉' E] to be read x is unbound in E. *)

Notation "x '∉' E" := (notin x E)
  (at level 67) : gen_env_scope.(** [xs '⊄' E] to be read xs are unbound in E. *)

Notation "xs '⊄' E" := (all_notin xs E)
  (at level 67) : gen_env_scope.

(* Specifications: *)
Lemma env_ind : forall (P : gen_env A -> Prop), (P (@empty A)) -> (forall E x v, P E -> P (E & (x ∶ v))) -> (forall E, P E).
Lemma singles_empty : nil ∷ nil = (@empty A).
Lemma singles_cons : forall x xs v vs, (x :: xs) ∷ (v :: vs) = (xs ∷ vs) & (x ∶ v).
Lemma singles_empty_r : forall xs, xs ∷ nil = (@empty A).
Lemma singles_empty_l : forall vs, nil ∷ vs = (@empty A).
Lemma concat_empty_r : forall E, E & (@empty A) = E.
Lemma concat_empty_l : forall E, (@empty A) & E = E.
Lemma concat_assoc : forall E F G, E & (F & G) = (E & F) & G.
Lemma get_empty : forall x, get x (@empty A) = None.
Lemma get_single_eq : forall x y v, x = y -> get x (y ∶ v) = Some v.
Lemma get_single_eq_inv : forall x y v w, get x (y ∶ w) = Some v -> x = y /\ v = w.
Lemma get_dec : forall x E, { v : A | get x E = Some v } + { get x E = None }.
Lemma get_concat_r : forall x y v E, x = y -> get x (E & (y ∶ v)) = Some v.
Lemma get_concat_l : forall x y v E, x <> y -> get x (E & (y ∶ v)) = get x E.
Lemma get_concat_inv : forall x y v w E, get x (E & (y ∶ v)) = Some w -> (x = y /\ v = w) \/ (x <> y /\ get x E = Some w).
Lemma dom_empty : dom (@empty A) = nil.
Lemma dom_empty_inv : forall E, dom (E) = nil -> E = (@empty A).
Lemma dom_single : forall x v, dom (x ∶ v) = x :: nil.
Lemma dom_singles : forall xs vs, length xs = length vs -> dom (xs ∷ vs) = xs.
Lemma dom_singles_incl : forall xs vs, List.incl (dom (xs ∷ vs)) xs.
Lemma dom_concat : forall E F, dom (E & F) = List.app (dom F) (dom E).
Lemma img_empty : img (@empty A) = nil.
Lemma img_empty_inv : forall E, img (E) = nil -> E = (@empty A).
Lemma img_single : forall x v, img (x ∶ v) = v :: nil.
Lemma img_singles : forall xs vs, length xs = length vs -> img (xs ∷ vs) = vs.
Lemma img_singles_incl : forall xs vs, List.incl (img (xs ∷ vs)) vs.
Lemma img_concat : forall E F, img (E & F) = List.app (img F) (img E).
Lemma dom_img_id : forall E, (dom E) ∷ (img E) = E.
Lemma length_dom_img_eq : forall E, length (dom E) = length (img E).
Lemma belongs_empty : forall x, x ∈ (@empty A) -> False.
Lemma belongs_single : forall x y v, x = y -> x ∈ (y ∶ v).
Lemma belongs_single_inv : forall x y v, x ∈ (y ∶ v) -> x = y.
Lemma belongs_singles : forall x xs vs, length xs = length vs -> List.In x xs -> x ∈ (xs ∷ vs).
Lemma belongs_singles_inv : forall x xs vs, length xs = length vs -> x ∈ (xs ∷ vs) -> List.In x xs.
Lemma belongs_concat_l : forall x F G, x ∈ F -> x ∈ (F & G).
Lemma belongs_concat_r : forall x F G, x ∈ F -> x ∈ (G & F).
Lemma belongs_concat_inv : forall x F G, x ∈ (F & G) -> x ∈ F ∨ x ∈ G.
Lemma belongs_dom : forall x E, x ∈ E -> List.In x (dom E).
Lemma belongs_dom_inv : forall x E, List.In x (dom E) -> x ∈ E.
Lemma all_belongs_def : forall xs E, (forall x, List.In x xs -> x ∈ E) -> xs ⊂ E.
Lemma all_belongs_def_inv : forall xs E, xs ⊂ E -> (forall x, List.In x xs -> x ∈ E).
Lemma all_belongs_belongs : forall x xs E, (x :: xs) ⊂ E -> x ∈ E ∧ xs ⊂ E.
Lemma belongs_all_belongs : forall x xs E, x ∈ E ∧ xs ⊂ E -> (x :: xs) ⊂ E.
Lemma all_belongs_empty : forall xs, xs ⊂ (@empty A) -> xs = nil.
Lemma all_belongs_nil : forall E, nil ⊂ E.
Lemma all_belongs_single : forall xs y v, xs = y :: nil -> xs ⊂ (y ∶ v).
Lemma all_belongs_single_inv : forall xs y v, length xs = 1 -> xs ⊂ (y ∶ v) -> xs = y :: nil.
Lemma all_belongs_singles : forall xs ys vs, length ys = length vs -> List.incl xs ys -> xs ⊂ (ys ∷ vs).
Lemma all_belongs_singles_inv : forall xs ys vs, xs ⊂ (ys ∷ vs) -> List.incl xs ys.
Lemma all_belongs_concat_l : forall xs F G, xs ⊂ F -> xs ⊂ (F & G).
Lemma all_belongs_concat_r : forall xs F G, xs ⊂ F -> xs ⊂ (G & F).
Lemma all_belongs_dom : forall xs E, xs ⊂ E -> List.incl xs (dom E).
Lemma all_belongs_dom_inv : forall xs E F, List.incl xs (dom E) -> xs ⊂ E.
Lemma notin_belongs : forall x E, x ∉ E -> ¬ x ∈ E.
Lemma belongs_notin : forall x E, x ∈ E -> ¬ x ∉ E.
Lemma not_belongs_notin : forall A x (E : gen_env A), ¬ x ∈ E -> x ∉ E.
Lemma notin_belongs_neq : forall x y E, x ∈ E -> y ∉ E -> x <> y.
Lemma notin_empty : forall x, x ∉ (@empty A).
Lemma notin_single : forall x y v, x <> y -> x ∉ (y ∶ v).
Lemma notin_single_inv : forall x y v, x ∉ (y ∶ v) -> x <> y.
Lemma notin_singles : forall x xs vs, ¬ List.In x xs -> x ∉ (xs ∷ vs).
Lemma notin_singles_inv : forall x xs vs, length xs = length vs -> x ∉ (xs ∷ vs) -> ¬ List.In x xs.
Lemma notin_concat : forall x F G, x ∉ F -> x ∉ G -> x ∉ (F & G).
Lemma notin_concat_inv : forall x F G, x ∉ (F & G) -> x ∉ F ∧ x ∉ G.
Lemma notin_dom : forall x E, x ∉ E -> ¬ List.In x (dom E).
Lemma notin_dom_inv : forall x E F, ¬ List.In x (dom E) -> x ∉ E.
Lemma all_notin_empty_l : forall E, nil ⊄ E.
Lemma all_notin_def : forall xs E, (forall x, List.In x xs -> x ∉ E) -> xs ⊄ E.
Lemma all_notin_def_inv : forall xs E, xs ⊄ E -> (forall x, List.In x xs -> x ∉ E).
Lemma all_notin_notin : forall x xs E, (x :: xs) ⊄ E -> x ∉ E ∧ xs ⊄ E.
Lemma notin_all_notin : forall x xs E, x ∉ E ∧ xs ⊄ E -> (x :: xs) ⊄ E.
Lemma all_notin_belongs_neq : forall x ys E, x ∈ E -> ys ⊄ E -> ¬ List.In x ys.
Lemma all_notin_empty_r : forall xs, xs ⊄ (@empty A).
Lemma all_notin_nil : forall E, nil ⊄ E.
Lemma all_notin_single : forall xs y v, ¬ List.In y xs -> xs ⊄ (y ∶ v).
Lemma all_notin_single_inv : forall xs y v, xs ⊄ (y ∶ v) -> ¬ List.In y xs.
Lemma all_notin_singles : forall xs ys vs, List.Forall (fun x => ¬ List.In x ys) xs -> xs ⊄ (ys ∷ vs).
Lemma all_notin_singles_inv : forall xs ys vs, length ys = length vs -> xs ⊄ (ys ∷ vs) -> List.Forall (fun x => ¬ List.In x ys) xs.
Lemma all_notin_concat : forall xs F G, xs ⊄ F -> xs ⊄ G -> xs ⊄ (F & G).
Lemma all_notin_concat_inv : forall xs F G, xs ⊄ (F & G) -> xs ⊄ F ∧ xs ⊄ G.
Lemma all_notin_dom : forall xs E, xs ⊄ E -> List.Forall (fun x => ¬ List.In x (dom E)) xs.
Lemma all_notin_dom_inv : forall xs E, List.Forall (fun x => ¬ List.In x (dom E)) xs -> xs ⊄ E.
Lemma map_empty : forall f, map f (@empty A) = (@empty B).
Lemma map_single : forall f x v, map f (x ∶ v) = x ∶ (f v).
Lemma map_singles : forall f xs vs, map f (xs ∷ vs) = xs ∷ (List.map f vs).
Lemma map_concat : forall f E F, map f (E & F) = (map f E) & (map f F).
Lemma dom_map : forall E f, dom (map f E) = dom E.
Lemma belongs_map : forall x E f, x ∈ E -> x ∈ (map f E).
Lemma belongs_map_inv : forall x E f, x ∈ (map f E) -> x ∈ E.
Lemma all_belongs_map : forall xs E f, xs ⊂ E -> xs ⊂ (map f E).
Lemma all_belongs_map_inv : forall xs E f, xs ⊂ (map f E) -> xs ⊂ E.
Lemma notin_map : forall x E f, x ∉ E -> x ∉ (map f E).
Lemma notin_map_inv : forall x E f, x ∉ (map f E) -> x ∉ E.
Lemma all_notin_map : forall xs E f, xs ⊄ E -> xs ⊄ (map f E).
Lemma all_notin_map_inv : forall xs E f, xs ⊄ (map f E) -> xs ⊄ E.
Lemma ok_map : forall E f, ok E -> ok (map f E).
Lemma ok_map_inv : forall E f, ok (map f E) -> ok E.
Lemma update_one_empty : forall x v, (@empty A) [x <- v] = (@empty A).
Lemma update_one_single : forall x y v w, x = y -> (x ∶ v) [y <- w] = (x ∶ w).
Lemma update_one_single_neq : forall x y v w, x <> y -> (x ∶ v) [y <- w] = (x ∶ v).
Lemma update_one_concat_r : forall x v E F, x ∈ F -> (E & F) [x <- v] = E & (F [x <- v]).
Lemma update_one_concat_l : forall x v E F, x ∉ F -> (E & F) [x <- v] = (E [x <- v]) & F.
Lemma dom_update_one : forall x v E, dom (E [x <- v]) = dom E.
Lemma belongs_update_one : forall x y v E, y ∈ E -> y ∈ (E [x <- v]).
Lemma belongs_update_one_inv : forall x y v E, y ∈ (E [x <- v]) -> y ∈ E.
Lemma all_belongs_update_one : forall x xs v E, xs ⊂ E -> xs ⊂ (E [x <- v]).
Lemma all_belongs_update_one_inv : forall x xs v E, xs ⊂ (E [x <- v]) -> xs ⊂ E.
Lemma notin_update_one : forall x y v E, y ∉ E -> y ∉ (E [x <- v]).
Lemma notin_update_one_inv : forall x y v E, y ∉ (E [x <- v]) -> y ∉ E.
Lemma all_notin_update_one : forall x xs v E, xs ⊄ E -> xs ⊄ (E [x <- v]).
Lemma all_notin_update_one_inv : forall x xs v E, xs ⊄ (E [x <- v]) -> xs ⊄ E.
Lemma update_one_notin : forall x v E, x ∉ E -> E [x <- v] = E.
Lemma map_update_one : forall f x v E, map f (E [x <- v]) = (map f E) [x <- f v].
Lemma ok_update_one : forall x v E, ok E -> ok (E [x <- v]).
Lemma ok_update_one_inv : forall x v E, ok (E [x <- v]) -> ok E.
Lemma update_empty_r : forall E, E ::= (@empty A) = E.
Lemma update_empty_l : forall E, (@empty A) ::= E = (@empty A).
Lemma update_update_one : forall x v E, E ::= (x ∶ v) = E [x <- v].
Lemma update_single_single : forall x y v w, x = y -> (x ∶ v) ::= (y ∶ w) = (x ∶ w).
Lemma update_single_single_neq : forall x y v w, x <> y -> (x ∶ v) ::= (y ∶ w) = (x ∶ v).
Lemma update_concat_r : forall E F G, E ::= (F & G) = (E ::= F) ::= G.
Lemma dom_update : forall E F, dom (E ::= F) = dom E.
Lemma belongs_update : forall x E F, x ∈ E -> x ∈ (E ::= F).
Lemma belongs_update_inv : forall x E F, x ∈ (E ::= F) -> x ∈ E.
Lemma all_belongs_update : forall xs E F, xs ⊂ E -> xs ⊂ (E ::= F).
Lemma all_belongs_update_inv : forall xs E F, xs ⊂ (E ::= F) -> xs ⊂ E.
Lemma notin_update : forall x E F, x ∉ E -> x ∉ (E ::= F).
Lemma notin_update_inv : forall x E F, x ∉ (E ::= F) -> x ∉ E.
Lemma all_notin_update : forall xs E F, xs ⊄ E -> xs ⊄ (E ::= F).
Lemma all_notin_update_inv : forall xs E F, xs ⊄ (E ::= F) -> xs ⊄ E.
Lemma update_notin : forall E F, (dom F) ⊄ E -> E ::= F = E.
Lemma map_update : forall f E F, map f (E ::= F) = (map f E) ::= (map f F).
Lemma ok_update : forall E F, ok E -> ok (E ::= F).
Lemma ok_update_inv : forall E F, ok (E ::= F) -> ok E.
Lemma remove_empty : forall x, (@empty A) ∖ {x} = (@empty A).
Lemma remove_single_eq : forall x y v, x = y -> (x ∶ v) ∖ {y} = (@empty A).
Lemma remove_single_neq : forall x y v, x <> y -> (x ∶ v) ∖ {y} = (x ∶ v).
Lemma remove_notin : forall x E, x ∉ E -> E ∖ {x} = E.
Lemma notin_remove_notin : forall x y E, x ∉ E -> x ∉ (E ∖ {y}).
Lemma all_notin_remove_notin : forall xs y E, xs ⊄ E -> xs ⊄ (E ∖ {y}).
Lemma belongs_remove : forall x y E, x <> y -> x ∈ E -> x ∈ (E ∖ {y}).
Lemma belongs_remove_inv : forall x y E, ok E -> x ∈ (E ∖ {y}) -> x <> y.
Lemma remove_belongs_concat_r : forall x E F, x ∈ F -> (E & F) ∖ {x} = E & (F ∖ {x}).
Lemma remove_belongs_concat_l : forall x E F, x ∉ F -> (E & F) ∖ {x} = (E ∖ {x}) & F.
Lemma remove_ok_notin : forall x E, ok E -> x ∉ (E ∖ {x}).
Lemma remove_all_belongs : forall x xs F, ¬ List.In x xs -> (x :: xs) ⊂ F -> xs ⊂ (F ∖ {x}).
Lemma remove_map : forall f E x, (map f E) ∖ {x} = map f (E ∖ {x}).
Lemma remove_update_one : forall x y v E, ok E -> (update_one E y v) ∖ {x} = update_one (E ∖ {x}) y v.
Lemma remove_update : forall x E F, ok E -> (E ::= F) ∖ {x} = (E ∖ {x}) ::= F.
Lemma remove_update_eq : forall x y v E, x = y -> (E ::= (y ∶ v)) ∖ {x} = E ∖ {x}.
Lemma ok_remove : forall x E, ok E -> ok (E ∖ {x}).
Lemma all_remove_remove : forall x xs E, E ∖ (x :: xs) = (E ∖ {x}) ∖ xs.
Lemma all_remove_empty : forall xs, (@empty A) ∖ xs = (@empty A).
Lemma all_remove_nil : forall E, E ∖ nil = E.
Lemma all_remove_single_in : forall x xs v, List.In x xs -> (x ∶ v) ∖ xs = (@empty A).
Lemma all_remove_single_not_in : forall x xs v, ¬ List.In x xs -> (x ∶ v) ∖ xs = (x ∶ v).
Lemma all_remove_singles_in : forall xs ys vs, xs = ys -> length xs = length vs -> (xs ∷ vs) ∖ ys = (@empty A).
Lemma all_remove_singles_not_in : forall xs ys vs, List.Forall (fun x => ¬ List.In x xs) ys -> (xs ∷ vs) ∖ ys = (xs ∷ vs).
Lemma all_remove_notin : forall xs E, xs ⊄ E -> E ∖ xs = E.
Lemma notin_all_remove_notin : forall x ys E, x ∉ E -> x ∉ (E ∖ ys).
Lemma all_notin_all_remove_notin : forall xs ys E, xs ⊄ E -> xs ⊄ (E ∖ ys).
Lemma all_remove_ok_notin : forall xs E, ok E -> xs ⊄ (E ∖ xs).
Lemma all_remove_belongs_concat_r : forall xs E F, List.NoDup xs -> xs ⊂ F -> (E & F) ∖ xs = E & (F ∖ xs).
Lemma all_remove_belongs_concat_l : forall xs E F, xs ⊄ F -> (E & F) ∖ xs = (E ∖ xs) & F.
Lemma all_remove_map : forall f E xs, (map f E) ∖ xs = map f (E ∖ xs).
Lemma all_remove_update : forall xs E F, ok E -> (E ::= F) ∖ xs = (E ∖ xs) ::= F.
Lemma ok_all_remove : forall xs E, ok E -> ok (E ∖ xs).
Lemma ok_empty : ok (@empty A).
Lemma ok_single : forall x v, ok (x ∶ v).
Lemma ok_singles : forall xs vs, List.NoDup xs -> ok (xs ∷ vs).
Lemma ok_singles_inv : forall xs vs, length xs = length vs -> ok (xs ∷ vs) -> List.NoDup xs.
Lemma ok_concat : forall E F, ok E -> ok F -> (dom E) ⊄ F -> (dom F) ⊄ E -> ok (E & F).
Lemma ok_concat_inv : forall E F, ok (E & F) -> ok E ∧ ok F ∧ (dom E) ⊄ F ∧ (dom F) ⊄ E.
Lemma ok_concat_comm : forall E F, ok (E & F) -> ok (F & E).
Lemma belongs_ok_concat_inv_l : forall x F G, ok (F & G) -> x ∈ F -> x ∉ G.
Lemma belongs_ok_concat_inv_r : forall x F G, ok (F & G) -> x ∈ G -> x ∉ F.
Lemma concat_not_ok : forall x F G, x ∈ F -> x ∈ G -> ¬ ok (F & G).
Lemma update_one_concat_ok : forall E F x v, ok (E & F) -> (E & F) [x <- v] = (E [x <- v]) & (F [x <- v]).
Lemma update_concat_l : forall E F G, ok (E & F) -> (E & F) ::= G = (E ::= G) & (F ::= G).