Require Import MyTactics. Require Import Sequences. Require Import LambdaCalculusSyntax. Require Import LambdaCalculusValues. Require Import LambdaCalculusReduction. Require Import SystemFDefinition. Require Import SystemFLemmas.
We begin with a direct attempt to establish type preservation (that is, subject reduction) for System F, and find that we need a key inversion lemma first.
forall (Gamma : tyenv) (t : term) (T : ty), jf Gamma t T -> forall t' : term, cbv t t' -> jf Gamma t' T(* By induction on the type derivation. *)forall (Gamma : tyenv) (t : term) (T : ty), jf Gamma t T -> forall t' : term, cbv t t' -> jf Gamma t' T(* JFApp *)Gamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv t1 t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
t': term
H1: cbv (App t1 t2) t'jf Gamma t' UGamma: var -> ty
t: term
T: ty
H: jf (Gamma >> ren (+1)) t T
IHjf: forall t' : term, cbv t t' -> jf (Gamma >> ren (+1)) t' T
t': term
H1: cbv t t'jf Gamma t' (TyAll T)Gamma: tyenv
t: term
T, U: {bind ty}
H: jf Gamma t (TyAll T)
IHjf: forall t' : term, cbv t t' -> jf Gamma t' (TyAll T)
t': term
H1: cbv t t'jf Gamma t' T.[U/]Gamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv t1 t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
t': term
H1: cbv (App t1 t2) t'jf Gamma t' U(* RedBetaV. A beta-redex, `App (Lam t) v`, reduces to `t.[v/]`. *)Gamma: tyenv
t2: term
T, U: ty
t: term
H: jf Gamma (Lam t) (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv (Lam t) t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
H4: cbv_mask RuleBetaV
H5: is_value t2jf Gamma t.[t2/] UGamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv t1 t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
t3: term
H4: cbv_mask RuleAppL
H6: cbv t1 t3jf Gamma (App t3 t2) UGamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv t1 t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
u2: term
H4: cbv_mask RuleAppVR
H5: is_value t1
H7: cbv t2 u2jf Gamma (App t1 u2) UGamma: tyenv
t2: term
T, U: ty
t: term
H: jf Gamma (Lam t) (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv (Lam t) t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
H4: cbv_mask RuleBetaV
H5: is_value t2jf Gamma t.[t2/] U(* This requires us to prove that the function body `t` is well-typed under an extended type environment `T .: Gamma`. An inversion lemma is needed. *) Abort.Gamma: tyenv
t2: term
T, U: ty
t: term
H: jf Gamma (Lam t) (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv (Lam t) t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
H4: cbv_mask RuleBetaV
H5: is_value t2jf (T .: Gamma) t U
We wish to establish an inversion lemma for the typing rule for lambda-abstractions.
A first version of the statement is as follows: if under Gamma
a
lambda-abstraction Lam t
has type TyFun T U
, then under the extended
environment T .: Gamma
, the term t
must have type U
. Let us try to prove
this:
forall (Gamma : tyenv) (t' : term) (T' : ty), jf Gamma t' T' -> forall (t : {bind term}) (T U : ty), t' = Lam t -> T' = TyFun T U -> jf (T .: Gamma) t Uforall (Gamma : tyenv) (t' : term) (T' : ty), jf Gamma t' T' -> forall (t : {bind term}) (T U : ty), t' = Lam t -> T' = TyFun T U -> jf (T .: Gamma) t U(* Case: JFLam. *)Gamma: var -> ty
t: term
T, U: ty
H: jf (T .: Gamma) t U
IHjf: forall (t0 : {bind term}) (T0 U0 : ty), t = Lam t0 -> U = TyFun T0 U0 -> jf (T0 .: T .: Gamma) t0 U0
t0: {bind term}
T0, U0: ty
H0: Lam t = Lam t0
H1: TyFun T U = TyFun T0 U0jf (T0 .: Gamma) t0 U0Gamma: tyenv
T, U: {bind ty}
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> TyAll T = TyFun T0 U -> jf (T0 .: Gamma) t U
H: jf Gamma (Lam t0) (TyAll T)
T0, U0: ty
H2: T.[U/] = TyFun T0 U0jf (T0 .: Gamma) t0 U0congruence.Gamma: var -> ty
t: term
T, U: ty
H: jf (T .: Gamma) t U
IHjf: forall (t0 : {bind term}) (T0 U0 : ty), t = Lam t0 -> U = TyFun T0 U0 -> jf (T0 .: T .: Gamma) t0 U0
t0: {bind term}
T0, U0: ty
H0: Lam t = Lam t0
H1: TyFun T U = TyFun T0 U0jf (T0 .: Gamma) t0 U0(* Case: JFTyApp. *)Gamma: tyenv
T, U: {bind ty}
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> TyAll T = TyFun T0 U -> jf (T0 .: Gamma) t U
H: jf Gamma (Lam t0) (TyAll T)
T0, U0: ty
H2: T.[U/] = TyFun T0 U0jf (T0 .: Gamma) t0 U0(* The induction hypothesis has the unsatisfiable requirement `TyAll _ = TyFun _ _`. *)Gamma: tyenv
T, U: {bind ty}
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> TyAll T = TyFun T0 U -> jf (T0 .: Gamma) t U
H: jf Gamma (Lam t0) (TyAll T)
T0, U0: ty
H2: T.[U/] = TyFun T0 U0jf (T0 .: Gamma) t0 U0(* We are stuck. *) Abort.Gamma: tyenv
T, U: {bind ty}
t0: {bind term}
H: jf Gamma (Lam t0) (TyAll T)
T0, U0: ty
H2: T.[U/] = TyFun T0 U0jf (T0 .: Gamma) t0 U0
The previous attempt fails, because the statement is not general enough. We
cannot restrict our attention to the situation where the term Lam t
has a
function type. We must also reason about the situations where it has a
polymorphic type that can be instantiated to a function type.
Thus, we propose a more general statement, where Lam t
has type T'
and
T'
can be weakened (via a subsumption relation) to TyFun T U
.
This relation is defined by just one rule: the type TyAll T
is a subtype of
the type T.[U/]
. When necessary, we will use the reflexive transitive
closure of this relation, [star sub], so as to allow for a sequence of
subtyping steps.
Inductive sub : ty -> ty -> Prop :=
| Sub:
forall T T' U,
T' = T.[U/] ->
sub (TyAll T) T'.
Here is a second attempt at the inversion lemma for lambda-abstractions.
Instead of requiring an equality between T'
and TyFun T U
, we allow
a sequence of subsumption steps. Thus, this statement is stronger.
forall (Gamma : tyenv) (t' : term) (T' : ty), jf Gamma t' T' -> forall (t : {bind term}) (T U : ty), t' = Lam t -> star sub T' (TyFun T U) -> jf (T .: Gamma) t Uforall (Gamma : tyenv) (t' : term) (T' : ty), jf Gamma t' T' -> forall (t : {bind term}) (T U : ty), t' = Lam t -> star sub T' (TyFun T U) -> jf (T .: Gamma) t U(* This time, we have three subgoals instead of two. *)Gamma: var -> ty
t: term
T, U: ty
H: jf (T .: Gamma) t U
IHjf: forall (t0 : {bind term}) (T0 U0 : ty), t = Lam t0 -> star sub U (TyFun T0 U0) -> jf (T0 .: T .: Gamma) t0 U0
t0: {bind term}
T0, U0: ty
H0: Lam t = Lam t0
H1: star sub (TyFun T U) (TyFun T0 U0)jf (T0 .: Gamma) t0 U0Gamma: var -> ty
T: ty
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub T (TyFun T0 U) -> jf (T0 .: Gamma >> ren (+1)) t U
H: jf (Gamma >> ren (+1)) (Lam t0) T
T0, U: ty
H2: star sub (TyAll T) (TyFun T0 U)jf (T0 .: Gamma) t0 UGamma: tyenv
T, U: {bind ty}
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub (TyAll T) (TyFun T0 U) -> jf (T0 .: Gamma) t U
H: jf Gamma (Lam t0) (TyAll T)
T0, U0: ty
H2: star sub T.[U/] (TyFun T0 U0)jf (T0 .: Gamma) t0 U0(* Case: JFLam. *)Gamma: var -> ty
t: term
T, U: ty
H: jf (T .: Gamma) t U
IHjf: forall (t0 : {bind term}) (T0 U0 : ty), t = Lam t0 -> star sub U (TyFun T0 U0) -> jf (T0 .: T .: Gamma) t0 U0
t0: {bind term}
T0, U0: ty
H0: Lam t = Lam t0
H1: star sub (TyFun T U) (TyFun T0 U0)jf (T0 .: Gamma) t0 U0Gamma: tyenv
T, U: {bind ty}
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub (TyAll T) (TyFun T0 U) -> jf (T0 .: Gamma) t U
H: jf Gamma (Lam t0) (TyAll T)
T0, U0: ty
H2: star sub T.[U/] (TyFun T0 U0)jf (T0 .: Gamma) t0 U0Gamma: var -> ty
T: ty
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub T (TyFun T0 U) -> jf (T0 .: Gamma >> ren (+1)) t U
H: jf (Gamma >> ren (+1)) (Lam t0) T
T0, U: ty
H2: star sub (TyAll T) (TyFun T0 U)jf (T0 .: Gamma) t0 U(* We have a hypothesis `star sub (TyFun T' U') (TyFun T U)`. Considering the definition of the relation `sub`, this must be a sequence of zero subtyping steps, so we must have `T' = T` and `U' = U`. To let Coq see this, it suffices to perform case analysis. (One could also make it a separate lemma, for clarity.) *)Gamma: var -> ty
t: term
T, U: ty
H: jf (T .: Gamma) t U
IHjf: forall (t0 : {bind term}) (T0 U0 : ty), t = Lam t0 -> star sub U (TyFun T0 U0) -> jf (T0 .: T .: Gamma) t0 U0
t0: {bind term}
T0, U0: ty
H0: Lam t = Lam t0
H1: star sub (TyFun T U) (TyFun T0 U0)jf (T0 .: Gamma) t0 U0(* The result is then immediate. *) congruence.Gamma: var -> ty
t: term
T0, U0: ty
H: jf (T0 .: Gamma) t U0
IHjf: forall (t0 : {bind term}) (T U : ty), t = Lam t0 -> star sub U0 (TyFun T U) -> jf (T .: T0 .: Gamma) t0 U
t0: {bind term}
H0: Lam t = Lam t0jf (T0 .: Gamma) t0 U0(* Case: JFTyApp. *)Gamma: tyenv
T, U: {bind ty}
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub (TyAll T) (TyFun T0 U) -> jf (T0 .: Gamma) t U
H: jf Gamma (Lam t0) (TyAll T)
T0, U0: ty
H2: star sub T.[U/] (TyFun T0 U0)jf (T0 .: Gamma) t0 U0Gamma: var -> ty
T: ty
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub T (TyFun T0 U) -> jf (T0 .: Gamma >> ren (+1)) t U
H: jf (Gamma >> ren (+1)) (Lam t0) T
T0, U: ty
H2: star sub (TyAll T) (TyFun T0 U)jf (T0 .: Gamma) t0 U(* In that case, it suffices to invoke the induction hypothesis. The subtyping sequence `star sub ...` grows by one, as one more step is prepended to it. This is precisely the reason why the lemma was formulated in this general form. *)Gamma: tyenv
T, U: {bind ty}
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub (TyAll T) (TyFun T0 U) -> jf (T0 .: Gamma) t U
H: jf Gamma (Lam t0) (TyAll T)
T0, U0: ty
H2: star sub T.[U/] (TyFun T0 U0)jf (T0 .: Gamma) t0 U0Gamma: tyenv
T, U: {bind ty}
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub (TyAll T) (TyFun T0 U) -> jf (T0 .: Gamma) t U
H: jf Gamma (Lam t0) (TyAll T)
T0, U0: ty
H2: star sub T.[U/] (TyFun T0 U0)Lam t0 = Lam t0Gamma: tyenv
T, U: {bind ty}
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub (TyAll T) (TyFun T0 U) -> jf (T0 .: Gamma) t U
H: jf Gamma (Lam t0) (TyAll T)
T0, U0: ty
H2: star sub T.[U/] (TyFun T0 U0)star sub (TyAll T) (TyFun T0 U0)eauto.Gamma: tyenv
T, U: {bind ty}
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub (TyAll T) (TyFun T0 U) -> jf (T0 .: Gamma) t U
H: jf Gamma (Lam t0) (TyAll T)
T0, U0: ty
H2: star sub T.[U/] (TyFun T0 U0)Lam t0 = Lam t0Gamma: tyenv
T, U: {bind ty}
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub (TyAll T) (TyFun T0 U) -> jf (T0 .: Gamma) t U
H: jf Gamma (Lam t0) (TyAll T)
T0, U0: ty
H2: star sub T.[U/] (TyFun T0 U0)star sub (TyAll T) (TyFun T0 U0)eauto using sub with sequences. }Gamma: tyenv
T, U: {bind ty}
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub (TyAll T) (TyFun T0 U) -> jf (T0 .: Gamma) t U
H: jf Gamma (Lam t0) (TyAll T)
T0, U0: ty
H2: star sub T.[U/] (TyFun T0 U0)star sub (TyAll T) (TyFun T0 U0)(* Case: JTyAbs. *)Gamma: var -> ty
T: ty
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub T (TyFun T0 U) -> jf (T0 .: Gamma >> ren (+1)) t U
H: jf (Gamma >> ren (+1)) (Lam t0) T
T0, U: ty
H2: star sub (TyAll T) (TyFun T0 U)jf (T0 .: Gamma) t0 U(* We have a hypothesis `star sub (TyAll T') (TyFun T U)`. Considering the definition of the relation `sub`, this must be a sequence of at least one subtyping step. To let Coq see this, we again perform case analysis. *)Gamma: var -> ty
T: ty
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub T (TyFun T0 U) -> jf (T0 .: Gamma >> ren (+1)) t U
H: jf (Gamma >> ren (+1)) (Lam t0) T
T0, U: ty
H2: star sub (TyAll T) (TyFun T0 U)jf (T0 .: Gamma) t0 UGamma: var -> ty
T: ty
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub T (TyFun T0 U) -> jf (T0 .: Gamma >> ren (+1)) t U
H: jf (Gamma >> ren (+1)) (Lam t0) T
T0, U, b: ty
H0: sub (TyAll T) b
H1: star sub b (TyFun T0 U)jf (T0 .: Gamma) t0 U(* Thus, we have one subtyping step from `TyAll T'` to `T'.[U'/]`, and from there, the rest of the subtyping sequence leads to `TyFun T U`. *) (* We are looking at a type abstraction. The term `Lam t` is polymorphic: the hypothesis `jf (Gamma >> ren (+1)) (Lam t) T'` shows that the term `Lam t` has been type-checked in the presence of a new type variable numbered 0. The idea is to instantiate this type variable with the type `U'` so as to obtain `jf Gamma (Lam t) T'.[U'/]`. Then, we hope to be able to exploit the induction hypothesis. Let's try: *)Gamma: var -> ty
T: ty
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub T (TyFun T0 U) -> jf (T0 .: Gamma >> ren (+1)) t U
H: jf (Gamma >> ren (+1)) (Lam t0) T
T0, U: ty
U0: {bind ty}
H1: star sub T.[U0/] (TyFun T0 U)jf (T0 .: Gamma) t0 U(* The first step has worked: we have `jf Gamma (Lam t) T'.[U'/]`. Unfortunately, this new judgement, which has been produced by the lemma [jf_ty_substitution_0], is not a child of the typing judgement over which we are performing structural induction. Thus, there is no induction hypothesis for it. We are stuck. *) Abort.Gamma: var -> ty
T: ty
t0: {bind term}
IHjf: forall (t : {bind term}) (T0 U : ty), Lam t0 = Lam t -> star sub T (TyFun T0 U) -> jf (T0 .: Gamma >> ren (+1)) t U
H: jf (Gamma >> ren (+1)) (Lam t0) T
T0, U: ty
U0: {bind ty}
H1: star sub T.[U0/] (TyFun T0 U)
H0: jf Gamma (Lam t0) T.[?Goal/]jf (T0 .: Gamma) t0 U
If we had an explicit syntax for type abstractions and type applications, we would see that what we are doing in the previous proof attempt is to reduce a type redex (that is, a type application of a type abstraction). The difficulty that we are hitting is to prove that this process must terminate.
The intuitive reason why it must terminate is that a type derivation for
the term Lam t
must end with a finite number of uses of the typing
rules JFTyAbs
and JFTyApp
, and our proof peels them away one by one.
Crucially, we must argue that our use of the type substitution lemma
jf_ty_substitution_0
preserves the structure of the derivation, so
does not increase the number of uses of JFTyAbs
and JFTyApp
.
To do this, we introduce an auxiliary typing judgment, jtn
. (See
SystemFLemmas.) This judgement is parameterized with an integer n
that
counts the number of uses of JFTyAbs
and JFTyApp
at the root of a type
derivation. This allows us to prove the lemma invert_jtn_Lam_TyFun
by
induction on n
.
We show that the judgements jtn
and jf
are equivalent, that is, jf
can be viewed as a version of jtn
where the parameter n
is ignored.
(See SystemFLemmas.) Thus, we can reason in terms of jtn
where
necessary, and use the simpler judgement jf
elsewhere.
forall (n : nat) (Gamma : tyenv) (t : {bind term}) (T' T U : ty), jtn n Gamma (Lam t) T' -> star sub T' (TyFun T U) -> jt (T .: Gamma) t U(* By induction on `n`, and by case analysis on the typing judgement. *)forall (n : nat) (Gamma : tyenv) (t : {bind term}) (T' T U : ty), jtn n Gamma (Lam t) T' -> star sub T' (TyFun T U) -> jt (T .: Gamma) t U(* Case: `n` is 0. The type derivation must end with `JTNLam`. *)Gamma: tyenv
t: {bind term}
T, U, T0, U0: ty
H: jtn 0 Gamma (Lam t) (TyFun T0 U0)
n: nat
H1: jtn n (T0 .: Gamma) t U0
H3: star sub (TyFun T0 U0) (TyFun T U)jt (T .: Gamma) t Un: nat
IHn: forall (Gamma : tyenv) (t : {bind term}) (T' T U : ty), jtn n Gamma (Lam t) T' -> star sub T' (TyFun T U) -> jt (T .: Gamma) t U
Gamma: tyenv
t: {bind term}
T, U, T0: ty
H: jtn (S n) Gamma (Lam t) (TyAll T0)
H1: jtn n (Gamma >> ren (+1)) (Lam t) T0
H6: star sub (TyAll T0) (TyFun T U)jt (T .: Gamma) t Un: nat
IHn: forall (Gamma : tyenv) (t : {bind term}) (T' T U : ty), jtn n Gamma (Lam t) T' -> star sub T' (TyFun T U) -> jt (T .: Gamma) t U
Gamma: tyenv
t: {bind term}
T, U: ty
T0, U0: {bind ty}
H: jtn (S n) Gamma (Lam t) T0.[U0/]
H1: jtn n Gamma (Lam t) (TyAll T0)
H6: star sub T0.[U0/] (TyFun T U)jt (T .: Gamma) t U(* We have a hypothesis `star sub (TyFun T' U') (TyFun T U)`. Considering the definition of the relation `sub`, this must be a sequence of zero subtyping steps, so we must have `T' = T` and `U' = U`. To let Coq see this, it suffices to perform case analysis. (One could also make it a separate lemma, for clarity.) *)Gamma: tyenv
t: {bind term}
T, U, T0, U0: ty
H: jtn 0 Gamma (Lam t) (TyFun T0 U0)
n: nat
H1: jtn n (T0 .: Gamma) t U0
H3: star sub (TyFun T0 U0) (TyFun T U)jt (T .: Gamma) t U(* The result is then immediate. *) eauto with jt.Gamma: tyenv
t: {bind term}
T, U: ty
H: jtn 0 Gamma (Lam t) (TyFun T U)
n: nat
H1: jtn n (T .: Gamma) t Ujt (T .: Gamma) t U(* Case: `n` is `S m`. The type derivation ends with `JTNTyAbs`. *)n: nat
IHn: forall (Gamma : tyenv) (t : {bind term}) (T' T U : ty), jtn n Gamma (Lam t) T' -> star sub T' (TyFun T U) -> jt (T .: Gamma) t U
Gamma: tyenv
t: {bind term}
T, U, T0: ty
H: jtn (S n) Gamma (Lam t) (TyAll T0)
H1: jtn n (Gamma >> ren (+1)) (Lam t) T0
H6: star sub (TyAll T0) (TyFun T U)jt (T .: Gamma) t Un: nat
IHn: forall (Gamma : tyenv) (t : {bind term}) (T' T U : ty), jtn n Gamma (Lam t) T' -> star sub T' (TyFun T U) -> jt (T .: Gamma) t U
Gamma: tyenv
t: {bind term}
T, U: ty
T0, U0: {bind ty}
H: jtn (S n) Gamma (Lam t) T0.[U0/]
H1: jtn n Gamma (Lam t) (TyAll T0)
H6: star sub T0.[U0/] (TyFun T U)jt (T .: Gamma) t U(* We have a hypothesis `star sub (TyAll T') (TyFun T U)`. Considering the definition of the relation `sub`, this must be a sequence of at least one subtyping step. To let Coq see this, we again perform case analysis. *)n: nat
IHn: forall (Gamma : tyenv) (t : {bind term}) (T' T U : ty), jtn n Gamma (Lam t) T' -> star sub T' (TyFun T U) -> jt (T .: Gamma) t U
Gamma: tyenv
t: {bind term}
T, U, T0: ty
H: jtn (S n) Gamma (Lam t) (TyAll T0)
H1: jtn n (Gamma >> ren (+1)) (Lam t) T0
H6: star sub (TyAll T0) (TyFun T U)jt (T .: Gamma) t Un: nat
IHn: forall (Gamma : tyenv) (t : {bind term}) (T' T U : ty), jtn n Gamma (Lam t) T' -> star sub T' (TyFun T U) -> jt (T .: Gamma) t U
Gamma: tyenv
t: {bind term}
T, U, T0: ty
H: jtn (S n) Gamma (Lam t) (TyAll T0)
H1: jtn n (Gamma >> ren (+1)) (Lam t) T0
b: ty
H0: sub (TyAll T0) b
H2: star sub b (TyFun T U)jt (T .: Gamma) t U(* Thus, we have one subtyping step from `TyAll T'` to `T'.[U'/]`, and from there, the rest of the subtyping sequence leads to `TyFun T U`. We are looking at a type abstraction: the idea is to instantiate this abstraction by substituting the type `U'` for the type variable `0`, and then to use the induction hypothesis. (This exploits the fact that `jtn_ty_substitution` preserves the size of the type derivation.) We express this idea, in backward style, by instructing Coq that the proof ends with an application of the induction hypothesis: *)n: nat
IHn: forall (Gamma : tyenv) (t : {bind term}) (T' T U : ty), jtn n Gamma (Lam t) T' -> star sub T' (TyFun T U) -> jt (T .: Gamma) t U
Gamma: tyenv
t: {bind term}
T, U, T0: ty
H: jtn (S n) Gamma (Lam t) (TyAll T0)
H1: jtn n (Gamma >> ren (+1)) (Lam t) T0
U0: {bind ty}
H2: star sub T0.[U0/] (TyFun T U)jt (T .: Gamma) t U(* The goal is now to prove that `Lam t` has type `T'.[U'/]` under `Gamma`. We know that it has type `TyAll T'` under `Gamma >> ren (+1)`, so this is exactly the type substitution lemma. *) eauto using jtn_ty_substitution_0.n: nat
IHn: forall (Gamma : tyenv) (t : {bind term}) (T' T U : ty), jtn n Gamma (Lam t) T' -> star sub T' (TyFun T U) -> jt (T .: Gamma) t U
Gamma: tyenv
t: {bind term}
T, U, T0: ty
H: jtn (S n) Gamma (Lam t) (TyAll T0)
H1: jtn n (Gamma >> ren (+1)) (Lam t) T0
U0: {bind ty}
H2: star sub T0.[U0/] (TyFun T U)jtn n Gamma (Lam t) T0.[U0/](* Case: `n` is `S m`. The type derivation ends with `JTNApp`. *)n: nat
IHn: forall (Gamma : tyenv) (t : {bind term}) (T' T U : ty), jtn n Gamma (Lam t) T' -> star sub T' (TyFun T U) -> jt (T .: Gamma) t U
Gamma: tyenv
t: {bind term}
T, U: ty
T0, U0: {bind ty}
H: jtn (S n) Gamma (Lam t) T0.[U0/]
H1: jtn n Gamma (Lam t) (TyAll T0)
H6: star sub T0.[U0/] (TyFun T U)jt (T .: Gamma) t U(* In that case, it suffices to invoke the induction hypothesis. The subtyping sequence `star sub ...` grows by one, as one more step is prepended to it. This is precisely the reason why the lemma was formulated in this general form. *) eapply IHn; eauto using sub with sequences. } Qed.n: nat
IHn: forall (Gamma : tyenv) (t : {bind term}) (T' T U : ty), jtn n Gamma (Lam t) T' -> star sub T' (TyFun T U) -> jt (T .: Gamma) t U
Gamma: tyenv
t: {bind term}
T, U: ty
T0, U0: {bind ty}
H: jtn (S n) Gamma (Lam t) T0.[U0/]
H1: jtn n Gamma (Lam t) (TyAll T0)
H6: star sub T0.[U0/] (TyFun T U)jt (T .: Gamma) t U
The inversion lemma can be reformulated in terms of jf
.
forall (Gamma : tyenv) (t : {bind term}) (T U : ty), jf Gamma (Lam t) (TyFun T U) -> jf (T .: Gamma) t Uforall (Gamma : tyenv) (t : {bind term}) (T U : ty), jf Gamma (Lam t) (TyFun T U) -> jf (T .: Gamma) t UGamma: tyenv
t: {bind term}
T, U: ty
H: jf Gamma (Lam t) (TyFun T U)jf (T .: Gamma) t UGamma: tyenv
t: {bind term}
T, U: ty
H: jf Gamma (Lam t) (TyFun T U)
H0: jt Gamma (Lam t) (TyFun T U)jf (T .: Gamma) t UGamma: tyenv
t: {bind term}
T, U: ty
H: jf Gamma (Lam t) (TyFun T U)
H0: exists n : nat, jtn n Gamma (Lam t) (TyFun T U)jf (T .: Gamma) t UGamma: tyenv
t: {bind term}
T, U: ty
H: jf Gamma (Lam t) (TyFun T U)
x: nat
H0: jtn x Gamma (Lam t) (TyFun T U)jf (T .: Gamma) t UGamma: tyenv
t: {bind term}
T, U: ty
H: jf Gamma (Lam t) (TyFun T U)
x: nat
H0: jtn x Gamma (Lam t) (TyFun T U)
fact:= jt (?Goal .: Gamma) t ?Goal0: Propstar sub (TyFun T U) (TyFun ?Goal ?Goal0)Gamma: tyenv
t: {bind term}
T, U: ty
H: jf Gamma (Lam t) (TyFun T U)
x: nat
H0: jtn x Gamma (Lam t) (TyFun T U)
H1: jt (?Goal .: Gamma) t ?Goal0jf (T .: Gamma) t Ueauto with sequences.Gamma: tyenv
t: {bind term}
T, U: ty
H: jf Gamma (Lam t) (TyFun T U)
x: nat
H0: jtn x Gamma (Lam t) (TyFun T U)
fact:= jt (?Goal .: Gamma) t ?Goal0: Propstar sub (TyFun T U) (TyFun ?Goal ?Goal0)eauto using jt_jf. Qed.Gamma: tyenv
t: {bind term}
T, U: ty
H: jf Gamma (Lam t) (TyFun T U)
x: nat
H0: jtn x Gamma (Lam t) (TyFun T U)
H1: jt (T .: Gamma) t Ujf (T .: Gamma) t U
The typing judgement is preserved by one step of reduction.
forall (Gamma : tyenv) (t : term) (T : ty), jf Gamma t T -> forall t' : term, cbv t t' -> jf Gamma t' T(* By induction on the type derivation. *)forall (Gamma : tyenv) (t : term) (T : ty), jf Gamma t T -> forall t' : term, cbv t t' -> jf Gamma t' T(* JFApp *)Gamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv t1 t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
t': term
H1: cbv (App t1 t2) t'jf Gamma t' UGamma: var -> ty
t: term
T: ty
H: jf (Gamma >> ren (+1)) t T
IHjf: forall t' : term, cbv t t' -> jf (Gamma >> ren (+1)) t' T
t': term
H1: cbv t t'jf Gamma t' (TyAll T)Gamma: tyenv
t: term
T, U: {bind ty}
H: jf Gamma t (TyAll T)
IHjf: forall t' : term, cbv t t' -> jf Gamma t' (TyAll T)
t': term
H1: cbv t t'jf Gamma t' T.[U/]Gamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv t1 t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
t': term
H1: cbv (App t1 t2) t'jf Gamma t' U(* RedBetaV. A beta-redex, `App (Lam t) v`, reduces to `t.[v/]`. *)Gamma: tyenv
t2: term
T, U: ty
t: term
H: jf Gamma (Lam t) (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv (Lam t) t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
H4: cbv_mask RuleBetaV
H5: is_value t2jf Gamma t.[t2/] UGamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv t1 t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
t3: term
H4: cbv_mask RuleAppL
H6: cbv t1 t3jf Gamma (App t3 t2) UGamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv t1 t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
u2: term
H4: cbv_mask RuleAppVR
H5: is_value t1
H7: cbv t2 u2jf Gamma (App t1 u2) UGamma: tyenv
t2: term
T, U: ty
t: term
H: jf Gamma (Lam t) (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv (Lam t) t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
H4: cbv_mask RuleBetaV
H5: is_value t2jf Gamma t.[t2/] U(* This requires us to prove that the function body `t` is well-typed under an extended type environment `T .: Gamma`. Fortunately, this is guaranteed by the inversion lemma `invert_jf_Lam_TyFun`. *) eapply invert_jf_Lam_TyFun; eauto with sequences.Gamma: tyenv
t2: term
T, U: ty
t: term
H: jf Gamma (Lam t) (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv (Lam t) t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
H4: cbv_mask RuleBetaV
H5: is_value t2jf (T .: Gamma) t U(* RedAppL. *)Gamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv t1 t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
t3: term
H4: cbv_mask RuleAppL
H6: cbv t1 t3jf Gamma (App t3 t2) UGamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv t1 t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
u2: term
H4: cbv_mask RuleAppVR
H5: is_value t1
H7: cbv t2 u2jf Gamma (App t1 u2) Ueauto with jf.Gamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv t1 t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
t3: term
H4: cbv_mask RuleAppL
H6: cbv t1 t3jf Gamma (App t3 t2) U(* RedAppVR. *)Gamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv t1 t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
u2: term
H4: cbv_mask RuleAppVR
H5: is_value t1
H7: cbv t2 u2jf Gamma (App t1 u2) Ueauto with jf. }Gamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: forall t' : term, cbv t1 t' -> jf Gamma t' (TyFun T U)
IHjf2: forall t' : term, cbv t2 t' -> jf Gamma t' T
u2: term
H4: cbv_mask RuleAppVR
H5: is_value t1
H7: cbv t2 u2jf Gamma (App t1 u2) U(* JTNTyAbs *)Gamma: var -> ty
t: term
T: ty
H: jf (Gamma >> ren (+1)) t T
IHjf: forall t' : term, cbv t t' -> jf (Gamma >> ren (+1)) t' T
t': term
H1: cbv t t'jf Gamma t' (TyAll T)Gamma: tyenv
t: term
T, U: {bind ty}
H: jf Gamma t (TyAll T)
IHjf: forall t' : term, cbv t t' -> jf Gamma t' (TyAll T)
t': term
H1: cbv t t'jf Gamma t' T.[U/]eauto with jf.Gamma: var -> ty
t: term
T: ty
H: jf (Gamma >> ren (+1)) t T
IHjf: forall t' : term, cbv t t' -> jf (Gamma >> ren (+1)) t' T
t': term
H1: cbv t t'jf Gamma t' (TyAll T)(* JTNTyApp *)Gamma: tyenv
t: term
T, U: {bind ty}
H: jf Gamma t (TyAll T)
IHjf: forall t' : term, cbv t t' -> jf Gamma t' (TyAll T)
t': term
H1: cbv t t'jf Gamma t' T.[U/]eauto with jf. } Qed.Gamma: tyenv
t: term
T, U: {bind ty}
H: jf Gamma t (TyAll T)
IHjf: forall t' : term, cbv t t' -> jf Gamma t' (TyAll T)
t': term
H1: cbv t t'jf Gamma t' T.[U/]
An inversion lemma: if a closed value admits a function type TyFun T1 T2
,
then it must be a lambda-abstraction.
forall (n : nat) (Gamma : tyenv) (t : term) (T : ty), jtn n Gamma t T -> forall T1 T2 : ty, star sub T (TyFun T1 T2) -> closed t -> is_value t -> exists t' : {bind term}, t = Lam t'(* We do not comment this proof in detail. It is analogous in its general structure to the proof of `invert_jtn_Lam_TyFun`. *)forall (n : nat) (Gamma : tyenv) (t : term) (T : ty), jtn n Gamma t T -> forall T1 T2 : ty, star sub T (TyFun T1 T2) -> closed t -> is_value t -> exists t' : {bind term}, t = Lam t'(* Case: JTNLam. *)Gamma: tyenv
t0: term
T0, U: ty
H: jtn 0 Gamma (Lam t0) (TyFun T0 U)
n: nat
H0: jtn n (T0 .: Gamma) t0 U
T1, T2: ty
H1: star sub (TyFun T0 U) (TyFun T1 T2)
H5: closed (Lam t0)
H6: is_value (Lam t0)exists t' : {bind term}, Lam t0 = Lam t'n: nat
IHn: forall (Gamma : tyenv) (t : term) (T : ty), jtn n Gamma t T -> forall T1 T2 : ty, star sub T (TyFun T1 T2) -> closed t -> is_value t -> exists t' : {bind term}, t = Lam t'
Gamma: tyenv
t: term
T0: ty
H: jtn (S n) Gamma t (TyAll T0)
H1: jtn n (Gamma >> ren (+1)) t T0
T1, T2: ty
H6: star sub (TyAll T0) (TyFun T1 T2)
H7: closed t
H8: is_value texists t' : {bind term}, t = Lam t'n: nat
IHn: forall (Gamma : tyenv) (t : term) (T : ty), jtn n Gamma t T -> forall T1 T2 : ty, star sub T (TyFun T1 T2) -> closed t -> is_value t -> exists t' : {bind term}, t = Lam t'
Gamma: tyenv
t: term
T0, U: {bind ty}
H: jtn (S n) Gamma t T0.[U/]
H1: jtn n Gamma t (TyAll T0)
T1, T2: ty
H6: star sub T0.[U/] (TyFun T1 T2)
H7: closed t
H8: is_value texists t' : {bind term}, t = Lam t'eauto.Gamma: tyenv
t0: term
T0, U: ty
H: jtn 0 Gamma (Lam t0) (TyFun T0 U)
n: nat
H0: jtn n (T0 .: Gamma) t0 U
T1, T2: ty
H1: star sub (TyFun T0 U) (TyFun T1 T2)
H5: closed (Lam t0)
H6: is_value (Lam t0)exists t' : {bind term}, Lam t0 = Lam t'(* Case: JTNTyAbs. *)n: nat
IHn: forall (Gamma : tyenv) (t : term) (T : ty), jtn n Gamma t T -> forall T1 T2 : ty, star sub T (TyFun T1 T2) -> closed t -> is_value t -> exists t' : {bind term}, t = Lam t'
Gamma: tyenv
t: term
T0: ty
H: jtn (S n) Gamma t (TyAll T0)
H1: jtn n (Gamma >> ren (+1)) t T0
T1, T2: ty
H6: star sub (TyAll T0) (TyFun T1 T2)
H7: closed t
H8: is_value texists t' : {bind term}, t = Lam t'n: nat
IHn: forall (Gamma : tyenv) (t : term) (T : ty), jtn n Gamma t T -> forall T1 T2 : ty, star sub T (TyFun T1 T2) -> closed t -> is_value t -> exists t' : {bind term}, t = Lam t'
Gamma: tyenv
t: term
T0, U: {bind ty}
H: jtn (S n) Gamma t T0.[U/]
H1: jtn n Gamma t (TyAll T0)
T1, T2: ty
H6: star sub T0.[U/] (TyFun T1 T2)
H7: closed t
H8: is_value texists t' : {bind term}, t = Lam t'n: nat
IHn: forall (Gamma : tyenv) (t : term) (T : ty), jtn n Gamma t T -> forall T1 T2 : ty, star sub T (TyFun T1 T2) -> closed t -> is_value t -> exists t' : {bind term}, t = Lam t'
Gamma: tyenv
t: term
T0: ty
H: jtn (S n) Gamma t (TyAll T0)
H1: jtn n (Gamma >> ren (+1)) t T0
T1, T2: ty
H6: star sub (TyAll T0) (TyFun T1 T2)
H7: closed t
H8: is_value texists t' : {bind term}, t = Lam t'n: nat
IHn: forall (Gamma : tyenv) (t : term) (T : ty), jtn n Gamma t T -> forall T1 T2 : ty, star sub T (TyFun T1 T2) -> closed t -> is_value t -> exists t' : {bind term}, t = Lam t'
Gamma: tyenv
t: term
T0: ty
H: jtn (S n) Gamma t (TyAll T0)
H1: jtn n (Gamma >> ren (+1)) t T0
T1, T2: ty
H7: closed t
H8: is_value t
b: ty
H0: sub (TyAll T0) b
H2: star sub b (TyFun T1 T2)exists t' : {bind term}, t = Lam t'n: nat
IHn: forall (Gamma : tyenv) (t : term) (T : ty), jtn n Gamma t T -> forall T1 T2 : ty, star sub T (TyFun T1 T2) -> closed t -> is_value t -> exists t' : {bind term}, t = Lam t'
Gamma: tyenv
t: term
T0: ty
H: jtn (S n) Gamma t (TyAll T0)
H1: jtn n (Gamma >> ren (+1)) t T0
T1, T2: ty
H7: closed t
H8: is_value t
U: {bind ty}
H2: star sub T0.[U/] (TyFun T1 T2)exists t' : {bind term}, t = Lam t'eauto using jtn_ty_substitution_0.n: nat
IHn: forall (Gamma : tyenv) (t : term) (T : ty), jtn n Gamma t T -> forall T1 T2 : ty, star sub T (TyFun T1 T2) -> closed t -> is_value t -> exists t' : {bind term}, t = Lam t'
Gamma: tyenv
t: term
T0: ty
H: jtn (S n) Gamma t (TyAll T0)
H1: jtn n (Gamma >> ren (+1)) t T0
T1, T2: ty
H7: closed t
H8: is_value t
U: {bind ty}
H2: star sub T0.[U/] (TyFun T1 T2)jtn n ?Gamma t T0.[U/](* Case: JTNTyApp. *)n: nat
IHn: forall (Gamma : tyenv) (t : term) (T : ty), jtn n Gamma t T -> forall T1 T2 : ty, star sub T (TyFun T1 T2) -> closed t -> is_value t -> exists t' : {bind term}, t = Lam t'
Gamma: tyenv
t: term
T0, U: {bind ty}
H: jtn (S n) Gamma t T0.[U/]
H1: jtn n Gamma t (TyAll T0)
T1, T2: ty
H6: star sub T0.[U/] (TyFun T1 T2)
H7: closed t
H8: is_value texists t' : {bind term}, t = Lam t'eauto using sub with sequences. } Qed.n: nat
IHn: forall (Gamma : tyenv) (t : term) (T : ty), jtn n Gamma t T -> forall T1 T2 : ty, star sub T (TyFun T1 T2) -> closed t -> is_value t -> exists t' : {bind term}, t = Lam t'
Gamma: tyenv
t: term
T0, U: {bind ty}
H: jtn (S n) Gamma t T0.[U/]
H1: jtn n Gamma t (TyAll T0)
T1, T2: ty
H6: star sub T0.[U/] (TyFun T1 T2)
H7: closed t
H8: is_value texists t' : {bind term}, t = Lam t'forall (Gamma : tyenv) (t : term) (T1 T2 : ty), jf Gamma t (TyFun T1 T2) -> closed t -> is_value t -> exists t' : {bind term}, t = Lam t'forall (Gamma : tyenv) (t : term) (T1 T2 : ty), jf Gamma t (TyFun T1 T2) -> closed t -> is_value t -> exists t' : {bind term}, t = Lam t'Gamma: tyenv
t: term
T1, T2: ty
H: jf Gamma t (TyFun T1 T2)
H0: closed t
H1: is_value texists t' : {bind term}, t = Lam t'Gamma: tyenv
t: term
T1, T2: ty
H: jf Gamma t (TyFun T1 T2)
H0: closed t
H1: is_value t
H2: jt Gamma t (TyFun T1 T2)exists t' : {bind term}, t = Lam t'Gamma: tyenv
t: term
T1, T2: ty
H: jf Gamma t (TyFun T1 T2)
H0: closed t
H1: is_value t
H2: exists n : nat, jtn n Gamma t (TyFun T1 T2)exists t' : {bind term}, t = Lam t'Gamma: tyenv
t: term
T1, T2: ty
H: jf Gamma t (TyFun T1 T2)
H0: closed t
H1: is_value t
x: nat
H2: jtn x Gamma t (TyFun T1 T2)exists t' : {bind term}, t = Lam t'Gamma: tyenv
t: term
T1, T2: ty
H: jf Gamma t (TyFun T1 T2)
H0: closed t
H1: is_value t
x: nat
H2: jtn x Gamma t (TyFun T1 T2)
fact:= exists t' : {bind term}, t = Lam t': Propstar sub (TyFun T1 T2) (TyFun ?T1 ?T2)Gamma: tyenv
T1, T2: ty
x0: {bind term}
H1: is_value (Lam x0)
H0: closed (Lam x0)
H: jf Gamma (Lam x0) (TyFun T1 T2)
x: nat
H2: jtn x Gamma (Lam x0) (TyFun T1 T2)exists t' : {bind term}, Lam x0 = Lam t'eauto with sequences.Gamma: tyenv
t: term
T1, T2: ty
H: jf Gamma t (TyFun T1 T2)
H0: closed t
H1: is_value t
x: nat
H2: jtn x Gamma t (TyFun T1 T2)
fact:= exists t' : {bind term}, t = Lam t': Propstar sub (TyFun T1 T2) (TyFun ?T1 ?T2)eauto using jt_jf. Qed.Gamma: tyenv
T1, T2: ty
x0: {bind term}
H1: is_value (Lam x0)
H0: closed (Lam x0)
H: jf Gamma (Lam x0) (TyFun T1 T2)
x: nat
H2: jtn x Gamma (Lam x0) (TyFun T1 T2)exists t' : {bind term}, Lam x0 = Lam t'
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), jf Gamma t T -> closed t -> (exists t' : term, cbv t t') \/ is_value tforall (Gamma : tyenv) (t : term) (T : ty), jf 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), jf Gamma t T -> closed t -> (exists t' : term, cbv t t') \/ is_value t(* Case: JFVar. *)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: jf (T .: Gamma) t U
IHjf: 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: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: closed t1 -> (exists t' : term, cbv t1 t') \/ is_value t1
IHjf2: 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)Gamma: var -> ty
t: term
T: ty
H: jf (Gamma >> ren (+1)) t T
IHjf: closed t -> (exists t' : term, cbv t t') \/ is_value t
H1: closed t(exists t' : term, cbv t t') \/ is_value tGamma: tyenv
t: term
T, U: {bind ty}
H: jf Gamma t (TyAll T)
IHjf: closed t -> (exists t' : term, cbv t t') \/ is_value t
H1: closed t(exists t' : term, cbv t t') \/ is_value tGamma: 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: JFLam. *)Gamma: var -> ty
t: term
T, U: ty
H: jf (T .: Gamma) t U
IHjf: 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: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: closed t1 -> (exists t' : term, cbv t1 t') \/ is_value t1
IHjf2: 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)Gamma: var -> ty
t: term
T: ty
H: jf (Gamma >> ren (+1)) t T
IHjf: closed t -> (exists t' : term, cbv t t') \/ is_value t
H1: closed t(exists t' : term, cbv t t') \/ is_value tGamma: tyenv
t: term
T, U: {bind ty}
H: jf Gamma t (TyAll T)
IHjf: closed t -> (exists t' : term, cbv t t') \/ is_value t
H1: closed t(exists t' : term, cbv t t') \/ is_value tobvious.Gamma: var -> ty
t: term
T, U: ty
H: jf (T .: Gamma) t U
IHjf: 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: JFApp. *)Gamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: closed t1 -> (exists t' : term, cbv t1 t') \/ is_value t1
IHjf2: 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)Gamma: var -> ty
t: term
T: ty
H: jf (Gamma >> ren (+1)) t T
IHjf: closed t -> (exists t' : term, cbv t t') \/ is_value t
H1: closed t(exists t' : term, cbv t t') \/ is_value tGamma: tyenv
t: term
T, U: {bind ty}
H: jf Gamma t (TyAll T)
IHjf: closed t -> (exists t' : term, cbv t t') \/ is_value t
H1: closed t(exists t' : term, cbv t t') \/ is_value tGamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf1: closed t1 -> (exists t' : term, cbv t1 t') \/ is_value t1
IHjf2: 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)Gamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf Gamma t2 T
IHjf2: 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)Gamma: tyenv
t1, t2: term
T, U: ty
H: jf Gamma t1 (TyFun T U)
H0: jf 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: jf Gamma t1 (TyFun T U)
H0: jf 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: jf Gamma t1 (TyFun T U)
H0: jf 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: jf Gamma (Lam x) (TyFun T U)
H0: jf 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: jf Gamma t1 (TyFun T U)
H0: jf 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.Gamma: tyenv
t2: term
T, U: ty
x: {bind term}
H: jf Gamma (Lam x) (TyFun T U)
H0: jf 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'(* Case: JFTyAbs. *)Gamma: var -> ty
t: term
T: ty
H: jf (Gamma >> ren (+1)) t T
IHjf: closed t -> (exists t' : term, cbv t t') \/ is_value t
H1: closed t(exists t' : term, cbv t t') \/ is_value tGamma: tyenv
t: term
T, U: {bind ty}
H: jf Gamma t (TyAll T)
IHjf: closed t -> (exists t' : term, cbv t t') \/ is_value t
H1: closed t(exists t' : term, cbv t t') \/ is_value teauto.Gamma: var -> ty
t: term
T: ty
H: jf (Gamma >> ren (+1)) t T
IHjf: closed t -> (exists t' : term, cbv t t') \/ is_value t
H1: closed t(exists t' : term, cbv t t') \/ is_value t(* Case: JFTyApp. *)Gamma: tyenv
t: term
T, U: {bind ty}
H: jf Gamma t (TyAll T)
IHjf: closed t -> (exists t' : term, cbv t t') \/ is_value t
H1: closed t(exists t' : term, cbv t t') \/ is_value teauto. } Qed.Gamma: tyenv
t: term
T, U: {bind ty}
H: jf Gamma t (TyAll T)
IHjf: closed t -> (exists t' : term, cbv t t') \/ is_value t
H1: closed t(exists t' : term, cbv t t') \/ is_value t