Rec.Extras.lambda_model

From mathcomp Require Import ssreflect.all_ssreflect.
Require Import Base.axioms Base.fintype Framework.graded Extras.lambda_terms.
Set Implicit Arguments.
Unset Strict Implicit.

Local Ltac asimpl :=
  repeat progress (cbn; fsimpl; gsimpl; tm_simpl).

Section LambdaModel.
  Variable (D : Type).
  Variable (app : D -> D -> D).
  Variable (lam : (D -> D) -> D).

  Definition lambda_smodel : Tm.smodel D D := Tm.SModel id app lam.
  Notation "⟦ s ⟧ rho" := (Tm.seval lambda_smodel rho s) (at level 2, format "⟦ s ⟧ rho").

  Lemma ev_var n (rho : fin n -> D) (i : fin n) :
     Tm.var i rho = rho i.
  Proof. by []. Qed.

  Lemma ev_app n (rho : fin n -> D) (s t : tm n) :
     Tm.app s t rho = app ( s rho) ( t rho).
  Proof. by []. Qed.

  Lemma ev_lam n (rho : fin n -> D) (b : tm n.+1) :
     Tm.lam b rho = lam (fun v => b (v .: rho)).
  Proof. by []. Qed.

  Lemma ev_inst m n (rho : fin n -> D) (f : fin m -> tm n) (s : tm m) :
     s.[f]%tm rho = s (fun i => f i rho).
  Proof. by asimpl. Qed.

  Variable (beta : forall f x, app (lam f) x = f x).

  Inductive step {n} : tm n -> tm n -> Prop :=
  | step_beta (b : tm n.+1) (s : tm n) :
      step (Tm.app (Tm.lam b) s) b.[s .: Tm.var]%tm
  | step_appL (s1 s2 t : tm n) :
      step s1 s2 -> step (Tm.app s1 t) (Tm.app s2 t)
  | step_appR (s t1 t2 : tm n) :
      step t1 t2 -> step (Tm.app s t1) (Tm.app s t2)
  | step_lam (b1 b2 : tm n.+1) :
      @step n.+1 b1 b2 -> step (Tm.lam b1) (Tm.lam b2).

  Lemma step_invariant n (s t : tm n) :
    step s t -> forall rho, s rho = t rho.
  Proof.
    elim=> {n s t}[n b s|n s1 s2 t _ ih|n s t1 t2 _ ih|n b1 b2 _ ih] rho.
    - rewrite ev_app ev_lam beta ev_inst. f_equal. fext=>/=-[i|]//=.
    - by rewrite !ev_app ih.
    - by rewrite !ev_app ih.
    - rewrite !ev_lam. f_equal; fext=>/= d. exact: ih.
  Qed.
End LambdaModel.