(* --- an environment-based interpreter for named terms ------- *)

(*
   The result of this interpreter is a "closure" --- a lambda expression
   paired with a substitution for all of the free variables in the term.
   We call such substitutions "environments".

*)


Inductive nom_env : Set :=
  | nom_nil  : nom_env
  | nom_cons : atom -> n_exp -> nom_env -> nom_env -> nom_env.(* --- an environment-based interpreter for named terms ------- *)

(*
   The result of this interpreter is a "closure" --- a lambda expression
   paired with a substitution for all of the free variables in the term.
   We call such substitutions "environments".

*)


Inductive nom_env : Set :=
  | nom_nil  : nom_env
  | nom_cons : atom -> n_exp -> nom_env -> nom_env -> nom_env.(* --- an environment-based interpreter for named terms ------- *)

(*
   The result of this interpreter is a "closure" --- a lambda expression
   paired with a substitution for all of the free variables in the term.
   We call such substitutions "environments".

*)


Inductive nom_env : Set :=
  | nom_nil  : nom_env
  | nom_cons : atom -> n_exp -> nom_env -> nom_env -> nom_env.Inductive nom_val : Set :=
  | nom_closure : atom -> nom_env -> n_exp -> nom_val.Inductive nom_val : Set :=
  | nom_closure : atom -> nom_env -> n_exp -> nom_val.Inductive res (a : Set) : Set :=
  | val     : a -> res a
  | timeout : res a
  | stuck   : res a.Inductive res (a : Set) : Set :=
  | val     : a -> res a
  | timeout : res a
  | stuck   : res a.Inductive res (a : Set) : Set :=
  | val     : a -> res a
  | timeout : res a
  | stuck   : res a.Inductive res (a : Set) : Set :=
  | val     : a -> res a
  | timeout : res a
  | stuck   : res a.Fixpoint nom_interp (n:nat) (e:n_exp) (rho: nom_env) : res nom_val :=
  match n with
  | 0 => timeout _
  | S m =>
    match e with
    | n_var x =>  match (rho_lookup x rho) with
                | Some (e',r') => nom_interp m e' r'
                | None   => stuck _
                end
    | n_app e1 e2 =>
      match nom_interp m e1 rho with
      | val _ (nom_closure x rho' e1') =>
              nom_interp m e1' (nom_cons x e2 rho rho')
      | r       => r
      end
    | n_abs x e   => val _ (nom_closure x rho e)
    end
  end.(* --- translation from nominal terms and values to LN terms --- *)
(*
    Our goal is to prove the correctness of this interpreter. In otherwords,
    we want to show that if it produces a value, then we can translate to an
    evaluation of LN terms.

    The property that we ultimately want to prove looks something like this:

<<
   Lemma nom_soundness0 : forall n e v,
      val _ v = nom_interp n e nom_nil  ->
      bigstep (nom_to_exp e) (nom_val_to_exp v).
>>

    where we straightforwardly translate nominal terms to LN terms.
    (Note that we cannot write the function in the other direction --- there
    are many equally valid names that we can choose for the bound variable.)
*)

Fixpoint nom_to_exp (ne : n_exp) : exp :=
  match ne with
  | n_var x => var_f x
  | n_app e1 e2 => app (nom_to_exp e1) (nom_to_exp e2)
  | n_abs x e1 => abs (close_exp_wrt_exp x (nom_to_exp e1))
end.Fixpoint nom_val_to_exp (cv:nom_val) : exp :=
  match cv with
  | nom_closure x rho e =>
    nom_envsubst rho (nom_to_exp (n_abs x e))
  end.

(* Specifications: *)
Lemma nom_envsubst_open : forall rho e e', (forall v, lc_exp (nom_val_to_exp v)) -> (nom_envsubst rho (open e e')) = (open (nom_envsubst rho e) (nom_envsubst rho e')).
Lemma nom_envsubst_var : forall x rho e rho', closed_env rho -> Some (e,rho') = rho_lookup x rho -> nom_envsubst rho (var_f x) = nom_envsubst rho' (nom_to_exp e).
Lemma nom_envsubst_abs : forall rho e, nom_envsubst rho (abs e) = abs (nom_envsubst rho e).
Lemma nom_envsubst_app : forall rho e1 e2, nom_envsubst rho (app e1 e2) = app (nom_envsubst rho e1) (nom_envsubst rho e2).
Lemma nom_val_to_exp_is_value : forall v, is_value (nom_val_to_exp v).
Lemma nom_to_exp_lc : forall ne, lc_exp (nom_to_exp ne).