(***********************************************************************)
(** * Scoped configurations                                            *)
(***********************************************************************)
(** Not all abstract machine steps simulate small-steps of the substitution-based STLC.  For example, if the domain of the heap is not unique (i.e. it has multiple definitions for the same variable) then its evaluation may not produce expected results.  Similarly, if the [avoid] set that we pass to each machine step does not include initial the free variables of the term, then we could capture them in strange ways.  Therefore, we will restrict our correctness lemmas so that they only apply to _well-scoped_ configurations; as defined below. *)
(***********************************************************************)
(** ** Scoped heaps                                                    *)
(***********************************************************************)
(** Well-scoped heaps behave "telescopically".  Each binding (x,e) added to the heap is for a unique name x and the free variables of e are bound in the remainder of the heap.  The scoping relation is parameterized by [D], an "ambient scope". This will let us reason about the execution of the abstract machine for terms with free variables. *)
(** *** Recommended (Challenge) Exercise [apply_heap_get]  We can use [get] to look up expressions in the heap. However, to know that we have the right result we need to know that the heap is well-scoped, i.e.  that later bindings do not affect earlier ones.  State a lemma about the scoping of expressions that appear in the heap and use it to finish the [apply_heap_get] lemma below.  *)

(* Specifications: *)
(* SOLUTION *)
Lemma scoped_get : forall h D1 D2 x e,
scoped_heap D1 h ->
get x h = Some e ->
dom h \u D1 [<=] D2 ->
fv_exp (nom_to_exp e) [<=] D2.