Library Icharate.Kernel.lambda_bruijn


Require Export listAux.
Require Export Arith.
Require Export basics.
Set Implicit Arguments.
Global Set Asymmetric Patterns.

Section allSem.
Variables I J A:Set.

Inductive semType :Set :=
| e :semType
| t : semType
| funAppli :semType semType semType
| cartProd:semType semType semType
|intention :semTypesemType.
Definition eqDecSem: (t1 t2:semType), {t1=t2}+{t1 t2}.
decide equality.
Defined.
Variable map:AsemType.

Fixpoint mapExt (f:Form I J A){struct f}:semType :=
match f with
| At pmap p
| Slash _ f1 f2funAppli (mapExt f2) (mapExt f1)
| Backslash _ f1 f2funAppli (mapExt f1) (mapExt f2)
| Dot _ f1 f2cartProd (mapExt f1) (mapExt f2)
| Box _ f1 ⇒ (intention (mapExt f1))
| Diamond _ f1 ⇒ (intention (mapExt f1))
end.

Section lambdaX.
Variable X:Set.
Variable getSemTypeX : XsemType.

Inductive lambda_terms:Set:=
| num : nat lambda_terms
| ress : X lambda_terms
| hyps: natsemTypelambda_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 kmatch (le_lt_dec n k) with
                            | right _True
                            | left _False
             end
| ress rTrue
|hyps _ _True
| appl l1 l2isWellFormedN n l1 isWellFormedN n l2
| abs _ l1isWellFormedN (S n) l1
| twoL l1 l2isWellFormedN n l1 isWellFormedN n l2
| pi1 l1isWellFormedN n l1
| pi2 l1isWellFormedN n l1
| box l1isWellFormedN n l1
| debox l1isWellFormedN n l1
| diam l1isWellFormedN n l1
| dediam l1isWellFormedN 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 kTrue
| ress rTrue
| appl l1 l2no_hyps_inside l1 no_hyps_inside l2
| abs _ l1no_hyps_inside l1
| twoL l1 l2no_hyps_inside l1 no_hyps_inside l2
| pi1 l1no_hyps_inside l1
| pi2 l1no_hyps_inside l1
| box l1no_hyps_inside l1
| debox l1no_hyps_inside l1
| diam l1no_hyps_inside l1
| dediam l1no_hyps_inside l1
end.

Fixpoint lambdaBind (lTerm:lambda_terms)(i n:nat)(st:semType){struct lTerm}:lambda_terms :=
match lTerm with
| num lif (le_lt_dec i l) then (num (S l)) else (num l)
| ress rress r
| hyps k sif (eq_nat_dec k n)
           then (if (eqDecSem s st) then (num i) else (hyps k s))
           else (hyps k s)
| appl t1 t2appl (lambdaBind t1 i n st) (lambdaBind t2 i n st)
| abs ty t1abs ty (lambdaBind t1 (S i) n st)
| twoL t1 t2twoL (lambdaBind t1 i n st) (lambdaBind t2 i n st)
| pi1 t1pi1 (lambdaBind t1 i n st)
| pi2 t1pi2 (lambdaBind t1 i n st)
| box t1box (lambdaBind t1 i n st)
| debox t1debox (lambdaBind t1 i n st)
| diam t1diam (lambdaBind t1 i n st)
| dediam t1dediam (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 mmatch (le_lt_dec i m) with
            |left _num (m+n)
            |right _num m
             end
|ress rress r
|hyps k shyps k s
|appl l1 l2appl (up_lambda l1 n i) (up_lambda l2 n i)
|abs ty l1abs ty (up_lambda l1 n (S i))
| twoL l1 l2twoL (up_lambda l1 n i) (up_lambda l2 n i)
| pi1 l1pi1 (up_lambda l1 n i)
|pi2 l1pi2 (up_lambda l1 n i)
| box l1box (up_lambda l1 n i)
|debox l1debox (up_lambda l1 n i)
|diam l1diam (up_lambda l1 n i)
|dediam l1dediam (up_lambda l1 n i)
end.

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

Lemma lift_wf: (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 rress r
| hyps k sif (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 t2appl (lambdaSubN t1 lTerm2 i n st) (lambdaSubN t2
lTerm2 i n st)
| abs ty t1abs ty (lambdaSubN t1 lTerm2 (S i) n st)
| twoL t1 t2twoL (lambdaSubN t1 lTerm2 i n st) (lambdaSubN t2
lTerm2 i n st)
| pi1 t1pi1 (lambdaSubN t1 lTerm2 i n st)
| pi2 t1pi2 (lambdaSubN t1 lTerm2 i n st)
| box t1box (lambdaSubN t1 lTerm2 i n st)
| debox t1debox (lambdaSubN t1 lTerm2 i n st)
| diam t1diam (lambdaSubN t1 lTerm2 i n st)
|dediam t1dediam (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_termssemType Set:=
| typeNum: (env:list semType) (n:nat)(ty:semType),
                    nth_error env n=Some ty
                    isWellTyped env (num n) ty
| typeVar : (x:X)(env:list semType) ,
                  isWellTyped env (ress x) (getSemTypeX x)
|typeHyps: (n:nat)(ty:semType)env, isWellTyped env (hyps n ty) ty
| typeAppl : (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 : (l1:lambda_terms)( t1 t2:semType)(env:list semType),
                  isWellTyped (t2::env) l1 t1
                  isWellTyped env (abs t2 l1) (funAppli t2 t1)
| typeTwoL: (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: (l1:lambda_terms)(t1 t2 :semType)(env:list semType),
                 isWellTyped env l1 (cartProd t1 t2)
                 isWellTyped env (pi1 l1) t1
| typePi2 : (l1:lambda_terms)(t1 t2 :semType)(env:list semType),
                 isWellTyped env l1 (cartProd t1 t2)
                 isWellTyped env (pi2 l1) t2
|typeBox: (l1:lambda_terms) (t1:semType)(env:list semType),
                 isWellTyped env l1 t1
                 isWellTyped env (box l1) (intention t1)
|typeDebox: (l1:lambda_terms)(t1:semType) (env:list semType),
                 isWellTyped env l1 (intention t1)
                 isWellTyped env (debox l1) t1
|typeDiam: (l1:lambda_terms)(t1:semType) (env:list semType),
                 isWellTyped env l1 t1
                 isWellTyped env (diam l1) (intention t1)
|typeDediam: (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 nnth_error env n
| ress rSome (getSemTypeX r)
| hyps k tySome ty
| appl l1 l2match (type_check env l1) with
                | Some (funAppli t1 t2) ⇒ match (type_check env l2) with
                                           | Some t'1match (eqDecSem t1 t'1) with
                                                        | left _Some t2
                                                        | right _None
                                                       end
                                           | NoneNone
                                           end
                |othersNone
                 end
| abs t1 l1match (type_check (t1::env) l1) with
              | Some t2Some (funAppli t1 t2)
              | NoneNone
             end
|twoL l1 l2match (type_check env l1) with
       |Some t1match (type_check env l2) with
           |Some t2Some (cartProd t1 t2)
           | NoneNone
           end
       |NoneNone
         end
| pi1 l1match (type_check env l1) with
              |Some (cartProd t1 t2) ⇒ Some t1
              |othersNone
            end
| pi2 l1match (type_check env l1) with
              |Some (cartProd t1 t2) ⇒ Some t2
              |othersNone
            end
|box l1match (type_check env l1) with
         |Some t1Some (intention t1)
         |NoneNone
       end
|debox l1match (type_check env l1) with
           |Some (intention t1) ⇒ Some t1
           |othersNone
       end
|diam l1match (type_check env l1) with
         |Some t1Some (intention t1)
         |NoneNone
       end
|dediam l1match (type_check env l1) with
           |Some (intention t1) ⇒ Some t1
           |othersNone
       end
end.

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

Lemma getTypeAppl : (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.
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: (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.
a0; a.
injection H; intro R; rewrite R;tauto.
intros; disc.
intros; disc.
intros ; disc.
Defined.

Lemma getTypePi1: (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.
s0; injection H1; intro R; rewrite R.
auto.
intro; disc.
Defined.

Lemma getTypePi2: (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.
s; injection H1; intro R; rewrite R.
auto.
intro; disc.
Defined.

Lemma getTypeAbs: (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.
s;tauto.
intro; disc.
Defined.

Lemma getTypeBox: (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.
  a; split.
 rewrite H0; reflexivity.
 auto.
 intro H1; discriminate H1.
Defined.

Lemma getTypeDiam: (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.
  a; split.
 rewrite H0; reflexivity.
 auto.
 intro H1; discriminate H1.
Defined.

Lemma getTypeDebox: (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: (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: (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: (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: (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 Alist AnatProp:=
|add_0: l1, add_ith_list a l1 (a::l1) 0
|add_next: l1 l2 i b , add_ith_list a l1 l2 iadd_ith_list a
(b::l1)(b::l2) (S i).

Lemma nth_add1: (A:Set)(l1 l2:list A)(i:nat)a b,
                 add_ith_list a l1 l2 i
               (n:nat), ni
              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: (A:Set)(l1 l2:list A)(i:nat)a b,
                 add_ith_list a l1 l2 i
               (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: (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: (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: (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: (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: (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: (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: (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: (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: (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: (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: (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: (l:lambda_terms)(t1:semType)
                     (env:(list semType))(n:nat)(st:semType),
                            isWellTyped env l t1
                           ( (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: (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: (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: (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: (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.