Require Import MyTactics. Require Import LambdaCalculusSyntax. Require Import LambdaCalculusValues. Require Import LambdaCalculusReduction. Require Import STLCDefinition. Require Import STLCLemmas.
This is a failed attempt to prove the lemma jt_te_substitution_0
in
a direct way, without introducing the auxiliary judgement js
. See
STLCLemmas for a valid proof.
forall (Delta : tyenv) (t1 : term) (U : ty), jt Delta t1 U -> forall (Gamma : var -> ty) (t2 : term) (T : ty), Delta = T .: Gamma -> jt Gamma t2 T -> jt Gamma t1.[t2/] U(* Let us attempt to naively prove this statement by induction. *)forall (Delta : tyenv) (t1 : term) (U : ty), jt Delta t1 U -> forall (Gamma : var -> ty) (t2 : term) (T : ty), Delta = T .: Gamma -> jt Gamma t2 T -> jt Gamma t1.[t2/] Ux: var
Gamma0: var -> ty
t2: term
T0: ty
H1: jt Gamma0 t2 T0jt Gamma0 ((t2 .: ids) x) ((T0 .: Gamma0) x)t: term
T, U: ty
Gamma0: var -> ty
T0: ty
IHjt: forall (Gamma : var -> ty) (t2 : term) (T1 : ty), T .: T0 .: Gamma0 = T1 .: Gamma -> jt Gamma t2 T1 -> jt Gamma t.[t2/] U
H: jt (T .: T0 .: Gamma0) t U
t2: term
H1: jt Gamma0 t2 T0jt Gamma0 (Lam t.[ids 0 .: lift 1 t2 .: ren (+1)]) (TyFun T U)t1, t2: term
T, U: ty
Gamma0: var -> ty
T0: ty
IHjt2: forall (Gamma : var -> ty) (t3 : term) (T1 : ty), T0 .: Gamma0 = T1 .: Gamma -> jt Gamma t3 T1 -> jt Gamma t2.[t3/] T
IHjt1: forall (Gamma : var -> ty) (t2 : term) (T1 : ty), T0 .: Gamma0 = T1 .: Gamma -> jt Gamma t2 T1 -> jt Gamma t1.[t2/] (TyFun T U)
H0: jt (T0 .: Gamma0) t2 T
H: jt (T0 .: Gamma0) t1 (TyFun T U)
t0: term
H2: jt Gamma0 t0 T0jt Gamma0 (App t1.[t0/] t2.[t0/]) U(* JTVar. *)x: var
Gamma0: var -> ty
t2: term
T0: ty
H1: jt Gamma0 t2 T0jt Gamma0 ((t2 .: ids) x) ((T0 .: Gamma0) x)t1, t2: term
T, U: ty
Gamma0: var -> ty
T0: ty
IHjt2: forall (Gamma : var -> ty) (t3 : term) (T1 : ty), T0 .: Gamma0 = T1 .: Gamma -> jt Gamma t3 T1 -> jt Gamma t2.[t3/] T
IHjt1: forall (Gamma : var -> ty) (t2 : term) (T1 : ty), T0 .: Gamma0 = T1 .: Gamma -> jt Gamma t2 T1 -> jt Gamma t1.[t2/] (TyFun T U)
H0: jt (T0 .: Gamma0) t2 T
H: jt (T0 .: Gamma0) t1 (TyFun T U)
t0: term
H2: jt Gamma0 t0 T0jt Gamma0 (App t1.[t0/] t2.[t0/]) Ut: term
T, U: ty
Gamma0: var -> ty
T0: ty
IHjt: forall (Gamma : var -> ty) (t2 : term) (T1 : ty), T .: T0 .: Gamma0 = T1 .: Gamma -> jt Gamma t2 T1 -> jt Gamma t.[t2/] U
H: jt (T .: T0 .: Gamma0) t U
t2: term
H1: jt Gamma0 t2 T0jt Gamma0 (Lam t.[ids 0 .: lift 1 t2 .: ren (+1)]) (TyFun T U)x: var
Gamma0: var -> ty
t2: term
T0: ty
H1: jt Gamma0 t2 T0jt Gamma0 ((t2 .: ids) x) ((T0 .: Gamma0) x)Gamma0: var -> ty
t2: term
T0: ty
H1: jt Gamma0 t2 T0jt Gamma0 ((t2 .: ids) 0) ((T0 .: Gamma0) 0)x: nat
Gamma0: var -> ty
t2: term
T0: ty
H1: jt Gamma0 t2 T0jt Gamma0 ((t2 .: ids) (S x)) ((T0 .: Gamma0) (S x))Gamma0: var -> ty
t2: term
T0: ty
H1: jt Gamma0 t2 T0jt Gamma0 ((t2 .: ids) 0) ((T0 .: Gamma0) 0)eauto.Gamma0: var -> ty
t2: term
T0: ty
H1: jt Gamma0 t2 T0jt Gamma0 t2 T0x: nat
Gamma0: var -> ty
t2: term
T0: ty
H1: jt Gamma0 t2 T0jt Gamma0 ((t2 .: ids) (S x)) ((T0 .: Gamma0) (S x))x: nat
Gamma0: var -> ty
t2: term
T0: ty
H1: jt Gamma0 t2 T0jt Gamma0 ((t2 .: ids) (S x)) ((T0 .: Gamma0) (S x))eauto with jt. }x: nat
Gamma0: var -> ty
t2: term
T0: ty
H1: jt Gamma0 t2 T0jt Gamma0 (ids x) (Gamma0 x)(* JTApp. *) (* This case just works, thanks to the induction hypotheses. *)t1, t2: term
T, U: ty
Gamma0: var -> ty
T0: ty
IHjt2: forall (Gamma : var -> ty) (t3 : term) (T1 : ty), T0 .: Gamma0 = T1 .: Gamma -> jt Gamma t3 T1 -> jt Gamma t2.[t3/] T
IHjt1: forall (Gamma : var -> ty) (t2 : term) (T1 : ty), T0 .: Gamma0 = T1 .: Gamma -> jt Gamma t2 T1 -> jt Gamma t1.[t2/] (TyFun T U)
H0: jt (T0 .: Gamma0) t2 T
H: jt (T0 .: Gamma0) t1 (TyFun T U)
t0: term
H2: jt Gamma0 t0 T0jt Gamma0 (App t1.[t0/] t2.[t0/]) Ut: term
T, U: ty
Gamma0: var -> ty
T0: ty
IHjt: forall (Gamma : var -> ty) (t2 : term) (T1 : ty), T .: T0 .: Gamma0 = T1 .: Gamma -> jt Gamma t2 T1 -> jt Gamma t.[t2/] U
H: jt (T .: T0 .: Gamma0) t U
t2: term
H1: jt Gamma0 t2 T0jt Gamma0 (Lam t.[ids 0 .: lift 1 t2 .: ren (+1)]) (TyFun T U)eauto with jt.t1, t2: term
T, U: ty
Gamma0: var -> ty
T0: ty
IHjt2: forall (Gamma : var -> ty) (t3 : term) (T1 : ty), T0 .: Gamma0 = T1 .: Gamma -> jt Gamma t3 T1 -> jt Gamma t2.[t3/] T
IHjt1: forall (Gamma : var -> ty) (t2 : term) (T1 : ty), T0 .: Gamma0 = T1 .: Gamma -> jt Gamma t2 T1 -> jt Gamma t1.[t2/] (TyFun T U)
H0: jt (T0 .: Gamma0) t2 T
H: jt (T0 .: Gamma0) t1 (TyFun T U)
t0: term
H2: jt Gamma0 t0 T0jt Gamma0 (App t1.[t0/] t2.[t0/]) U(* JTLam. *)t: term
T, U: ty
Gamma0: var -> ty
T0: ty
IHjt: forall (Gamma : var -> ty) (t2 : term) (T1 : ty), T .: T0 .: Gamma0 = T1 .: Gamma -> jt Gamma t2 T1 -> jt Gamma t.[t2/] U
H: jt (T .: T0 .: Gamma0) t U
t2: term
H1: jt Gamma0 t2 T0jt Gamma0 (Lam t.[ids 0 .: lift 1 t2 .: ren (+1)]) (TyFun T U)t: term
T, U: ty
Gamma0: var -> ty
T0: ty
IHjt: forall (Gamma : var -> ty) (t2 : term) (T1 : ty), T .: T0 .: Gamma0 = T1 .: Gamma -> jt Gamma t2 T1 -> jt Gamma t.[t2/] U
H: jt (T .: T0 .: Gamma0) t U
t2: term
H1: jt Gamma0 t2 T0jt Gamma0 (Lam t.[ids 0 .: lift 1 t2 .: ren (+1)]) (TyFun T U)(* We would now like to apply the induction hypothesis, but this fails, because the statement of the lemma allows substituting a term for variable 0, but we are now attempting to substitute a term for variable 1. *)t: term
T, U: ty
Gamma0: var -> ty
T0: ty
IHjt: forall (Gamma : var -> ty) (t2 : term) (T1 : ty), T .: T0 .: Gamma0 = T1 .: Gamma -> jt Gamma t2 T1 -> jt Gamma t.[t2/] U
H: jt (T .: T0 .: Gamma0) t U
t2: term
H1: jt Gamma0 t2 T0jt (T .: Gamma0) t.[ids 0 .: lift 1 t2 .: ren (+1)] U(* The moral of the story is that it is preferable to state a lemma that allows applying an arbitrary substitution (of terms for term variables) to a term. This will give rise to statements that are more general, therefore both more powerful and easier to read. See STLCLemmas. *) Abort.t: term
T, U: ty
Gamma0: var -> ty
T0: ty
IHjt: forall (Gamma : var -> ty) (t2 : term) (T1 : ty), T .: T0 .: Gamma0 = T1 .: Gamma -> jt Gamma t2 T1 -> jt Gamma t.[t2/] U
H: jt (T .: T0 .: Gamma0) t U
t2: term
H1: jt Gamma0 t2 T0jt (T .: Gamma0) t.[ids 0 .: lift 1 t2 .: ren (+1)] U
The subject reduction theorem, also known as type preservation: the typing judgement is preserved by one step of reduction.
This is proved here for cbv
, but could be proved for other notions
of reduction, such as cbn
, or strong reduction.
forall (Gamma : tyenv) (t : term) (T : ty), jt Gamma t T -> forall t' : term, cbv t t' -> jt Gamma t' T(* By induction on the type derivation, then by cases on `cbv t t'`. *)forall (Gamma : tyenv) (t : term) (T : ty), jt Gamma t T -> forall t' : term, cbv t t' -> jt Gamma t' T(* Case: JApp/RedBetaV. *)Gamma: tyenv
t2: term
T, U: ty
t: term
H: jt Gamma (Lam t) (TyFun T U)
H0: jt Gamma t2 T
IHjt1: forall t' : term, cbv (Lam t) t' -> jt Gamma t' (TyFun T U)
IHjt2: forall t' : term, cbv t2 t' -> jt Gamma t' T
H4: cbv_mask RuleBetaV
H5: is_value t2jt Gamma t.[t2/] UGamma: tyenv
t1, t2: term
T, U: ty
H: jt Gamma t1 (TyFun T U)
H0: jt Gamma t2 T
IHjt1: forall t' : term, cbv t1 t' -> jt Gamma t' (TyFun T U)
IHjt2: forall t' : term, cbv t2 t' -> jt Gamma t' T
t3: term
H4: cbv_mask RuleAppL
H6: cbv t1 t3jt Gamma (App t3 t2) UGamma: tyenv
t1, t2: term
T, U: ty
H: jt Gamma t1 (TyFun T U)
H0: jt Gamma t2 T
IHjt1: forall t' : term, cbv t1 t' -> jt Gamma t' (TyFun T U)
IHjt2: forall t' : term, cbv t2 t' -> jt Gamma t' T
u2: term
H4: cbv_mask RuleAppVR
H5: is_value t1
H7: cbv t2 u2jt Gamma (App t1 u2) UGamma: tyenv
t2: term
T, U: ty
t: term
H: jt Gamma (Lam t) (TyFun T U)
H0: jt Gamma t2 T
IHjt1: forall t' : term, cbv (Lam t) t' -> jt Gamma t' (TyFun T U)
IHjt2: forall t' : term, cbv t2 t' -> jt Gamma t' T
H4: cbv_mask RuleBetaV
H5: is_value t2jt Gamma t.[t2/] Ueauto using jt_te_substitution_0.Gamma: tyenv
t2: term
T, U: ty
t: term
H0: jt Gamma t2 T
IHjt1: forall t' : term, cbv (Lam t) t' -> jt Gamma t' (TyFun T U)
IHjt2: forall t' : term, cbv t2 t' -> jt Gamma t' T
H4: cbv_mask RuleBetaV
H5: is_value t2
H6: jt (T .: Gamma) t Ujt Gamma t.[t2/] U(* Case: JApp/RedAppL. *)Gamma: tyenv
t1, t2: term
T, U: ty
H: jt Gamma t1 (TyFun T U)
H0: jt Gamma t2 T
IHjt1: forall t' : term, cbv t1 t' -> jt Gamma t' (TyFun T U)
IHjt2: forall t' : term, cbv t2 t' -> jt Gamma t' T
t3: term
H4: cbv_mask RuleAppL
H6: cbv t1 t3jt Gamma (App t3 t2) UGamma: tyenv
t1, t2: term
T, U: ty
H: jt Gamma t1 (TyFun T U)
H0: jt Gamma t2 T
IHjt1: forall t' : term, cbv t1 t' -> jt Gamma t' (TyFun T U)
IHjt2: forall t' : term, cbv t2 t' -> jt Gamma t' T
u2: term
H4: cbv_mask RuleAppVR
H5: is_value t1
H7: cbv t2 u2jt Gamma (App t1 u2) Ueauto with jt.Gamma: tyenv
t1, t2: term
T, U: ty
H: jt Gamma t1 (TyFun T U)
H0: jt Gamma t2 T
IHjt1: forall t' : term, cbv t1 t' -> jt Gamma t' (TyFun T U)
IHjt2: forall t' : term, cbv t2 t' -> jt Gamma t' T
t3: term
H4: cbv_mask RuleAppL
H6: cbv t1 t3jt Gamma (App t3 t2) U(* Case: JApp/RedAppVR. *)Gamma: tyenv
t1, t2: term
T, U: ty
H: jt Gamma t1 (TyFun T U)
H0: jt Gamma t2 T
IHjt1: forall t' : term, cbv t1 t' -> jt Gamma t' (TyFun T U)
IHjt2: forall t' : term, cbv t2 t' -> jt Gamma t' T
u2: term
H4: cbv_mask RuleAppVR
H5: is_value t1
H7: cbv t2 u2jt Gamma (App t1 u2) Ueauto with jt. } Qed.Gamma: tyenv
t1, t2: term
T, U: ty
H: jt Gamma t1 (TyFun T U)
H0: jt Gamma t2 T
IHjt1: forall t' : term, cbv t1 t' -> jt Gamma t' (TyFun T U)
IHjt2: forall t' : term, cbv t2 t' -> jt Gamma t' T
u2: term
H4: cbv_mask RuleAppVR
H5: is_value t1
H7: cbv t2 u2jt Gamma (App t1 u2) U
An inversion lemma: if a closed value admits a function type TyFun T1 T2
,
then it must be a lambda-abstraction.
forall (Gamma : tyenv) (t : term) (T1 T2 : ty), jt Gamma t (TyFun T1 T2) -> closed t -> is_value t -> exists t' : {bind term}, t = Lam t'(* By cases. The type system is so simple that an induction is not even required here. An induction would be required if the type system had non-syntax-directed rules, such as a subtyping rule, or type abstraction and type instantiation rules, as in System F. *)forall (Gamma : tyenv) (t : term) (T1 T2 : ty), jt Gamma t (TyFun T1 T2) -> closed t -> is_value t -> exists t' : {bind term}, t = Lam t'(* Case: JVar. A variable is not closed. Contradiction. *)Gamma: tyenv
T1, T2: ty
x: var
H: jt Gamma (Var x) (TyFun T1 T2)
H0: Gamma x = TyFun T1 T2
H4: closed (Var x)
H5: is_value (Var x)exists t' : {bind term}, Var x = Lam t'Gamma: tyenv
T1, T2: ty
t0: term
H: jt Gamma (Lam t0) (TyFun T1 T2)
H3: jt (T1 .: Gamma) t0 T2
H5: closed (Lam t0)
H6: is_value (Lam t0)exists t' : {bind term}, Lam t0 = Lam t'Gamma: tyenv
T1, T2: ty
t1, t2: term
H: jt Gamma (App t1 t2) (TyFun T1 T2)
T: ty
H0: jt Gamma t1 (TyFun T (TyFun T1 T2))
H1: jt Gamma t2 T
H5: closed (App t1 t2)
H6: is_value (App t1 t2)exists t' : {bind term}, App t1 t2 = Lam t'Gamma: tyenv
T1, T2: ty
x: var
H: jt Gamma (Var x) (TyFun T1 T2)
H0: Gamma x = TyFun T1 T2
H4: closed (Var x)
H5: is_value (Var x)exists t' : {bind term}, Var x = Lam t'eauto with closed.Gamma: tyenv
T1, T2: ty
x: var
H: jt Gamma (Var x) (TyFun T1 T2)
H0: Gamma x = TyFun T1 T2
H4: closed (Var x)
H5: is_value (Var x)False(* Case: JLam. Immediate. *)Gamma: tyenv
T1, T2: ty
t0: term
H: jt Gamma (Lam t0) (TyFun T1 T2)
H3: jt (T1 .: Gamma) t0 T2
H5: closed (Lam t0)
H6: is_value (Lam t0)exists t' : {bind term}, Lam t0 = Lam t'Gamma: tyenv
T1, T2: ty
t1, t2: term
H: jt Gamma (App t1 t2) (TyFun T1 T2)
T: ty
H0: jt Gamma t1 (TyFun T (TyFun T1 T2))
H1: jt Gamma t2 T
H5: closed (App t1 t2)
H6: is_value (App t1 t2)exists t' : {bind term}, App t1 t2 = Lam t'obvious.Gamma: tyenv
T1, T2: ty
t0: term
H: jt Gamma (Lam t0) (TyFun T1 T2)
H3: jt (T1 .: Gamma) t0 T2
H5: closed (Lam t0)
H6: is_value (Lam t0)exists t' : {bind term}, Lam t0 = Lam t'(* Case: JApp. An application is not a value. Contradiction. *)Gamma: tyenv
T1, T2: ty
t1, t2: term
H: jt Gamma (App t1 t2) (TyFun T1 T2)
T: ty
H0: jt Gamma t1 (TyFun T (TyFun T1 T2))
H1: jt Gamma t2 T
H5: closed (App t1 t2)
H6: is_value (App t1 t2)exists t' : {bind term}, App t1 t2 = Lam t'Gamma: tyenv
T1, T2: ty
t1, t2: term
H: jt Gamma (App t1 t2) (TyFun T1 T2)
T: ty
H0: jt Gamma t1 (TyFun T (TyFun T1 T2))
H1: jt Gamma t2 T
H5: closed (App t1 t2)
H6: is_value (App t1 t2)exists t' : {bind term}, App t1 t2 = Lam t'obvious. } Qed.Gamma: tyenv
T1, T2: ty
t1, t2: term
H: jt Gamma (App t1 t2) (TyFun T1 T2)
T: ty
H0: jt Gamma t1 (TyFun T (TyFun T1 T2))
H1: jt Gamma t2 T
H5: closed (App t1 t2)
H6: is_value (App t1 t2)False
The progress theorem: a closed, well-typed term must either be able to make one step of reduction or be a value.
forall (Gamma : tyenv) (t : term) (T : ty), jt Gamma t T -> closed t -> (exists t' : term, cbv t t') \/ is_value tforall (Gamma : tyenv) (t : term) (T : ty), jt Gamma t T -> closed t -> (exists t' : term, cbv t t') \/ is_value t(* By induction on the type derivation. *)forall (Gamma : tyenv) (t : term) (T : ty), jt Gamma t T -> closed t -> (exists t' : term, cbv t t') \/ is_value t(* Case: JVar. *)Gamma: var -> ty
x: var
H0: closed (Var x)(exists t' : term, cbv (Var x) t') \/ is_value (Var x)Gamma: var -> ty
t: term
T, U: ty
H: jt (T .: Gamma) t U
IHjt: closed t -> (exists t' : term, cbv t t') \/ is_value t
H0: closed (Lam t)(exists t' : term, cbv (Lam t) t') \/ is_value (Lam t)Gamma: tyenv
t1, t2: term
T, U: ty
H: jt Gamma t1 (TyFun T U)
H0: jt Gamma t2 T
IHjt1: closed t1 -> (exists t' : term, cbv t1 t') \/ is_value t1
IHjt2: closed t2 -> (exists t' : term, cbv t2 t') \/ is_value t2
H1: closed (App t1 t2)(exists t' : term, cbv (App t1 t2) t') \/ is_value (App t1 t2)(* A variable does not reduce, so we must find a contradiction among our hypotheses. Here, the hypothesis that `t` is closed provides such a contradiction. (We could also exploit the fact that, according to our definition of `is_value`, a variable is a value, but it is preferable not to do so if we can avoid it.) *)Gamma: var -> ty
x: var
H0: closed (Var x)(exists t' : term, cbv (Var x) t') \/ is_value (Var x)eauto with closed.Gamma: var -> ty
x: var
H0: closed (Var x)False(* Case: JLam. *)Gamma: var -> ty
t: term
T, U: ty
H: jt (T .: Gamma) t U
IHjt: closed t -> (exists t' : term, cbv t t') \/ is_value t
H0: closed (Lam t)(exists t' : term, cbv (Lam t) t') \/ is_value (Lam t)Gamma: tyenv
t1, t2: term
T, U: ty
H: jt Gamma t1 (TyFun T U)
H0: jt Gamma t2 T
IHjt1: closed t1 -> (exists t' : term, cbv t1 t') \/ is_value t1
IHjt2: closed t2 -> (exists t' : term, cbv t2 t') \/ is_value t2
H1: closed (App t1 t2)(exists t' : term, cbv (App t1 t2) t') \/ is_value (App t1 t2)obvious.Gamma: var -> ty
t: term
T, U: ty
H: jt (T .: Gamma) t U
IHjt: closed t -> (exists t' : term, cbv t t') \/ is_value t
H0: closed (Lam t)(exists t' : term, cbv (Lam t) t') \/ is_value (Lam t)(* Case: JApp. *)Gamma: tyenv
t1, t2: term
T, U: ty
H: jt Gamma t1 (TyFun T U)
H0: jt Gamma t2 T
IHjt1: closed t1 -> (exists t' : term, cbv t1 t') \/ is_value t1
IHjt2: closed t2 -> (exists t' : term, cbv t2 t') \/ is_value t2
H1: closed (App t1 t2)(exists t' : term, cbv (App t1 t2) t') \/ is_value (App t1 t2)(* Apply the induction hypothesis to `t1`. If `t1` reduces, then obviously `App t1 t2` reduces as well, so we are finished. There remains to consider the case where `t1` is a value. *)Gamma: tyenv
t1, t2: term
T, U: ty
H: jt Gamma t1 (TyFun T U)
H0: jt Gamma t2 T
IHjt1: closed t1 -> (exists t' : term, cbv t1 t') \/ is_value t1
IHjt2: closed t2 -> (exists t' : term, cbv t2 t') \/ is_value t2
H1: closed (App t1 t2)(exists t' : term, cbv (App t1 t2) t') \/ is_value (App t1 t2)(* Reason in the same way about `t2`. *)Gamma: tyenv
t1, t2: term
T, U: ty
H: jt Gamma t1 (TyFun T U)
H0: jt Gamma t2 T
IHjt2: closed t2 -> (exists t' : term, cbv t2 t') \/ is_value t2
H1: closed (App t1 t2)
H2: is_value t1(exists t' : term, cbv (App t1 t2) t') \/ is_value (App t1 t2)(* We wish to prove that `App t1 t2` is a beta-redex. *)Gamma: tyenv
t1, t2: term
T, U: ty
H: jt Gamma t1 (TyFun T U)
H0: jt Gamma t2 T
H1: closed (App t1 t2)
H2: is_value t1
H3: is_value t2(exists t' : term, cbv (App t1 t2) t') \/ is_value (App t1 t2)(* Because `t1` is a closed value and has a function type, it must be a lambda-abstraction. *)Gamma: tyenv
t1, t2: term
T, U: ty
H: jt Gamma t1 (TyFun T U)
H0: jt Gamma t2 T
H1: closed (App t1 t2)
H2: is_value t1
H3: is_value t2exists t' : term, cbv (App t1 t2) t'Gamma: tyenv
t1, t2: term
T, U: ty
H: jt Gamma t1 (TyFun T U)
H0: jt Gamma t2 T
H1: closed (App t1 t2)
H2: is_value t1
H3: is_value t2
fact:= exists t' : {bind term}, t1 = Lam t': Propclosed t1Gamma: tyenv
t2: term
T, U: ty
x: {bind term}
H: jt Gamma (Lam x) (TyFun T U)
H0: jt Gamma t2 T
H2: is_value (Lam x)
H1: closed (App (Lam x) t2)
H3: is_value t2exists t' : term, cbv (App (Lam x) t2) t'eauto with closed.Gamma: tyenv
t1, t2: term
T, U: ty
H: jt Gamma t1 (TyFun T U)
H0: jt Gamma t2 T
H1: closed (App t1 t2)
H2: is_value t1
H3: is_value t2
fact:= exists t' : {bind term}, t1 = Lam t': Propclosed t1(* Therefore, we have a beta-redex. *) obvious. } Qed.Gamma: tyenv
t2: term
T, U: ty
x: {bind term}
H: jt Gamma (Lam x) (TyFun T U)
H0: jt Gamma t2 T
H2: is_value (Lam x)
H1: closed (App (Lam x) t2)
H3: is_value t2exists t' : term, cbv (App (Lam x) t2) t'