Library Icharate.Kernel.lambda_bruijn


Require Export listAux.
Require Export Arith.
Require Export basics.
Set Implicit Arguments.

Section allSem.
Variables I J A:Set.

Inductive semType :Set :=
| e :semType
| t : semType
| funAppli :semType -> semType -> semType
| cartProd:semType -> semType -> semType
|intention :semType->semType.
Definition eqDecSem:forall (t1 t2:semType), {t1=t2}+{t1 <>t2}.
decide equality.
Defined.
Variable map:A->semType.

Fixpoint mapExt (f:Form I J A){struct f}:semType :=
match f with
| At p => map p
| Slash _ f1 f2 => funAppli (mapExt f2) (mapExt f1)
| Backslash _ f1 f2 =>funAppli (mapExt f1) (mapExt f2)
| Dot _ f1 f2 => cartProd (mapExt f1) (mapExt f2)
| Box _ f1 => (intention (mapExt f1))
| Diamond _ f1 => (intention (mapExt f1))
end.

Section lambdaX.
Variable X:Set.
Variable getSemTypeX : X->semType.

Inductive lambda_terms:Set:=
| num : nat -> lambda_terms
| ress : X ->lambda_terms
| hyps: nat->semType->lambda_terms
| appl :lambda_terms -> lambda_terms -> lambda_terms
| abs : semType ->lambda_terms -> lambda_terms
| twoL : lambda_terms -> lambda_terms -> lambda_terms
| pi1 :lambda_terms -> lambda_terms
| pi2 : lambda_terms -> lambda_terms
| box : lambda_terms -> lambda_terms
| debox : lambda_terms -> lambda_terms
| diam : lambda_terms -> lambda_terms
| dediam :lambda_terms -> lambda_terms.

Fixpoint isWellFormedN (n:nat) (l:lambda_terms){struct l} :Prop:=
match l with
| num k =>match (le_lt_dec n k) with
                            | right _ => True
                            | left _ => False
             end
| ress r => True
|hyps _ _ => True
| appl l1 l2 => isWellFormedN n l1 /\ isWellFormedN n l2
| abs _ l1 => isWellFormedN (S n) l1
| twoL l1 l2 => isWellFormedN n l1 /\ isWellFormedN n l2
| pi1 l1 => isWellFormedN n l1
| pi2 l1 => isWellFormedN n l1
| box l1 => isWellFormedN n l1
| debox l1 => isWellFormedN n l1
| diam l1 => isWellFormedN n l1
| dediam l1 => isWellFormedN n l1
end.

Definition isWellFormed(l:lambda_terms):=(isWellFormedN O l).

Fixpoint no_hyps_inside (l:lambda_terms):Prop:=
match l with
|hyps _ _=> False
| num k =>True
| ress r => True
| appl l1 l2 => no_hyps_inside l1 /\ no_hyps_inside l2
| abs _ l1 => no_hyps_inside l1
| twoL l1 l2 => no_hyps_inside l1 /\ no_hyps_inside l2
| pi1 l1 => no_hyps_inside l1
| pi2 l1 => no_hyps_inside l1
| box l1 => no_hyps_inside l1
| debox l1 => no_hyps_inside l1
| diam l1 => no_hyps_inside l1
| dediam l1 => no_hyps_inside l1
end.

Fixpoint lambdaBind (lTerm:lambda_terms)(i n:nat)(st:semType){struct lTerm}:lambda_terms :=
match lTerm with
| num l => if (le_lt_dec i l) then (num (S l)) else (num l)
| ress r =>ress r
| hyps k s=> if (eq_nat_dec k n)
           then (if (eqDecSem s st) then (num i) else (hyps k s))
           else (hyps k s)
| appl t1 t2 => appl (lambdaBind t1 i n st) (lambdaBind t2 i n st)
| abs ty t1 => abs ty (lambdaBind t1 (S i) n st)
| twoL t1 t2 => twoL (lambdaBind t1 i n st) (lambdaBind t2 i n st)
| pi1 t1=>pi1 (lambdaBind t1 i n st)
| pi2 t1 => pi2 (lambdaBind t1 i n st)
| box t1 =>box (lambdaBind t1 i n st)
| debox t1 => debox (lambdaBind t1 i n st)
| diam t1 => diam (lambdaBind t1 i n st)
| dediam t1 => dediam (lambdaBind t1 i n st)
end.

Definition lambdaAbs(lTerm:lambda_terms)(n :nat)(st:semType):lambda_terms
 :=(abs st (lambdaBind lTerm O n st)).

Fixpoint up_lambda (l:lambda_terms)(n:nat)(i:nat){struct l}:lambda_terms:=
match l with
|num m=>match (le_lt_dec i m) with
            |left _ =>num (m+n)
            |right _=>num m
             end
|ress r => ress r
|hyps k s=>hyps k s
|appl l1 l2=> appl (up_lambda l1 n i) (up_lambda l2 n i)
|abs ty l1 => abs ty (up_lambda l1 n (S i))
| twoL l1 l2 =>twoL (up_lambda l1 n i) (up_lambda l2 n i)
| pi1 l1 => pi1 (up_lambda l1 n i)
|pi2 l1 => pi2 (up_lambda l1 n i)
| box l1 => box (up_lambda l1 n i)
|debox l1 =>debox (up_lambda l1 n i)
|diam l1=>diam (up_lambda l1 n i)
|dediam l1 =>dediam (up_lambda l1 n i)
end.

Definition lift_lambda(l:lambda_terms)(n:nat):lambda_terms:=
(up_lambda l n 0).

Lemma lift_wf:forall (l:lambda_terms)(k n:nat),
                 isWellFormedN n l->
                 up_lambda l k n=l.
 Proof.
 intros l k; elim l; simpl in |- *; intros; auto.
 generalize H; case (le_lt_dec n0 n).
 induction 2.
 auto.
 decompose [and] H1.
 rewrite (H _ H2); rewrite (H0 _ H3).
 auto.
 rewrite (H _ H0).
 auto.
 decompose [and] H1.
 rewrite (H _ H2); rewrite (H0 _ H3); auto.
 rewrite H; auto.
 rewrite H; auto.
 rewrite H; auto.
 rewrite H; auto.
 rewrite H; auto.
 rewrite H; auto.
Qed.

Fixpoint lambdaSubN (lTerm1 lTerm2:lambda_terms)(i n:nat)(st:semType){struct lTerm1}:lambda_terms:=
match lTerm1 with
| num l=> (num l)
| ress r => ress r
| hyps k s=>if (eq_nat_dec k n)
           then (if (eqDecSem s st) then (lift_lambda lTerm2 i) else
           (hyps k s))
           else (hyps k s)
| appl t1 t2 => appl (lambdaSubN t1 lTerm2 i n st) (lambdaSubN t2
lTerm2 i n st)
| abs ty t1 => abs ty (lambdaSubN t1 lTerm2 (S i) n st)
| twoL t1 t2 => twoL (lambdaSubN t1 lTerm2 i n st) (lambdaSubN t2
lTerm2 i n st)
| pi1 t1 =>pi1 (lambdaSubN t1 lTerm2 i n st)
| pi2 t1 =>pi2 (lambdaSubN t1 lTerm2 i n st)
| box t1 =>box (lambdaSubN t1 lTerm2 i n st)
| debox t1 =>debox (lambdaSubN t1 lTerm2 i n st)
| diam t1 =>diam (lambdaSubN t1 lTerm2 i n st)
|dediam t1 =>dediam (lambdaSubN t1 lTerm2 i n st)
end.

Definition lambSub (lTerm1 lTerm2:lambda_terms)(n:nat)(st:semType):lambda_terms:=
                         lambdaSubN lTerm1 lTerm2 0 n st.

Inductive isWellTyped :(list semType)->lambda_terms->semType ->Set:=
| typeNum: forall (env:list semType) (n:nat)(ty:semType),
                    nth_error env n=Some ty ->
                    isWellTyped env (num n) ty
| typeVar :forall (x:X)(env:list semType) ,
                  isWellTyped env (ress x) (getSemTypeX x)
|typeHyps:forall (n:nat)(ty:semType)env, isWellTyped env (hyps n ty) ty
| typeAppl : forall (l1 l2: lambda_terms)(t1 t2:semType)(env:(list semType)),
                  isWellTyped env l1 (funAppli t1 t2) ->
                  isWellTyped env l2 t1 ->
                  isWellTyped env (appl l1 l2) t2
| typeAbs : forall (l1:lambda_terms)( t1 t2:semType)(env:list semType),
                  isWellTyped (t2::env) l1 t1->
                  isWellTyped env (abs t2 l1) (funAppli t2 t1)
| typeTwoL: forall (l1 l2: lambda_terms)(t1 t2:semType)(env:(list semType)),
                  isWellTyped env l1 t1 ->
                  isWellTyped env l2 t2 ->
                  isWellTyped env (twoL l1 l2) (cartProd t1 t2)
| typePi1:forall (l1:lambda_terms)(t1 t2 :semType)(env:list semType),
                 isWellTyped env l1 (cartProd t1 t2)->
                 isWellTyped env (pi1 l1) t1
| typePi2 :forall (l1:lambda_terms)(t1 t2 :semType)(env:list semType),
                 isWellTyped env l1 (cartProd t1 t2)->
                 isWellTyped env (pi2 l1) t2
|typeBox:forall (l1:lambda_terms) (t1:semType)(env:list semType),
                 isWellTyped env l1 t1->
                 isWellTyped env (box l1) (intention t1)
|typeDebox:forall (l1:lambda_terms)(t1:semType) (env:list semType),
                 isWellTyped env l1 (intention t1)->
                 isWellTyped env (debox l1) t1
|typeDiam:forall (l1:lambda_terms)(t1:semType) (env:list semType),
                 isWellTyped env l1 t1->
                 isWellTyped env (diam l1) (intention t1)
|typeDediam:forall (l1:lambda_terms)(t1:semType) (env:list semType),
                 isWellTyped env l1 (intention t1)->
                 isWellTyped env (dediam l1) t1.

Fixpoint type_check (env:list semType)(l:lambda_terms){struct l} :
 (option semType):=
match l with
| num n => nth_error env n
| ress r => Some (getSemTypeX r)
| hyps k ty=> Some ty
| appl l1 l2 => match (type_check env l1) with
                | Some (funAppli t1 t2) => match (type_check env l2) with
                                           | Some t'1 => match (eqDecSem t1 t'1) with
                                                        | left _ => Some t2
                                                        | right _ => None
                                                       end
                                           | None => None
                                           end
                |others => None
                 end
| abs t1 l1 => match (type_check (t1::env) l1) with
              | Some t2 => Some (funAppli t1 t2)
              | None => None
             end
|twoL l1 l2 => match (type_check env l1) with
       |Some t1 => match (type_check env l2) with
           |Some t2 => Some (cartProd t1 t2)
           | None => None
           end
       |None => None
         end
| pi1 l1=> match (type_check env l1) with
              |Some (cartProd t1 t2) => Some t1
              |others => None
            end
| pi2 l1=> match (type_check env l1) with
              |Some (cartProd t1 t2) => Some t2
              |others => None
            end
|box l1=>match (type_check env l1) with
         |Some t1 => Some (intention t1)
         |None => None
       end
|debox l1=>match (type_check env l1) with
           |Some (intention t1) => Some t1
           |others => None
       end
|diam l1=>match (type_check env l1) with
         |Some t1 => Some (intention t1)
         |None => None
       end
|dediam l1=>match (type_check env l1) with
           |Some (intention t1) => Some t1
           |others => None
       end
end.

Ltac disc:=
 match goal with
| H: None = Some _ |- _ =>
 discriminate H
end.

Lemma getTypeAppl :forall (l1 l2:lambda_terms)(env :list semType)(t1:semType),
                   type_check env (appl l1 l2) =Some t1 ->
                  {t2:semType | (type_check env l1 = (Some (funAppli t2 t1))) /\
                   (type_check env l2 = (Some t2))}.
Proof.
intros.
generalize H;clear H.
simpl;elim (type_check env l1); elim (type_check env l2).
intros a a0; case a0.
intro H2; discriminate H2.
intro H2; discriminate H2.
intros s s0; elim (eqDecSem s a).
intros.
exists s.
rewrite a1; injection H; intro R; rewrite R; tauto.
intros H H1; discriminate H1.
intros s s0 H1; discriminate H1.
intros H H1; discriminate H1.
intro a; elim a; intros; disc.
intros.
 discriminate H.
intro H; discriminate H.
Defined.

Lemma getTypeTwoL:forall (l1 l2:lambda_terms)(env :list semType)(t1:semType),
                             type_check env (twoL l1 l2) =Some t1 ->
                             {t'1: semType & { t'2:semType |t1 =cartProd t'1 t'2 /\
                              type_check env l1 =Some t'1 /\
                              type_check env l2 =Some t'2}}.
Proof.
intros.
generalize H; clear H; simpl;
 elim (type_check env l1); elim (type_check env l2).
intros.
exists a0; exists a.
injection H; intro R; rewrite R;tauto.
intros; disc.
intros; disc.
intros ; disc.
Defined.

Lemma getTypePi1:forall (l1:lambda_terms)(env:list semType)(t1:semType),
                        (type_check env (pi1 l1)) = Some t1 ->
                        {t2:semType|(type_check env l1) =
                                           Some (cartProd t1 t2)}.
Proof.
intros.
generalize H; clear H;simpl.
elim (type_check env l1).
intro a; elim a; intros; try disc.
exists s0; injection H1; intro R; rewrite R.
auto.
intro; disc.
Defined.

Lemma getTypePi2:forall (l1:lambda_terms)(env:list semType)(t1:semType),
                        (type_check env (pi2 l1)) = Some t1 ->
                        {t2:semType|(type_check env l1) =
                                   Some (cartProd t2 t1)}.
Proof.
intros.
generalize H; clear H;simpl.
elim (type_check env l1).
intro a; elim a; intros; try disc.
exists s; injection H1; intro R; rewrite R.
auto.
intro; disc.
Defined.

Lemma getTypeAbs: forall (l1 :lambda_terms)(t1 t2:semType)(env:list semType),
                     type_check env (abs t1 l1)=Some t2 ->
                     {t'1:semType| t2=funAppli t1 t'1 /\
                                          type_check (t1::env) l1 =Some t'1}.
Proof.
intros.
generalize H.
clear H; simpl.
case (type_check (t1::env) l1).
intros s H; injection H; intro R; rewrite <- R.
exists s;tauto.
intro; disc.
Defined.

Lemma getTypeBox:forall (l1:lambda_terms)(t1:semType)(env:list semType),
                     type_check env (box l1)=Some t1->
                     { t'1:semType| t1=intention t'1/\ type_check env l1 =Some t'1}.
Proof.
 intros.
 generalize H; clear H; simpl in |- *.
 elim (type_check env l1).
 intros.
 injection H.
 intro.
 exists a; split.
 rewrite H0; reflexivity.
 auto.
 intro H1; discriminate H1.
Defined.

Lemma getTypeDiam:forall (l1:lambda_terms)(t1:semType)(env:list semType),
                     type_check env (diam l1)=Some t1->
                     {t'1:semType| t1=intention t'1/\
                      type_check env l1 =Some t'1}.
Proof.
 intros.
 generalize H; clear H; simpl in |- *.
 elim (type_check env l1).
 intros.
 injection H.
 intro.
 exists a; split.
 rewrite H0; reflexivity.
 auto.
 intro H1; discriminate H1.
Defined.

Lemma getTypeDebox:forall (l1:lambda_terms)(t1:semType)(env:list semType),
                    type_check env (debox l1)=Some t1->
                    type_check env l1=Some (intention t1).
Proof.
 intros l1 t1 env.
 simpl in |- *.
 elim (type_check env l1).
 intro a.
 case a; intros; try disc.
 injection H; intro R; rewrite R; auto.
 intro; disc.
Defined.

Lemma getTypeDediam:forall (l1:lambda_terms)(t1:semType)(env:list semType),
                   type_check env (dediam l1)=Some t1->
                   type_check env l1=Some (intention t1).
Proof.
 intros l1 t1 env.
 simpl in |- *.
 elim (type_check env l1).
 intro a.
 case a; intros; try disc.
 injection H; intro R; rewrite R; auto.
 intro; disc.
Defined.

Lemma type_check_wellTyped:forall (l1:lambda_terms)(env:list semType) (t1:semType),
                        type_check env l1= Some t1->
                         isWellTyped env l1 t1.
Proof.
intro l1; elim l1;intros.
simpl in H.
constructor.
auto.
simpl in H.
injection H.
intro R;rewrite <-R;constructor.
simpl in H;injection H;intro R.
rewrite <- R; constructor.
elim (getTypeAppl _ _ _ H1).
intros x H2.
elim H2; intros.
econstructor; eauto.
elim (getTypeAbs _ _ _ H0).
intros x H1.
elim H1; intros R H2; rewrite R.
constructor.
apply H;auto.
elim (getTypeTwoL _ _ _ H1).
intros x H2.
elim H2; intros x0 H3.
elim H3; intros H4 H5.
rewrite H4; elim H5; intros; constructor;auto.
elim (getTypePi1 _ _ H0).
intros.
econstructor;eauto.
elim (getTypePi2 _ _ H0); intros; econstructor; eauto.
elim (getTypeBox _ _ H0).
intros x H1.
elim H1; clear H1; intros.
subst.
constructor.
eauto.
constructor.
apply H.
apply getTypeDebox; auto.
elim (getTypeDiam _ _ H0).
intros x H1.
elim H1; clear H1; intros.
subst.
constructor.
auto.
constructor.
apply H; apply getTypeDediam.
auto.
Defined.

Lemma wellTyped_type_check:forall (l1:lambda_terms)(env:list semType) (t1:semType),
                   isWellTyped env l1 t1->
                   type_check env l1= Some t1.
Proof.
 induction 1.
 simpl in |- *; auto.
 simpl in |- *; auto.
 auto.
 simpl in |- *; rewrite IHisWellTyped1;
 rewrite IHisWellTyped2; auto.
 case (eqDecSem t1 t1).
 auto.
 induction 1; auto.
 simpl in |- *.
 rewrite IHisWellTyped.
 auto.
 simpl in |- *; rewrite IHisWellTyped1;
 rewrite IHisWellTyped2; auto.
 simpl in |- *.
 rewrite IHisWellTyped; auto.
 simpl in |- *; rewrite IHisWellTyped; auto.
 simpl in |- *; rewrite IHisWellTyped; auto.
 simpl in |- *; rewrite IHisWellTyped; auto.
 simpl in |- *; rewrite IHisWellTyped; auto.
 simpl in |- *; rewrite IHisWellTyped; auto.
Defined.

Lemma one_type:forall (l:lambda_terms) (t1 t2:semType)(env:list semType),
                     isWellTyped env l t1 ->
                     isWellTyped env l t2 ->
                      t1 =t2.
Proof.
 intros; cut (Some t1 = Some t2).
 injection 1; auto.
 rewrite <- (wellTyped_type_check H); rewrite <- (wellTyped_type_check H0).
 auto.
Qed.

Inductive add_ith_list (A:Set)(a:A):list A->list A->nat->Prop:=
|add_0:forall l1, add_ith_list a l1 (a::l1) 0
|add_next:forall l1 l2 i b , add_ith_list a l1 l2 i->add_ith_list a
(b::l1)(b::l2) (S i).

Lemma nth_add1:forall (A:Set)(l1 l2:list A)(i:nat)a b,
                 add_ith_list a l1 l2 i->
              forall (n:nat), n>=i->
              nth_error l1 n=Some b->
              nth_error l2 (S n) =Some b.
Proof.
 induction 1.
 simpl in |- *; auto.
 simpl in |- *.
 intros.
 generalize H0 H1; clear H0 H1; case n; intros.
 inversion H0.
 simpl in H1.
 eauto with arith.
Qed.

Lemma nth_add2:forall (A:Set)(l1 l2:list A)(i:nat)a b,
                 add_ith_list a l1 l2 i->
              forall (n:nat), n<i->
              nth_error l1 n=Some b->
              nth_error l2 n =Some b.
Proof.
 induction 1.
 inversion 1.
 intro n; case n; simpl in |- *; intros.
 auto.
 eauto with arith.
Qed.

Lemma nth_add3:forall (A:Set)(l1 l2:list A)(i:nat)a ,
                 add_ith_list a l1 l2 i->
                nth_error l2 i=Some a.
induction 1;simpl;auto.
Qed.

Lemma wellFLe1:forall (n m:nat), lt n m ->
                                isWellFormedN m (num n).
Proof.
 intros.
 simpl in |- *.
 elim (le_lt_dec m n); intro.
 absurd (m <= n); auto with arith.
 auto.
Qed.

Lemma wellFLe2:forall (n m:nat),isWellFormedN m (num n)->
                                lt n m.
Proof.
 intros n m .
 simpl in |- *.
 elim (le_lt_dec m n).
 tauto.
 auto.
Qed.

Lemma notWellFormedNum:forall (n:nat), isWellFormed (num n) ->
                                       False.
Proof.
 intros n H.
 unfold isWellFormed in H.
 cut (n < O).
 intro; auto with arith.
 apply wellFLe2 ; auto.
Qed.

Lemma wellFLe: forall (l:lambda_terms)(n m:nat), n <= m ->
                                        (isWellFormedN n l)->
                                        (isWellFormedN m l).
Proof.
 intro l; elim l; intros.
 apply wellFLe1.
 eapply lt_le_trans.
 eapply wellFLe2; eauto.
 auto.
 simpl in |- *; auto.
 simpl in |- *; auto.
 simpl in H2; elim H2; clear H2; intros; simpl in |- *;split; eauto.
 simpl in H1.
 simpl in |- *.
 apply (H (S n) (S m)).
 auto with arith.
 auto.
 simpl in |- *.
 simpl in H2; elim H2; intros;split;eauto.
 simpl in |- *;simpl in H1;eauto.
 simpl in |- *; simpl in H1; eauto.
 simpl in |- *; simpl in H1; eauto.
 simpl in |- *; simpl in H1; eauto.
 simpl in |- *; simpl in H1; eauto.
 simpl in |- *; simpl in H1; eauto.
Qed.

Lemma isWellFormedBindN:forall (l:lambda_terms)(i n:nat)(st:semType),
                            isWellFormedN i l->
                            isWellFormedN (S i) (lambdaBind l i n st).
Proof.
 intro l; elim l; intros.
 simpl lambdaBind.
 case (le_lt_dec i n).
 intro; apply wellFLe1.
 cut (n < i).
 auto with arith.
 eapply wellFLe2; eauto.
 intro; apply wellFLe1; auto with arith.
 simpl in |- *;auto.
 simpl in |- *.
 case (eq_nat_dec n n0).
 case (eqDecSem s st).
 intros; apply wellFLe1; auto with arith.
 simpl in |- *; auto.
 auto.
 simpl in |- *.
 auto.
 simpl in |- *;simpl in H1; elim H1;intros; split; eauto.
 simpl; simpl in H0; intros; eauto.
 simpl in |- *;elim H1; intros;split; eauto.
 simpl in |- *; simpl in H0; intros; eauto.
 simpl in |- *; simpl in H0; intros; eauto.
 simpl in |- *; simpl in H0; intros; eauto.
 simpl in |- *; simpl in H0; intros; eauto.
 simpl in |- *; simpl in H0; intros; eauto.
 simpl in |- *; simpl in H0; intros; eauto.
Qed.

Lemma isWellFormedBind: forall (l:lambda_terms)(n:nat)(st:semType),
                       isWellFormed l ->
                       isWellFormed (lambdaAbs l n st).
Proof.
 unfold isWellFormed in |- *.
 unfold lambdaAbs in |- *.
 simpl in |- *.
 intros.
 apply isWellFormedBindN; auto.
Qed.

Lemma wellFormedUp:forall (l1 :lambda_terms)(i j k:nat),
                   isWellFormedN i l1->
                   isWellFormedN (i+j) (up_lambda l1 j k).
Proof.
  intro l1;elim l1.
  simpl up_lambda in |- *.
  intros; elim (le_lt_dec k n); intro.
  cut (n < i).
  intro; apply wellFLe1; auto with arith.
  apply wellFLe2; auto.
  apply wellFLe with i.
  auto with arith.
  auto.
  simpl in |- *; auto.
  simpl in |- *; auto.
  simpl in |- *.
  intros; elim H1; split; auto.
  simpl in |- *; intros; auto.
  cut (S (i + j) = S i + j).
  intro H1; rewrite H1.
  auto.
  auto with arith.
  simpl in |- *; intros.
  elim H1; split; auto.
  simpl in |- *; intros; auto.
  simpl in |- *; intros; auto.
  simpl in |- *; intros; auto.
  simpl in |- *; intros; auto.
  simpl in |- *; intros;auto.
  simpl in |- *; intros; auto.
Qed.

Lemma wellFormNSub:forall (l1 l2:lambda_terms)(i j n:nat)(st:semType),
                        isWellFormedN i l2->
                        isWellFormedN j l1->
                        isWellFormedN (i+j) (lambdaSubN l1 l2 j n st).
Proof.
 intro l1; elim l1; intros.
 simpl in |- *.
 apply wellFLe1.
 cut (n < j).
 unfold lt in |- *; intro.
 apply le_trans with j.
 auto.
 auto with arith.
 apply wellFLe2; auto.
 simpl in |- *.
 auto.
 simpl in |- *.
 case (eq_nat_dec n n0).
 case (eqDecSem s st).
 unfold lift_lambda in |- *.
 intros; apply wellFormedUp.
 auto.
 simpl in |- *; auto.
 simpl in |- *; auto.
 simpl in |- *.
 simpl in H2; split.
 elim H2; auto.
 elim H2; auto.
 simpl in |- *.
 simpl in H1.
 cut (S (i + j) = i + S j).
 intro H2; rewrite H2.
 auto.
 auto with arith.
 elim H2; simpl in |- *; split; auto.
 simpl in H1; simpl in |- *; auto.
 simpl in H1; simpl in |- *; auto.
 simpl in H1; simpl in |- *; auto.
 simpl in H1; simpl in |- *; auto.
 simpl in H1; simpl in |- *; auto.
 simpl in H1; simpl in |- *; auto.
Qed.

Lemma isWellFormedSubst:forall (l1 l2:lambda_terms)(n:nat)(st:semType),
                         isWellFormed l2->
                         isWellFormed l1->
                         isWellFormed (lambSub l1 l2 n st).
Proof.
 unfold isWellFormed in |- *; unfold lambSub in |- *.
 intros.
 change (isWellFormedN (0 + 0) (lambdaSubN l1 l2 0 n st)) in |- *.
 apply wellFormNSub;auto.
Qed.

Lemma wellTypedFormed:forall (l:lambda_terms)(t1:semType)(env:list semType),
                             isWellTyped env l t1 ->
                             isWellFormedN (length env) l.
Proof.
intro l ; elim l; intros.
inversion H.
apply wellFLe1.
eapply nth_error_some_length; eauto.
simpl in |- *; auto.
simpl;auto.
inversion H1;simpl;split;eauto.
inversion H0; simpl.
cut ((S (length env))=(length (s::env))).
intro R; rewrite R;eauto.
simpl;auto.
inversion H1;simpl; split;eauto.
inversion H0; simpl;eauto.
inversion H0; simpl; eauto.
inversion H0;simpl;eauto.
inversion H0;simpl;eauto.
inversion H0;simpl;eauto.
inversion H0;simpl;eauto.
Defined.

Lemma wellTypedBind: forall (l:lambda_terms)(t1:semType)
                     (env:(list semType))(n:nat)(st:semType),
                            isWellTyped env l t1 ->
                           (forall (i:nat)(env':list semType),
                              add_ith_list st env env' i->
                              isWellTyped env' (lambdaBind l i n st) t1).
Proof.
 induction 1; intros; simpl in |- *.
 case (le_lt_dec i n0).
 intro; constructor.
 eapply nth_add1; eauto.
 intro; constructor; eapply nth_add2; eauto.
 constructor.
 auto.
 case (eq_nat_dec n0 n).
 case (eqDecSem ty st).
 intros; subst; constructor.
 eapply nth_add3; eauto.
 intros; constructor.
 intro; constructor.
 econstructor; eauto.
 constructor.
 apply IHisWellTyped.
 constructor; auto.
 constructor; auto.
 econstructor; eauto.
 econstructor; eauto.
 constructor; auto.
 constructor; auto.
 constructor; auto.
 constructor; auto.
Defined.

Lemma wellTypedAbs:forall (l:lambda_terms)(t1:semType)
             (env:list semType)(n:nat)(st:semType),
                       isWellTyped env l t1 ->
                       isWellTyped env (lambdaAbs l n st) (funAppli st t1).
Proof.
intros.
unfold lambdaAbs.
constructor.
eapply wellTypedBind.
eauto.
constructor.
Defined.

Lemma wellTypedAppEnv:forall (l1:lambda_terms)(env1 env2:list semType)(t1:semType),
                       isWellTyped env1 l1 t1 ->
                       isWellTyped (env1++ env2) l1 t1.
Proof.
intro l1; elim l1; intros.
inversion H.
constructor.
apply nth_error_fst_app; auto.
inversion H.
constructor.
auto.
inversion H.
constructor.
inversion H1; econstructor;eauto.
inversion H0; constructor.
change (s::env1++env2) with ((s::env1)++env2).
apply H;auto.
inversion H1; constructor;auto.
inversion H0; econstructor;eauto.
inversion H0; econstructor; eauto.
inversion H0; constructor;auto.
inversion H0; constructor;auto.
inversion H0; constructor;auto.
inversion H0; constructor;auto.
Defined.

Lemma wellTypedSub: forall(l1 l2 :lambda_terms)(env:list semType)
                                (i n:nat)(t1 st:semType),
                               isWellTyped nil l2 st ->
                               isWellTyped env l1 t1 ->
                               isWellTyped env (lambdaSubN l1 l2 i n st) t1.
Proof.
intro l1; elim l1; intros;simpl.
auto.
auto.
case (eq_nat_dec n n0).
case (eqDecSem s st).
intros; subst.
inversion H0.
subst.
unfold lift_lambda in |- *; rewrite lift_wf.
change env with (nil ++ env) in |- *.
apply wellTypedAppEnv; auto.
exact (wellTypedFormed H).
auto.
auto.
inversion H2.
econstructor;eauto.
inversion H1.
constructor;eauto.
inversion H2; constructor;auto.
inversion H1;econstructor;eauto.
inversion H1; econstructor;eauto.
inversion H1; constructor;auto.
inversion H1; constructor;auto.
inversion H1; constructor;auto.
inversion H1; constructor;auto.
Defined.

Lemma wellTypedSubst: forall(l1 l2 :lambda_terms)(env:list semType)
                                (n:nat)(t1 st:semType),
                               isWellTyped nil l2 st ->
                               isWellTyped env l1 t1 ->
                               isWellTyped env (lambSub l1 l2 n st) t1.
Proof.
unfold lambSub in |- *.
intros; apply wellTypedSub; auto.
Defined.

End lambdaX.
End allSem.