Library CatSem.ULC.ULC_semantics

Require Import Coq.Relations.Relations.

Require Export CatSem.CAT.cat_TYPE_option.
Require Export CatSem.CAT.orders_bis.
Require Export CatSem.ULC.ULC_syntax.

Set Implicit Arguments.
Unset Strict Implicit.
Unset Automatic Introduction.

Section Relations_on_ULC.

Reserved Notation "x :> y" (at level 70).

Variable rel : forall (V:TT), relation (ULC V).

Inductive ULCpropag (V: TT)
       : relation (ULC V) :=
| relorig : forall (v v': ULC V), rel v v' -> v :> v'
| relApp1: forall (M M' N : ULC V),
       M :> M' -> App M N :> App M' N
| relApp2: forall M (N N' : ULC V),
      N :> N' -> App M N :> App M N'
| relAbs: forall (M M':ULC V*),
      M :> M' -> Abs M :> Abs M'

where "y :> z" := (@ULCpropag _ y z).

Notation "y :>> z" :=
  (clos_refl_trans_1n _ (@ULCpropag _ ) y z) (at level 50).

Variable V : TT.

these are some trivial lemmata which will be used later

Lemma cp_App1 (M M' N : ULC V) :
    M :>> M' -> App M N :>> App M' N.
Proof.
  intros. generalize N.
  induction H. constructor.
  intros. constructor 2 with (App y N0); auto.
  constructor 2. auto.
Qed.

Lemma cp_App2 (M N N' : ULC V) :
    N :>> N' -> App M N :>> App M N'.
Proof.
  intros. generalize M.
  induction H. constructor.
  intros. constructor 2 with (App M0 y); auto.
  constructor 3. auto.
Qed.

Lemma cp_Abs (M M': ULC V*):
      M :>> M' -> Abs M :>> Abs M'.
Proof.
  intros. induction H. constructor.
  constructor 2 with (Abs y); auto.
  constructor 4. auto.
Qed.

End Relations_on_ULC.

Beta reduction

Inductive beta (V : TT): relation (ULC V) :=
| app_abs : forall (M: ULC V*) N,
               beta (App (Abs M) N) (M [*:= N]).

Definition beta_star := ULCpropag beta.

Definition beta_rel :=
   fun (V : TT) => clos_refl_trans_1n _ (@beta_star V).

Notation "a >>> b" := (beta_rel a b) (at level 70).

lemmata

Lemma beta_eq : forall V (M N : ULC V),
   M = N -> M >>> N.
Proof.
  intros.
  destruct H.
  reflexivity.
Qed.

Lemma beta_trans : forall V (M N K : ULC V),
 M >>> K -> N >>> M -> N >>> K.
Proof.
  intros.
  transitivity M;
  auto.
Qed.

Lemma beta_beta : forall V M (N : ULC V),
   App (Abs M) N >>> M [*:= N].
Proof.
  intros.
  apply clos_refl_trans_1n_contains.
  apply relorig.
  constructor.
Qed.

Lemma app_abs_red V (M : ULC _ ) (N M' : ULC V) :
   M [*:= N ] >>> M' -> App (Abs M) N >>> M'.
Proof.
  intros.
  apply (beta_trans H).
  apply beta_beta.
Qed.

Lemma App1_app_abs V (M : ULC V*)
       (N : ULC V) (L : ULC _ ) K:
  beta_rel (App (M [*:= N]) L) K ->
  beta_rel (App (App (Abs M) N) L) K.
Proof.
  intros.
  transitivity (App (M[*:=N]) L).
  apply cp_App1.
  apply clos_refl_trans_1n_contains.
  apply relorig.
  constructor.
  auto.
Qed.

Lemma App2_app_abs V (M : ULC V*)
      M' (N : ULC V) K:
  beta_rel (App M' (M [*:= N])) K ->
  beta_rel (App M' (App (Abs M) N)) K.
Proof.
  intros.
  transitivity (App M' (M[*:=N])).
  apply cp_App2.
  apply beta_beta.
  auto.
Qed.

Lemma App1_App1_app_abs V
     (M : ULC V*)
     (N : ULC _)
     (K : ULC V)
     (L : ULC V) (R : ULC V):
  beta_rel (App (App (M[*:=N]) K) L) R ->
  beta_rel (App (App (App (Abs M) N) K) L) R.
Proof.
  simpl; intros.
  transitivity (App (App (M [*:=N]) K) L).
  apply cp_App1.
  apply cp_App1.
  apply beta_beta.
  auto.
Qed.

Lemma App1_App1_App1_app_abs V
       (M : ULC V*)
       (N : ULC V)
       (K : ULC V)
       (L : ULC V)
       (J : ULC V) (R : ULC V):
  beta_rel (App (App (App (M[*:=N]) K) L) J) R ->
  beta_rel (App (App (App (App (Abs M) N) K) L) J) R.
Proof.
  simpl; intros.
  apply (beta_trans H).
  do 3 apply cp_App1.
  apply beta_beta.
Qed.

Lemma Abs_Abs_App1_App1_Abs_app_abs V
        (M : ULC V* * * * )
        (N : ULC _ )
        (K : ULC _ )
        (L : ULC _ ) (R : ULC V):
beta_rel (Abs (Abs
      (App (App (Abs (M[*:=N])) K) L))) R ->
beta_rel (Abs (Abs (App (App (Abs (App (Abs M) N)) K) L))) R.
Proof.
  intros.
  apply (beta_trans H).
  repeat apply cp_Abs.
  repeat apply cp_App1.
  apply cp_Abs.
  apply beta_beta.
Qed.

Lemma Abs_Abs_App1_App1_app_abs V
         (M : ULC V * * * )
         (N : ULC _)
         (K : ULC _)
         (L : ULC _) (R : ULC V):
beta_rel (Abs (Abs (App (App (M[*:=N]) K) L))) R ->
beta_rel (Abs (Abs (App (App (App (Abs M) N) K) L))) R.
Proof.
  intros.
  apply (beta_trans H).
  repeat apply cp_Abs.
  repeat apply cp_App1.
  apply beta_beta.
Qed.

Lemma Abs_Abs_App1_app_abs V
       (M : ULC V * * * )
       N (K : ULC _) (R : ULC V) :
beta_rel (Abs (Abs (App (M[*:=N]) K))) R ->
beta_rel (Abs (Abs (App (App (Abs M) N) K))) R.
Proof.
  intros.
  apply (beta_trans H).
  do 2 apply cp_Abs.
  apply cp_App1.
  apply beta_beta.
Qed.

Lemma Abs_Abs_app_abs V
       (M : ULC V * * * )
       N (R : ULC V) :
beta_rel (Abs (Abs (M[*:=N]))) R ->
beta_rel (Abs (Abs (App (Abs M) N))) R.
Proof.
  intros.
  apply (beta_trans H).
  do 2 apply cp_Abs.
  apply beta_beta.
Qed.

Lemma App2_App1_app_abs V
    (M : ULC V* ) N K
    (L : ULC V) (R:ULC V) :
  App K (App (M [*:=N]) L) >>> R ->
  App K (App (App (Abs M) N) L) >>> R.
Proof.
  intros.
  apply (beta_trans H).
  apply cp_App2.
  apply cp_App1.
  apply beta_beta.
Qed.

Lemma Abs_Abs_App1_Abs_App2_App1_app_abs V
     (M : ULC V * * * * )
     N (K : ULC _) (L : ULC _) (J : ULC _)
       (R:ULC V):
   Abs (Abs (App (Abs (App K
             (App (M[*:=N]) J))) L)) >>> R ->
   Abs (Abs (App (Abs (App K
     (App (App (Abs M) N) J))) L)) >>> R.
Proof.
  intros.
  apply (beta_trans H).
  do 2 apply cp_Abs.
  apply cp_App1.
  apply cp_Abs.
  apply cp_App2.
  apply cp_App1.
  apply beta_beta.
Qed.

Lemma Abs_Abs_App1_Abs_App2_app_abs V
   (M : ULC V * * * * )
   N (K : ULC _) (L : ULC _)
       (R:ULC V):
   Abs (Abs (App (Abs (App K
             (M[*:=N]) )) L)) >>> R ->
   Abs (Abs (App (Abs (App K
      (App (Abs M) N) )) L)) >>> R.
Proof.
  intros.
  apply (beta_trans H).
  do 2 apply cp_Abs.
  apply cp_App1.
  apply cp_Abs.
  apply cp_App2.
  apply beta_beta.
Qed.

Lemma Abs_Abs_App2_app_abs V
      (M : ULC V * * * )
      N K (R:ULC V ) :
  Abs (Abs (App K (M[*:=N]))) >>> R ->
  Abs (Abs (App K (App (Abs M) N))) >>> R.
Proof.
  intros.
  apply (beta_trans H).
  do 2 apply cp_Abs.
  apply cp_App2.
  apply beta_beta.
Qed.

Lemma App2_Abs_Abs_App2_App1_app_abs V
     (M : ULC V * * * )
     N K L (J : ULC _) (R:ULC V) :
   App K (Abs (Abs (App L (App (M[*:=N]) J)))) >>> R ->
   App K (Abs (Abs (App L (App (App (Abs M) N) J)))) >>> R.
Proof.
  intros.
  apply (beta_trans H).
  apply cp_App2.
  do 2 apply cp_Abs.
  apply cp_App2.
  apply cp_App1.
  apply beta_beta.
Qed.

Lemma Abs_Abs_App1_App1_App1_app_abs V
   (M : ULC V * * * )
   N (K : ULC _ ) (L : ULC _ ) (J : ULC _ ) (R:ULC V) :
  Abs (Abs (App (App (App (M [*:=N]) K) L) J)) >>> R ->
  Abs (Abs (App (App (App (App (Abs M) N) K) L) J)) >>> R .
Proof.
  intros.
  apply (beta_trans H).
  do 2 apply cp_Abs.
  do 3 apply cp_App1.
  apply beta_beta.
Qed.

Lemma Abs_Abs_App2_App1_App1_app_abs V
    (M : ULC V * * * )
    (N : ULC _) (K : ULC _)
    (L : ULC _) (J : ULC _) (R:ULC V):
   Abs (Abs (App K (App (App (M[*:=N]) L) J))) >>> R ->
   Abs (Abs (App K (App (App (App (Abs M) N) L) J))) >>> R.
Proof.
  intros.
  apply (beta_trans H).
  do 2 apply cp_Abs.
  apply cp_App2.
  do 2 apply cp_App1.
  apply beta_beta.
Qed.

Lemma Abs_Abs_App2_App1_app_abs V
    (M : ULC V * * * )
    N (K : ULC _) (L : ULC _) (R:ULC V):
  Abs (Abs (App K (App (M[*:=N]) L))) >>> R ->
  Abs (Abs (App K (App (App (Abs M) N) L))) >>> R.
Proof.
  intros.
  apply (beta_trans H).
  do 2 apply cp_Abs.
  apply cp_App2.
  apply cp_App1.
  apply beta_beta.
Qed.

Lemma Abs_App2_app_abs V
     (M : ULC V * * )
     N K (R : ULC V) :
   Abs (App K (M[*:=N])) >>> R ->
   Abs (App K (App (Abs M) N)) >>> R.
Proof.
  intros.
  apply (beta_trans H).
  apply cp_Abs.
  apply cp_App2.
  apply beta_beta.
Qed.

Lemma App1_Abs_app_abs V
   (M : ULC V * * )
   N (K : ULC _) (R:ULC V) :
  App (Abs (M[*:=N])) K >>> R ->
  App (Abs (App (Abs M) N)) K >>> R.
Proof.
  intros.
  apply (beta_trans H).
  apply cp_App1.
  apply cp_Abs.
  apply beta_beta.
Qed.

Lemma App1_Abs_App2_App1_app_abs V
   (M : ULC V * * )
   N (K : ULC _) (L : ULC _)
   (J : ULC _) (R:ULC V) :
  App (Abs (App K (App (M[*:=N]) L))) J >>> R ->
  App (Abs (App K (App (App (Abs M) N) L))) J >>> R.
Proof.
  intros.
  apply (beta_trans H).
  apply cp_App1.
  apply cp_Abs.
  apply cp_App2.
  apply cp_App1.
  apply beta_beta.
Qed.

Lemma App1_Abs_Abs_App2_App1_app_abs V
   (M : ULC V * * * )
    N (K : ULC _) (L:ULC _) (J : ULC _) (R:ULC V) :
  App (Abs (Abs (App K (App (M[*:=N]) L)))) J >>> R ->
  App (Abs (Abs (App K (App (App (Abs M) N) L)))) J >>> R.
Proof.
  intros.
  apply (beta_trans H).
  apply cp_App1.
  do 2 apply cp_Abs.
  apply cp_App2.
  apply cp_App1.
  apply beta_beta.
Qed.

Lemma App1_App1_Abs_app_abs V
   (M : ULC V * * )
    N (K : ULC _) (L : ULC _) (R:ULC V) :
  App (App (Abs (M[*:=N])) K) L >>> R ->
  App (App (Abs (App (Abs M)N)) K) L >>> R.
Proof.
  intros.
  apply (beta_trans H).
  do 2 apply cp_App1.
  apply cp_Abs.
  apply beta_beta.
Qed.

Lemma App1_App1_Abs_Abs_app_abs V
    (M : ULC V * * * )
     N (K : ULC _) (L : ULC _) (R:ULC V) :
  App (App (Abs (Abs (M[*:=N]))) K) L >>> R ->
  App (App (Abs (Abs (App (Abs M)N))) K) L >>> R.
Proof.
  intros.
  apply (beta_trans H).
  do 2 apply cp_App1.
  do 2 apply cp_Abs.
  apply beta_beta.
Qed.

Lemma App1_App1_Abs_Abs_App1_app_abs V M N K L J (R : ULC V):
    App (App (Abs (Abs (App (M[*:=N]) K))) L) J >>> R ->
    App (App (Abs (Abs (App (App (Abs M) N) K))) L) J >>> R.
Proof.
  intros.
  apply (beta_trans H).
  do 2 apply cp_App1.
  do 2 apply cp_Abs.
  apply cp_App1.
  apply beta_beta.
Qed.

Obligation Tactic := idtac.

Program Instance ULCBETA_struct (V : TT) :
  PO_obj_struct (ULC V) := {
 Rel := @beta_rel V
}.

Definition ULCBETA (V: TT) : Ord :=
    Build_PO_obj (ULCBETA_struct V ).

Program Instance Var_s (V : TT) :
    PO_mor_struct (a:=sm_po V) (b:=ULCBETA V) (Var (V:=V)).
Next Obligation.
Proof.
  intros V.
  unfold Proper;
  red.
  simpl.
  intros y z H.
  induction H.
  reflexivity.
Qed.

Definition VAR V := Build_PO_mor (Var_s V).

Lemma rename_beta (V W : TT)(f : V ---> W) (v w : ULC V):
     v >>> w -> v //- f >>> w //- f.
Proof.
  intros V W f v w H.
  generalize dependent W.
  induction H.
  reflexivity.
  intros W f.
  transitivity (y //- f);
  auto.
  clear dependent z.
  generalize dependent W.
  induction H.
  induction H.

  simpl.
  intros W f.
  apply app_abs_red.
  simpl.
  unfold substar.
  rewrite rename_subst.
  simpl.
  rewrite subst_rename.
  simpl.
  apply beta_eq.
  apply (subst_eq M).
  intros y;
  destruct y as [y| ];
  simpl;
  auto.

  intros W f.
  simpl.
  apply cp_App1.
  apply IHULCpropag.
  intros W f.
  simpl.
  apply cp_App2.
  apply IHULCpropag.
  simpl.
  intros W f.
  apply cp_Abs.
  apply IHULCpropag.
Qed.

Program Instance subst_s (V W : TT)
     (f : sm_po V ---> ULCBETA W) :
   PO_mor_struct
     (a:=ULCBETA V) (b:=ULCBETA W) (_subst f).
Next Obligation.
Proof.
  intros V W f.
  unfold Proper;
  red.
  intros y z H.
  generalize dependent W.
  induction H;
  simpl;
  intros.
  constructor.
  transitivity (_subst f y);
  try apply IHclos_refl_trans_1n.
  clear dependent z.

    generalize dependent W.
  induction H;
  simpl;
  intros.

  Focus 2.
  apply cp_App1.
  apply IHULCpropag.
  Focus 2.
  apply cp_App2.
  apply IHULCpropag.
  Focus 2.
  apply cp_Abs.
  simpl in *.
  apply (IHULCpropag _ (Sm_ind
            (V:=V*) (W:=ULCBETA W*)
      (fun y => _shift f y))).

  generalize dependent W.
    induction H;
    simpl;
    intros.
    apply clos_refl_trans_1n_contains.
    apply relorig.
    assert (H:=app_abs (_subst (_shift f) M) (_subst f N)).
    rewrite subst_substar.
    auto.
Qed.

Lemma subst_beta (V W : TT) (f : V ---> ULC W)
    (v w : ULC V) :
   v >>> w -> v >>= f >>> w >>= f.
Proof.
  intros.
  assert (H':= subst_s _ _ (Sm_ind (W:= ULCBETA W) f)).
  apply H'.
  simpl.
  auto.
Qed.

Definition SUBST V W f := Build_PO_mor (subst_s V W f).