Definition subst := A -> (A -> val) -> val.Definition stack_subst (s: stack A val) (sub: subst) : stack A val :=
    fun x => sub x s.Definition apply_subst {B}
          (e : (A -> val) -> B) (sub : subst) : (A -> val) -> B :=
    fun s => e (stack_subst s sub).Definition substlist := list (A * @expr A val).(* The identity substitution *)
  Definition subst0 : subst := fun x => stack_get x.(* Substitution of one variable *)
  Definition subst1 e x : subst :=
    fun x' => if x' ?[ eq ] x then e else stack_get x'.(* Truncating substitution of one variable *)
  Definition subst1_trunc e x : subst :=
    fun x' => if x' ?[ eq ] x then e else empty_open.(* Simultaneous substitution of a finite list of variables *)
  Fixpoint substl_aux (subs: substlist) : subst :=
    match subs with
      | nil => subst0
      | cons (x,e) subs' => fun x' => 
        if x' ?[ eq ] x then e else substl_aux subs' x'
    end.(* Truncating simultaneous substitution of a finite list of variables *)
  Fixpoint substl_trunc_aux (subs: substlist) : subst :=
    match subs with
      | nil => fun _ => empty_open
      | cons (x,e) subs' => fun x' => 
        if x' ?[ eq ] x then e else substl_trunc_aux subs' x'
    end.Definition substl es v := substl_aux es v.Definition substl_trunc es v := substl_trunc_aux es v.(* Binds tighter than function application *)
(* We have the e at precedence level one less than the precedence of the infix
   // operator to make parsing work. *)

Notation "g [{ e // x }]" := (apply_subst g (subst1 e x)) (at level 9, e at level 39,
  format "g [{ e // x }]") : open_scope.Notation "g [{ e //! x }]" := (apply_subst g (subst1_trunc e x)) (at level 9, e at level 39,
  format "g [{ e //! x }]") : open_scope.Notation " g '//' es " := (apply_subst g (substl es)) (at level 40) : open_scope.Notation " g '//!' es " := (apply_subst g (substl_trunc es)) (at level 40) : open_scope.

(* Specifications: *)
Lemma open_subst_stack {B} (m: @open A val B) (sub : subst) (s : @stack A val) : (apply_subst m sub) s = m (stack_subst s sub).
Lemma subst0_id B (g: @open A val B) : (apply_subst g (@subst0 A val)) = g.
Lemma subst1_stack (s: @stack A val) e x : stack_subst s (subst1 e x) = stack_add x (e s) s.
Lemma substl_subst1 x e : substl (val := val) (cons (x,e) nil) = subst1 e x.
Lemma substl_subst1_trunc x e : substl_trunc (cons (x,e) nil) = subst1_trunc e x.
Lemma stack_add_var (x : A) (s : @stack A val) (v : val) : (stack_get x) (stack_add x v s) = v.
Lemma substl_trunc_notin x' xs es : ~ In x' xs -> substl_trunc (combine xs es) x' = @empty_open _ val _.
Lemma subst_open_expr_nil {B} : forall (e : @open A val B), (e // nil) = e.
Lemma subst_var_cons_eq : forall (x:A) es (e : expr (val := val)), (stack_get x // (cons (x, e) es)) = e.
Lemma subst_var_cons_ineq : forall (x:A) y es (e : expr (val := val)) (Hneq: x <> y), (stack_get x // (cons (y, e) es)) = (stack_get x // es).
Lemma val_expr_substs : forall (v : val) es, ((V_expr v) // es) = (V_expr v).