Require Import List.
Require Import MyTactics.
Require Import Sequences.
Require Import LambdaCalculusSyntax.
Require Import LambdaCalculusFreeVars.
Require Import LambdaCalculusValues.
Require Import LambdaCalculusReduction.

(* -------------------------------------------------------------------------- *)
(* -------------------------------------------------------------------------- *)

(* A big-step call-by-value semantics. *)

Inductive bigcbv : term -> term -> Prop :=
| BigcbvValue:
    forall v,
    is_value v ->
    bigcbv v v
| BigcbvApp:
    forall t1 t2 u1 v2 v,
    bigcbv t1 (Lam u1) ->
    bigcbv t2 v2 ->
    bigcbv u1.[v2/] v ->
    bigcbv (App t1 t2) v
| BigcbvLet:
    forall t1 t2 v1 v,
    bigcbv t1 v1 ->
    bigcbv t2.[v1/] v ->
    bigcbv (Let t1 t2) v
.

Hint Constructors bigcbv : bigcbv.

(* The tactic [invert_bigcbv] looks for a hypothesis of the form [bigcbv t v]
   and inverts it. *)

Ltac invert_bigcbv :=
  pick bigcbv invert;
  try solve [ false; eauto 3 with obvious ].

(* -------------------------------------------------------------------------- *)

(* If [bigcbv t v] holds, then [v] must be a value. *)

Lemma bigcbv_is_value:
  forall t v,
  bigcbv t v ->
  is_value v.
Proof.
  induction 1; eauto.
Qed.

Hint Resolve bigcbv_is_value : is_value obvious.

(* -------------------------------------------------------------------------- *)

(* If [t] evaluates to [v] according to the big-step semantics,
   then [t] reduces to [v] according to the small-step semantics. *)

Lemma bigcbv_star_cbv:
  forall t v,
  bigcbv t v ->
  star cbv t v.
Proof.
  (* A detailed proof: *)
  induction 1.
  (* BigcbvValue *)
  { eapply star_refl. }
  (* BigcbvApp *)
  { eapply star_trans. obvious.
    eapply star_trans. obvious.
    eapply star_step. obvious.
    eauto. }
  (* BigcbvLet *)
  { eapply star_trans. obvious.
    eapply star_step. obvious.
    eauto. }
Restart.
  (* A much shorter proof: *)
  induction 1; eauto 6 with sequences obvious.
Qed.

(* Conversely, if [t] reduces to [v] in the small-step semantics,
   then [t] evaluates to [v] in the big-step semantics. *)

Lemma cbv_bigcbv_bigcbv:
  forall t1 t2,
  cbv t1 t2 ->
  forall v,
  bigcbv t2 v ->
  bigcbv t1 v.
Proof.
  (* A detailed proof: *)
  induction 1; intros; subst; try solve [ false; tauto ].
  (* BetaV *)
  { econstructor; eauto with bigcbv. }
  (* LetV *)
  { econstructor; eauto with bigcbv. }
  (* AppL *)
  { invert_bigcbv. eauto with bigcbv. }
  (* AppR *)
  { invert_bigcbv. eauto with bigcbv. }
  (* LetL *)
  { invert_bigcbv. eauto with bigcbv. }
Restart.
  (* A shorter proof: *)
  induction 1; intros; subst; try solve [ false; tauto
  | econstructor; eauto with bigcbv
  | invert_bigcbv; eauto with bigcbv
  ].
Qed.

Lemma star_cbv_bigcbv:
  forall t v,
  star cbv t v ->
  is_value v ->
  bigcbv t v.
Proof.
  induction 1; eauto using cbv_bigcbv_bigcbv with bigcbv.
Qed.

(* In conclusion, we have the following equivalence: *)

Lemma star_cbv_bigcbv_eq:
  forall t v,
  (star cbv t v /\ is_value v) <-> bigcbv t v.
Proof.
  split; intros; unpack;
  eauto using star_cbv_bigcbv, bigcbv_star_cbv with is_value.
Qed.

(* -------------------------------------------------------------------------- *)
(* -------------------------------------------------------------------------- *)

(* A big-step call-by-value semantics with explicit environments. *)

(* A closure is a pair of a term and an environment. A cvalue [cv] must be a
   closure, as we have no other forms of values. An environment [e] is a list
   of cvalues. *)

(* We break the mutual induction between [cvalue] and [cenv] by inlining the
   definition of [cenv] into the definition of [cvalue]. *)

Inductive cvalue :=
| Clo: {bind term} -> list cvalue -> cvalue.

Definition cenv :=
  list cvalue.

(* This dummy cvalue is passed below as an argument to [nth], but is really
   irrelevant, as the condition [x < length e] ensures that the dummy cvalue
   is never used. *)

Definition dummy_cvalue : cvalue :=
  Clo (Var 0) nil.

(* The judgement [ebigcbv e t cv] means that, under the environment [e], the
   term [t] evaluates to [cv]. *)

Inductive ebigcbv : cenv -> term -> cvalue -> Prop :=
| EBigcbvVar:
    forall e x cv,
    (* The variable [x] must be in the domain of [e]. *)
    x < length e ->
    (* This allows us to safely look up [e] at [x]. *)
    cv = nth x e dummy_cvalue ->
    ebigcbv e (Var x) cv
| EBigcbvLam:
    forall e t,
    (* The free variables of [t] must be less than or equal to [length e]. *)
    (forall cv, fv (length (cv :: e)) t) ->
    (* This allows us to build a closure that is indeed closed. *)
    ebigcbv e (Lam t) (Clo t e)
| EBigcbvApp:
    forall e e' t1 t2 u1 cv2 cv,
    (* Evaluate [t1] to a closure, *)
    ebigcbv e t1 (Clo u1 e') ->
    (* evaluate [t2] to a value, *)
    ebigcbv e t2 cv2 ->
    (* and evaluate the function body, in a suitable environment. *)
    ebigcbv (cv2 :: e') u1 cv ->
    ebigcbv e (App t1 t2) cv
| EBigcbvLet:
    forall e t1 t2 cv1 cv,
    (* Evaluate [t1] to a value, *)
    ebigcbv e t1 cv1 ->
    (* and evaluate [t2] under a suitable environment. *)
    ebigcbv (cv1 :: e) t2 cv ->
    ebigcbv e (Let t1 t2) cv
.

Hint Constructors ebigcbv : ebigcbv.

(* -------------------------------------------------------------------------- *)

(* To explain what the above semantics means, and to prove that it is
   equivalent to the big-step semantics, we first define a function that
   decodes a cvalue into a value. *)

(* Ideally, the function [decode] should be defined by the equation:

     decode (Clo t e) = (Lam t).[decode_cenv e]

   where the auxiliary function [decode_cenv] maps [decode] over the
   environment [e], and converts the result to a substitution, that
   is, a function of type [term -> term]:

     decode_cenv e = fun x => nth x (map decode e) (decode dummy_cvalue)

   The definitions below are a bit more awkward (as Coq does not support
   mutual induction very well), but mean the same thing. *)

Definition dummy_value : term :=
  Lam (Var 0).

Fixpoint decode (cv : cvalue) : term :=
  match cv with
  | Clo t e =>
      (Lam t).[fun x => nth x (map decode e) dummy_value]
  end.
  (* I am not even sure why this definition is accepted by Coq? *)

Definition decode_cenv e :=
  fun x => nth x (map decode e) (decode dummy_cvalue).

(* The first equation in the above comment is satisfied, as shown by
   the following lemma. The second equation in the above comment is
   satisfied too, by definition. *)

Lemma decode_eq:
  forall t e,
  decode (Clo t e) = (Lam t).[decode_cenv e].
Proof.
  reflexivity.
Qed.

(* This equation is useful, too. *)

Lemma decode_cenv_Var_eq:
  forall x e,
  (Var x).[decode_cenv e] = decode (nth x e dummy_cvalue).
Proof.
  intros. asimpl. unfold decode_cenv. rewrite map_nth. eauto.
Qed.

(* The tactic [decode] rewrites using the above two equations. *)

Hint Rewrite decode_eq decode_cenv_Var_eq : decode.
Ltac decode := autorewrite with decode in *.

(* We make [decode] opaque, so its definition is not unfolded by Coq. *)

Opaque decode.

(* [decode cv] is always a value. *)

Lemma is_value_decode:
  forall cv,
  is_value (decode cv).
Proof.
  intros. destruct cv. decode. asimpl. tauto.
Qed.

Lemma is_value_decode_cenv:
  forall x e,
  is_value (Var x).[decode_cenv e].
Proof.
  intros. decode. eauto using is_value_decode.
Qed.

Local Hint Resolve is_value_decode is_value_decode_cenv : is_value obvious.

(* A composition of two substitutions is the same thing as one substitution. *)

Lemma decode_cenv_cons:
  forall t e cv,
  t.[up (decode_cenv e)].[decode cv/] = t.[decode_cenv (cv :: e)].
Proof.
  intros. autosubst. (* wonderful *)
Qed.

(* The tactic [nonvalue_eq_decode] closes a subgoal when there is a hypothesis
   of the form [_ = decode_cenv e x], where the left-hand side of the equation
   clearly is not a value. This is a contradiction. *)

Ltac nonvalue_eq_decode :=
  match goal with
  | heq: _ = decode_cenv ?e ?x |- _ =>
      assert (hv: is_value (decode_cenv e x)); [
        solve [ obvious ]
      | rewrite <- heq in hv; false; is_value ]
  end.

(* -------------------------------------------------------------------------- *)

(* If [t] evaluates to [cv] under environment [e],
   then, in the big-step semantics,
   the term [t.[decode_cenv e]] evaluates to the value [decode cv]. *)

Lemma ebigcbv_bigcbv:
  forall e t cv,
  ebigcbv e t cv ->
  bigcbv t.[decode_cenv e] (decode cv).
Proof.
  induction 1; intros; subst.
  (* EBigcbvVar *)
  { decode. econstructor. obvious. }
  (* EBigcbvLam *)
  { econstructor. obvious. }
  (* EBigcbvApp *)
  { decode.
    asimpl. econstructor; eauto.
    asimpl. eauto. }
  (* EBigcbvLet *)
  { asimpl. econstructor; eauto.
    asimpl. eauto. }
Qed.

(* A simplified corollary, where [t] is closed and is therefore evaluated
   under the empty environment. *)

Lemma ebigcbv_bigcbv_nil:
  forall t cv,
  ebigcbv nil t cv ->
  closed t ->
  bigcbv t (decode cv).
Proof.
  intros.
  replace t with t.[decode_cenv nil] by eauto using closed_unaffected.
  eauto using ebigcbv_bigcbv.
Qed.

(* -------------------------------------------------------------------------- *)

(* The converse statement: if in the big-step semantics, the term
   [t.[decode_cenv e]] evaluates to the value [decode cv], then [t] evaluates
   to [cv] under environment [e]. *)

(* This proof does not work (and, in fact, the statement is wrong). A failed
   proof attempt reveals two problems... *)

Lemma bigcbv_ebigcbv_failed:
  forall e t cv,
  bigcbv t.[decode_cenv e] (decode cv) ->
  ebigcbv e t cv.
Proof.
  inversion 1; intros; subst.
  (* BigcbvValue *)
  { (* [t] must be a variable or a lambda-abstraction. *)
    destruct t; [ | | false; is_value | false; is_value ].
    (* Case: [t] is a variable. *)
    { econstructor.
      (* Here, we have two subgoals, neither of which can be proved. *)
      { (* Problem 1: we are unable to prove [x < length e]. In order
           to establish such a property, we would have to express the
           hypothesis that the free variables of [t] are in the domain
           of the environment [e]. And, for this hypothesis to be
           inductive, we have to further require every closure in
           the environment [e] to satisfy a similar condition. *)
        admit. }
      { (* Problem 2: we have [decode cv1 = decode cv2], and the goal
           is [cv1 = cv2]. This goal cannot be proved, as the function
           [decode] is not injective: multiple closures represent the
           same lambda-abstraction. *)
        decode.
        admit. }
Abort.

(* -------------------------------------------------------------------------- *)

(* In order to fix the above failed statement, we need to express the
   following well-formedness invariant: whenever a closure [Clo t e] is
   constructed, the free variables of the term [t] are in the domain of the
   environment [env], and, recursively, every value in [e] is well-formed. *)

Inductive wf_cvalue : cvalue -> Prop :=
| WfCvalue:
    forall t e,
    (forall cv, fv (length (cv :: e)) t) ->
    wf_cenv e ->
    wf_cvalue (Clo t e)

with wf_cenv : cenv -> Prop :=
| WfCenv:
    forall e,
    Forall wf_cvalue e ->
    wf_cenv e.

(* The following trivial lemmas (which repeat the definition) are provided as
   hints for [eauto with wf_cvalue]. *)

Lemma use_wf_cvalue_1:
  forall t e cv,
  wf_cvalue (Clo t e) ->
  fv (length (cv :: e)) t.
Proof.
  inversion 1; eauto.
Qed.

Lemma use_wf_cvalue_2:
  forall t e,
  wf_cvalue (Clo t e) ->
  wf_cenv e.
Proof.
  inversion 1; eauto.
Qed.

Lemma prove_wf_cenv_nil:
  wf_cenv nil.
Proof.
  econstructor. eauto.
Qed.

Lemma prove_wf_cenv_cons:
  forall cv e,
  wf_cvalue cv ->
  wf_cenv e ->
  wf_cenv (cv :: e).
Proof.
  inversion 2; intros; subst.
  econstructor.
  econstructor; eauto.
Qed.

Hint Resolve
  use_wf_cvalue_1 use_wf_cvalue_2 prove_wf_cenv_nil prove_wf_cenv_cons
: wf_cvalue.

(* The following lemma states that the invariant is preserved by [ebigcbv].
   That is, if the term [t] is successfully evaluated in the well-formed
   environment [e] to a cvalue [cv], then [cv] is well-formed. *)

Lemma ebigcbv_wf_cvalue:
  forall e t cv,
  ebigcbv e t cv ->
  wf_cenv e ->
  wf_cvalue cv.
Proof.
  induction 1; intros; subst.
  (* EBigcbvVar *)
  { pick wf_cenv invert. rewrite Forall_forall in *. eauto using nth_In. }
  (* EBigcbvLam *)
  { econstructor; eauto. }
  (* EBigcbvApp *)
  { eauto 6 with wf_cvalue. }
  (* EBigcbvLet *)
  { eauto 6 with wf_cvalue. }
Qed.

Hint Resolve ebigcbv_wf_cvalue : wf_cvalue.

(* -------------------------------------------------------------------------- *)

(* We can now make an amended statement: if in the big-step semantics, the
   term [t.[decode_cenv e]] evaluates to a value [v], if the environment [e]
   is well-formed, and if the free variables of [t] are in the domain of [e],
   then under environment [e] the term [t] evaluates to some cvalue [cv] such
   that [decode cv] is [v]. *)

Lemma bigcbv_ebigcbv:
  forall te v,
  bigcbv te v ->
  forall t e,
  te = t.[decode_cenv e] ->
  fv (length e) t ->
  wf_cenv e ->
  exists cv,
  ebigcbv e t cv /\ decode cv = v.
Proof.
  induction 1; intros; subst.
  (* BigcbvValue *)
  { (* [t] must be a variable or a lambda-abstraction. *)
    destruct t; [ | | false; is_value | false; is_value ]; fv.
    (* Case: [t] is a variable. *)
    { eexists; split. econstructor; eauto. decode. eauto. }
    (* Case: [t] is a lambda-abstraction. *)
    { eexists; split. econstructor; eauto. reflexivity. }
  }
  (* BigcbvApp *)
  { (* [t] must be an application. *)
    destruct t;
    match goal with h: _ = _ |- _ => asimpl in h end;
    [ nonvalue_eq_decode | false; congruence | | false; congruence ].
    fv. unpack.
    (* The equality [App _ _ = App _ _] can be simplified. *)
    injections. subst.
    (* Exploit two of the induction hypotheses (forward). *)
    edestruct IHbigcbv1; eauto. unpack. clear IHbigcbv1.
    edestruct IHbigcbv2; eauto. unpack. clear IHbigcbv2.
    (* If [decode cv] is [Lam _], then [cv] must be a closure. This should
       be a lemma. Because (here) every cvalue is a closure, it is trivial. *)
    match goal with h: decode ?cv = Lam _ |- _ =>
      destruct cv as [ t' e' ];
      rewrite decode_eq in h;
      asimpl in h;
      injections; subst
    end.
    (* Now, exploit the third induction hypothesis (forward). *)
    edestruct IHbigcbv3; eauto using decode_cenv_cons with wf_cvalue.
    unpack. clear IHbigcbv3.
    (* The result follows. *)
    eauto with ebigcbv.
  }
  (* BigcbvLet *)
  { (* [t] must be a [Let] construct. *)
    destruct t;
    match goal with h: _ = _ |- _ => asimpl in h end;
    [ nonvalue_eq_decode | false; congruence | false; congruence | ].
    fv. unpack.
    injections. subst.
    (* Exploit the induction hypotheses (forward). *)
    edestruct IHbigcbv1; eauto. unpack. clear IHbigcbv1.
    edestruct IHbigcbv2; eauto using decode_cenv_cons with wf_cvalue.
    unpack. clear IHbigcbv2.
    (* The result follows. *)
    eauto with ebigcbv.
  }
Qed.

(* A simplified corollary, where [t] is closed and is therefore evaluated
   under the empty environment. *)

Lemma bigcbv_ebigcbv_nil:
  forall t v,
  bigcbv t v ->
  closed t ->
  exists cv,
  ebigcbv nil t cv /\ decode cv = v.
Proof.
  intros. eapply bigcbv_ebigcbv; eauto with wf_cvalue.
  rewrite closed_unaffected by eauto. reflexivity.
Qed.
