We demonstrate how to instantiate our framework to define the OGS associated to the CBV Ξ»-calculus. With the instance comes the proof that bisimilarity of the OGS entails substitution equivalence, which coincides with CIU-equivalence.
Note
This example is designed to be minimal, hiding by nature some difficulties. In particular it has no positive types, which simplifies the development a lot.
As discussed in the paper, our framework applies not really to a language but
more to an abstract machine. In order to ease this instanciation, we will
focus directly on a CBV machine and define evaluation contexts early on.
Working with intrinsically typed syntax, we need to give types to these
contexts: we will type them by the "formal negation" of the type of their
hole. In order to do so we first define the usual types ty0
of STLC with
functions and a ground type.
Declare Scope ty_scope . Inductive ty0 : Type := | ΞΉ : ty0 | Arr : ty0 -> ty0 -> ty0 . Notation "A β B" := (Arr A B) (at level 40) : ty_scope .
We then define "tagged types", where t+ a
will be the type of terms of type
a
, and t- a
the type of evaluation contexts of hole a
.
Variant ty : Type := | VTy : ty0 -> ty | KTy : ty0 -> ty . Notation "+ t" := (VTy t) (at level 5) : ty_scope . Notation "Β¬ t" := (KTy t) (at level 5) : ty_scope . Coercion VTy : ty0 >-> ty .
Typing contexts are now simply defined as lists of tagged types. This is perhaps the slightly surprising part: contexts will now contain "continuation variables". Rest assured terms will make no use of them. These are solely needed for evaluation contexts: as they are only typed with their hole, we are missing the type of their outside. We fix this problem by naming the outside and make evaluation contexts end with a continuation variable.
Note
Our choices make a bit more sense if we realize that what we are writing is exactly the subset of λμ-calculus that is the image of the CBV translation from λ-calculus.
Definition t_ctx : Type := ctx ty .
We now have all that is needed to define terms, which we define mutually with values. As discussed above, they are are indexed by a list of tagged types (of which they only care about the non-negated elements) and by an untagged type.
The only fanciness is the recursive lambda abstraction, which we include to safeguard ourselves from accidentally using the fact that the language is strongly normalizing.
Inductive term (Ξ : t_ctx) : ty0 -> Type :=
| Val {a} : val Ξ a -> term Ξ a
| App {a b} : term Ξ (a β b) -> term Ξ a -> term Ξ b
with val (Ξ : t_ctx) : ty0 -> Type :=
| Var {a} : Ξ β + a -> val Ξ a
| TT : val Ξ ΞΉ
| Lam {a b} : term (Ξ βΆβ (a β b) βΆβ a) b -> val Ξ (a β b)
.
Evaluation contexts follow. As discussed, there is a "covariable" case, to "end" the context. The other cases are usual: evaluating the argument of an application and evaluating the function.
Inductive ev_ctx (Ξ : t_ctx) : ty0 -> Type :=
| K0 {a} : Ξ β Β¬ a -> ev_ctx Ξ a
| K1 {a b} : term Ξ (a β b) -> ev_ctx Ξ b -> ev_ctx Ξ a
| K2 {a b} : val Ξ a -> ev_ctx Ξ b -> ev_ctx Ξ (a β b)
.
Next are the machine states. They consist of an explicit cut and represent a term in the process of being executed in some context. Notice how states they are only indexed by a typing context: these are proper "diverging programs".
Definition state := term β₯β ev_ctx.
Finally the last of syntactic categories: "machine values". This category is typed with a tagged type and encompasses both values (for non-negated types) and evaluation contexts (for negated types). The primary use-case for this category is to denote "things by which we can substitute (tagged) variables".
In fact when working with intrinsically-typed syntax, substitution is modelled
as a monoidal multiplication (see [AACMM21] and [FS22]). We will prove later
that val_m Ξ
is indeed a monoid relative to has Ξ
and that contexts and
assignments form a category.
Equations val_m : t_ctx -> ty -> Type :=
val_m Ξ (+ a) := val Ξ a ;
val_m Ξ (Β¬ a) := ev_ctx Ξ a .
Together with machine values we define a smart constructor for "machine var",
embedding tagged variables into these generalized values. It conveniently
serves as the identity assignment, a fact we use to give it this mysterious
point-free style type, which desugars to forall a, Ξ β a -> val_m Ξ a
.
Equations a_id {Ξ} : Ξ =[val_m]> Ξ :=
a_id (+ _) i := Var i ;
a_id (Β¬ _) i := K0 i .
In order to define substitution we first need to dance the intrinsically-typed dance and define renamings, from which we will derive weakenings and then only define substitution.
Lets write intrinsically-typed parallel renaming for all of our syntactic categories! If you have never seen such intrinsically-typed definitions you might be surprised by the absence of error-prone de-bruijn index manipulation. Enjoy this beautiful syntax traversal!
Equations t_rename {Ξ Ξ} : Ξ β Ξ -> term Ξ βα΅’ term Ξ := t_rename f _ (Val v) := Val (v_rename f _ v) ; t_rename f _ (App t1 t2) := App (t_rename f _ t1) (t_rename f _ t2) ; with v_rename {Ξ Ξ} : Ξ β Ξ -> val Ξ βα΅’ val Ξ := v_rename f _ (Var i) := Var (f _ i) ; v_rename f _ (TT) := TT ; v_rename f _ (Lam t) := Lam (t_rename (r_shift2 f) _ t) . Equations e_rename {Ξ Ξ} : Ξ β Ξ -> ev_ctx Ξ βα΅’ ev_ctx Ξ := e_rename f _ (K0 i) := K0 (f _ i) ; e_rename f _ (K1 t Ο) := K1 (t_rename f _ t) (e_rename f _ Ο) ; e_rename f _ (K2 v Ο) := K2 (v_rename f _ v) (e_rename f _ Ο) . Equations s_rename {Ξ Ξ} : Ξ β Ξ -> state Ξ -> state Ξ := s_rename f (Cut t Ο) := Cut (t_rename f _ t) (e_rename f _ Ο). Equations m_rename {Ξ Ξ} : Ξ β Ξ -> val_m Ξ βα΅’ val_m Ξ := m_rename f (+ _) v := v_rename f _ v ; m_rename f (Β¬ _) Ο := e_rename f _ Ο . #[global] Arguments s_rename _ _ _ /. #[global] Arguments m_rename _ _ _ /.
We can recast m_rename
as an operator on assigments, more precisely as
renaming an assigment on the left.
Definition a_ren {Ξ1 Ξ2 Ξ3} : Ξ2 β Ξ3 -> Ξ1 =[val_m]> Ξ2 -> Ξ1 =[val_m]> Ξ3 :=
fun f g _ i => m_rename f _ (g _ i) .
The following bunch of notations will help us to keep the code readable:
Notation "t ββα΅£ r" := (t_rename r%asgn _ t) (at level 14). Notation "v α΅₯βα΅£ r" := (v_rename r%asgn _ v) (at level 14). Notation "Ο ββα΅£ r" := (e_rename r%asgn _ Ο) (at level 14). Notation "v ββα΅£ r" := (m_rename r%asgn _ v) (at level 14). Notation "s ββα΅£ r" := (s_rename r%asgn s) (at level 14). Notation "a βα΅£ r" := (a_ren r%asgn a) (at level 14) : asgn_scope.
As discussed above, we can now obtain our precious weakenings. Here are the three we will need.
Definition t_shift {Ξ a} := @t_rename Ξ (Ξ βΆβ a) r_pop. Definition m_shift2 {Ξ a b} := @m_rename Ξ (Ξ βΆβ a βΆβ b) (r_pop α΅£β r_pop). Definition a_shift2 {Ξ Ξ a b} (f : Ξ =[val_m]> Ξ) : (Ξ βΆβ a βΆβ b) =[val_m]> (Ξ βΆβ a βΆβ b) := [ [ a_map f m_shift2 ,β a_id a (pop top) ] ,β a_id b top ].
With weakenings in place we are now equipped to define substitutions. This goes pretty much like renaming. We have abstained from defining generic syntax traversal tools like Allais et al's "Kits" to keep our example minimal... And incidentally showcase the intrinsically-typed style with Matthieu Sozeau's Equations.
Equations t_subst {Ξ Ξ} : Ξ =[val_m]> Ξ -> term Ξ βα΅’ term Ξ := t_subst f _ (Val v) := Val (v_subst f _ v) ; t_subst f _ (App t1 t2) := App (t_subst f _ t1) (t_subst f _ t2) ; with v_subst {Ξ Ξ} : Ξ =[val_m]> Ξ -> val Ξ βα΅’ val Ξ := v_subst f _ (Var i) := f _ i ; v_subst f _ (TT) := TT ; v_subst f _ (Lam t) := Lam (t_subst (a_shift2 f) _ t) . Equations e_subst {Ξ Ξ} : Ξ =[val_m]> Ξ -> ev_ctx Ξ βα΅’ ev_ctx Ξ := e_subst f _ (K0 i) := f _ i ; e_subst f _ (K1 t Ο) := K1 (t_subst f _ t) (e_subst f _ Ο) ; e_subst f _ (K2 v Ο) := K2 (v_subst f _ v) (e_subst f _ Ο) .
These notations will make everything shine.
Notation "t `ββ a" := (t_subst a%asgn _ t) (at level 30). Notation "v `α΅₯β a" := (v_subst a%asgn _ v) (at level 30). Notation "Ο `ββ a" := (e_subst a%asgn _ Ο) (at level 30).
These two last substitutions, for states and generalized values, are the ones we will give to the abstract interface. For categorical abstraction reasons, the abstract interface has the argument reversed for substitutions: first the state or value, then the assignment as second argument. To ease instanciation we will hence do so too. The type is given with tricky combinators but expands to:
m_subst Ξ a : val_m Ξ a -> forall Ξ, Ξ =[val_m]> Ξ -> val_m Ξ a
Equations m_subst : val_m ββ β¦ val_m , val_m β§β := m_subst _ (+ _) v _ f := v `α΅₯β f ; m_subst _ (Β¬ _) Ο _ f := Ο `ββ f . Definition s_subst : state ββ β¦ val_m , state β§β := fun _ s _ f => (s.(cut_l) `ββ f) β (s.(cut_r) `ββ f). #[global] Arguments s_subst _ _ /.
We can now instanciate the substitution monoid and module structures.
#[global] Instance val_m_monoid : subst_monoid val_m := {| v_var := @a_id ; v_sub := m_subst |} . #[global] Instance state_module : subst_module val_m state := {| c_sub := s_subst |} .
Finally we define a more usual substitution function which only substitutes the top two variables instead of doing parallel substitution.
Definition assign2 {Ξ a b} v1 v2 : (Ξ βΆβ a βΆβ b) =[val_m]> Ξ := [ [ a_id ,β v1 ] ,β v2 ] . Definition t_subst2 {Ξ a b c} (t : term _ c) v1 v2 := t `ββ @assign2 Ξ a b v1 v2. Notation "t /[ v1 , v2 ]" := (t_subst2 t v1 v2) (at level 50, left associativity).
As motivated earlier, the evaluator will be a defined as a state-machine, the
core definition being a state-transition function. To stick to the intrinsic
style, we wish that this state-machine stops only at evidently normal forms,
instead of stoping at states which happen to be in normal form. Perhaps more
simply said, we want to type the transition function as state Ξ β (state
Ξ + nf Ξ)
, where returning in the right component means stoping and outputing
a normal form.
In order to do this we first need to define normal forms! But instead of defining an inductive definition of normal forms as is customary, we will take an other route more tailored to OGS based on ultimate patterns.
As discussed in the paper, a central aspect of OGS is to circumvent the problem of naive trace semantics for higher-order languages by mean of a notion of "abstract values", or more commonly ultimate patterns, which define the "shareable part" of a value. For clarity reasons, instead of patterns we here take the dual point of view of "observations", which can be seen as patterns at the dual type (dual in the sense of swapping the tag). For our basic Ξ»-calculus, all types are negative -- that is, unsheareble -- hence the observations are pretty simple:
Observing a continuation of type Β¬ a
means returning a (hidden) value to
it. In terms of pattern this corresponds to the "fresh variable" pattern
Var x
.
Observing a function of type a β b
means giving it a hidden value and
a hidden continuation. In terms of patterns this corresponds to the
"application" co-pattern K2 (Var x) (K0 y)
.
Variant obs : ty -> Type :=
| ORet {a} : obs (Β¬ a)
| OApp {a b} : obs (a β b)
.
As observations correspond to a subset of (machine) values where all the
variables are "fresh", these variables have no counter-part in de-bruijn
notation (there is no meaningful notion of freshness). As such we have not
indexed obs
by any typing context, but to complete the definition we now
need to define a projection into typing contexts denoting the "domain",
"support" or more accurately "set of nameless fresh variables" of an
observation.
Equations obs_dom {a} : obs a -> t_ctx :=
obs_dom (@ORet a) := β
βΆβ + a ;
obs_dom (@OApp a b) := β
βΆβ + a βΆβ Β¬ b .
These two definitions together form an operator.
Definition obs_op : Oper ty t_ctx := {| o_op := obs ; o_dom := @obs_dom |} . Notation ORet' := (ORet : o_op obs_op _). Notation OApp' := (OApp : o_op obs_op _).
Given a value, an observation on its type and a value for each fresh variable of the observation, we can "refold" everything and form a new state which will indeed observe this value.
Equations obs_app {Ξ a} (v : val_m Ξ a) (p : obs a) (Ξ³ : obs_dom p =[val_m]> Ξ) : state Ξ :=
obs_app v OApp Ξ³ := Val v β
K2 (Ξ³ _ (pop top)) (Ξ³ _ top) ;
obs_app Ο ORet Ξ³ := Val (Ξ³ _ top) β
(Ο : ev_ctx _ _) .
Normal forms for CBV Ξ»-calculus can be characterized as either a value v
or
a stuck application in evaluation context E[x v]
(see "eager-normal forms"
in [L05]). Now it doesn't take much squinting to see that in our setting,
this corresponds respectively to states of the form β¨ v | K0 x β©
and β¨ Var
x | K2 v Ο β©
. Squinting a bit more, we can reap the benefits of our unified
treatment of terms and contexts and see that both of these cases work in the
same way: normal states are states given by a variable facing an observation
whose fresh variables have been substituted with values.
Having already defined observation and their set of fresh variables, an
observation stuffed with values in typing context Ξ
can be represented
simply by a formal substitution of an observation o
and an assigment
obs_dom o =[val]> Ξ
. This "split" definition of normal forms is the one we
will take.
Definition nf := c_var β₯β (obs_op # val_m).
Everything is now in place to define our state transition function. The reduction rules should come to no surprise:
β¨ t1 t2 | Ο β© β β¨ t2 | t1 β
1 Ο β©
β¨ v | x β©
normalβ¨ v | t β
1 Ο β© β β¨ t | v β
2 Ο β©
β¨ x | v β
2 Ο β©
normalβ¨ Ξ»fx.t | v β
2 Ο β© β β¨ t[fβ¦Ξ»fx.t; xβ¦v] | Ο β©
Rules 1,3,5 step to a new configuration, while cases 2,4 are stuck on normal forms.
Equations eval_step {Ξ : t_ctx} : state Ξ -> sum (state Ξ) (nf Ξ) :=
eval_step (Cut (App t1 t2) (Ο)) := inl (Cut t2 (K1 t1 Ο)) ;
eval_step (Cut (Val v) (K0 i)) := inr (i β
ORet' β¦ [ ! ,β v ] β¦) ;
eval_step (Cut (Val v) (K1 t Ο)) := inl (Cut t (K2 v Ο)) ;
eval_step (Cut (Val (Var i)) (K2 v Ο)) := inr (i β
OApp' β¦ [ [ ! ,β v ] ,β Ο ] β¦) ;
eval_step (Cut (Val (Lam t)) (K2 v Ο)) := inl (Cut (t /[ Lam t , v ]) Ο) .
Having defined the transition function, we can now iterate it inside the delay monad. This constructs a possibly non-terminating computation ending with a normal form.
Definition stlc_eval {Ξ : t_ctx} : state Ξ -> delay (nf Ξ)
:= iter_delay (ret_delay β eval_step).
We have now finished all the computational parts of the instanciation, but all the proofs are left to be done. Before attacking the OGS-specific hypotheses, we will need to prove the usual standard lemmata on renaming and substitution.
There will be a stack of lemmata which will all pretty much be simple inductions on the syntax, so we start by introducing some helpers for this. In fact it is not completely direct to do since terms and values are mutually defined: we will need to derive a mutual induction principle.
Scheme term_mut := Induction for term Sort Prop
with val_mut := Induction for val Sort Prop .
Annoyingly, Coq treats this mutual induction principle as two separate
induction principles. They both have the exact same premises but differ in
their conclusion. Thus we define a datatype for these premises, to avoid
duplicating the proofs. Additionally, evaluation contexts are not defined
mutually with terms and values, but it doesn't hurt to prove their properties
simultaneously too, so syn_ind_args
is in fact closer to the premises of
a three-way mutual induction principle between terms, values and evaluation
contexts.
Record syn_ind_args (P_t : forall Ξ A, term Ξ A -> Prop) (P_v : forall Ξ A, val Ξ A -> Prop) (P_e : forall Ξ A, ev_ctx Ξ A -> Prop) := { ind_val {Ξ a} v (_ : P_v Ξ a v) : P_t Ξ a (Val v) ; ind_app {Ξ a b} t1 (_ : P_t Ξ (a β b) t1) t2 (_ : P_t Ξ a t2) : P_t Ξ b (App t1 t2) ; ind_var {Ξ a} i : P_v Ξ a (Var i) ; ind_tt {Ξ} : P_v Ξ (ΞΉ) (TT) ; ind_lamrec {Ξ a b} t (_ : P_t _ b t) : P_v Ξ (a β b) (Lam t) ; ind_kvar {Ξ a} i : P_e Ξ a (K0 i) ; ind_kfun {Ξ a b} t (_ : P_t Ξ (a β b) t) Ο (_ : P_e Ξ b Ο) : P_e Ξ a (K1 t Ο) ; ind_karg {Ξ a b} v (_ : P_v Ξ a v) Ο (_ : P_e Ξ b Ο) : P_e Ξ (a β b) (K2 v Ο) } .destruct H; now apply (term_mut P_t P_v). Qed.P_t: forall (Ξ : t_ctx) (A : ty0), term Ξ A -> Prop
P_v: forall (Ξ : t_ctx) (A : ty0), val Ξ A -> Prop
P_e: forall (Ξ : t_ctx) (A : ty0), ev_ctx Ξ A -> Prop
H: syn_ind_args P_t P_v P_e
Ξ: t_ctx
a: ty0
t: term Ξ aP_t Ξ a tdestruct H; now apply (val_mut P_t P_v). Qed.P_t: forall (Ξ : t_ctx) (A : ty0), term Ξ A -> Prop
P_v: forall (Ξ : t_ctx) (A : ty0), val Ξ A -> Prop
P_e: forall (Ξ : t_ctx) (A : ty0), ev_ctx Ξ A -> Prop
H: syn_ind_args P_t P_v P_e
Ξ: t_ctx
a: ty0
v: val Ξ aP_v Ξ a vP_t: forall (Ξ : t_ctx) (A : ty0), term Ξ A -> Prop
P_v: forall (Ξ : t_ctx) (A : ty0), val Ξ A -> Prop
P_e: forall (Ξ : t_ctx) (A : ty0), ev_ctx Ξ A -> Prop
H: syn_ind_args P_t P_v P_e
Ξ: t_ctx
a: ty0
Ο: ev_ctx Ξ aP_e Ξ a ΟP_t: forall (Ξ : t_ctx) (A : ty0), term Ξ A -> Prop
P_v: forall (Ξ : t_ctx) (A : ty0), val Ξ A -> Prop
P_e: forall (Ξ : t_ctx) (A : ty0), ev_ctx Ξ A -> Prop
H: syn_ind_args P_t P_v P_e
Ξ: t_ctx
a: ty0
c: Ξ β Β¬ aP_e Ξ a (K0 c)P_t: forall (Ξ : t_ctx) (A : ty0), term Ξ A -> Prop
P_v: forall (Ξ : t_ctx) (A : ty0), val Ξ A -> Prop
P_e: forall (Ξ : t_ctx) (A : ty0), ev_ctx Ξ A -> Prop
H: syn_ind_args P_t P_v P_e
Ξ: t_ctx
a, b: ty0
t: term Ξ (a β b)
Ο: ev_ctx Ξ b
IHΟ: P_e Ξ b ΟP_e Ξ a (K1 t Ο)P_t: forall (Ξ : t_ctx) (A : ty0), term Ξ A -> Prop
P_v: forall (Ξ : t_ctx) (A : ty0), val Ξ A -> Prop
P_e: forall (Ξ : t_ctx) (A : ty0), ev_ctx Ξ A -> Prop
H: syn_ind_args P_t P_v P_e
Ξ: t_ctx
a, b: ty0
v: val Ξ a
Ο: ev_ctx Ξ b
IHΟ: P_e Ξ b ΟP_e Ξ (a β b) (K2 v Ο)apply (ind_kvar _ _ _ H).P_t: forall (Ξ : t_ctx) (A : ty0), term Ξ A -> Prop
P_v: forall (Ξ : t_ctx) (A : ty0), val Ξ A -> Prop
P_e: forall (Ξ : t_ctx) (A : ty0), ev_ctx Ξ A -> Prop
H: syn_ind_args P_t P_v P_e
Ξ: t_ctx
a: ty0
c: Ξ β Β¬ aP_e Ξ a (K0 c)apply (ind_kfun _ _ _ H); auto; apply (term_ind_mut _ _ _ H).P_t: forall (Ξ : t_ctx) (A : ty0), term Ξ A -> Prop
P_v: forall (Ξ : t_ctx) (A : ty0), val Ξ A -> Prop
P_e: forall (Ξ : t_ctx) (A : ty0), ev_ctx Ξ A -> Prop
H: syn_ind_args P_t P_v P_e
Ξ: t_ctx
a, b: ty0
t: term Ξ (a β b)
Ο: ev_ctx Ξ b
IHΟ: P_e Ξ b ΟP_e Ξ a (K1 t Ο)apply (ind_karg _ _ _ H); auto; apply (val_ind_mut _ _ _ H). Qed.P_t: forall (Ξ : t_ctx) (A : ty0), term Ξ A -> Prop
P_v: forall (Ξ : t_ctx) (A : ty0), val Ξ A -> Prop
P_e: forall (Ξ : t_ctx) (A : ty0), ev_ctx Ξ A -> Prop
H: syn_ind_args P_t P_v P_e
Ξ: t_ctx
a, b: ty0
v: val Ξ a
Ο: ev_ctx Ξ b
IHΟ: P_e Ξ b ΟP_e Ξ (a β b) (K2 v Ο)
Now equipped we can start with the first lemma: renaming respects pointwise equality of assignments. As discussed, we will prove this by mutual induction on our three "base" syntactic categories of terms, values and evaluation contexts, and then we will also deduce it for the three "derived" notions of machine values, states and assigments. Sometimes some of the derived notions will be omitted if it is not needed later on.
This proof, like all the following ones will follow a simple pattern: a simplification; an application of congruence; a fixup for the two-time shifted assigment in the case of Ξ»; finally a call to the induction hypothesis.
Note
Here is definitely where the generic syntax traversal kit of Guillaume Allais et al would shine. Indeed the proof pattern i outlined can really be formalized into a generic proof.
Definition t_ren_proper_P Ξ a (t : term Ξ a) : Prop := forall Ξ (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> t ββα΅£ f1 = t ββα΅£ f2 . Definition v_ren_proper_P Ξ a (v : val Ξ a) : Prop := forall Ξ (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> v α΅₯βα΅£ f1 = v α΅₯βα΅£ f2 . Definition e_ren_proper_P Ξ a (Ο : ev_ctx Ξ a) : Prop := forall Ξ (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> Ο ββα΅£ f1 = Ο ββα΅£ f2 .syn_ind_args t_ren_proper_P v_ren_proper_P e_ren_proper_Pforall (Ξ : t_ctx) (a : ty0) (v : val Ξ a), v_ren_proper_P Ξ a v -> t_ren_proper_P Ξ a vforall (Ξ : t_ctx) (a b : ty0) (t1 : term Ξ (a β b)), t_ren_proper_P Ξ (a β b) t1 -> forall t2 : term Ξ a, t_ren_proper_P Ξ a t2 -> t_ren_proper_P Ξ b (App t1 t2)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β + a), v_ren_proper_P Ξ a (Var i)forall Ξ : t_ctx, v_ren_proper_P Ξ ΞΉ TTforall (Ξ : t_ctx) (a b : ty0) (t : term (Ξ βΆβ + (a β b) βΆβ + a) b), t_ren_proper_P (Ξ βΆβ + (a β b) βΆβ + a) b t -> v_ren_proper_P Ξ (a β b) (Lam t)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β Β¬ a), e_ren_proper_P Ξ a (K0 i)forall (Ξ : t_ctx) (a b : ty0) (t : term Ξ (a β b)), t_ren_proper_P Ξ (a β b) t -> forall Ο : ev_ctx Ξ b, e_ren_proper_P Ξ b Ο -> e_ren_proper_P Ξ a (K1 t Ο)forall (Ξ : t_ctx) (a b : ty0) (v : val Ξ a), v_ren_proper_P Ξ a v -> forall Ο : ev_ctx Ξ b, e_ren_proper_P Ξ b Ο -> e_ren_proper_P Ξ (a β b) (K2 v Ο)forall (Ξ : t_ctx) (a : ty0) (v : val Ξ a), (forall (Ξ : t_ctx) (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> v α΅₯βα΅£ f1 = v α΅₯βα΅£ f2) -> forall (Ξ : t_ctx) (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> v ββα΅£ f1 = v ββα΅£ f2forall (Ξ : t_ctx) (a b : ty0) (t1 : term Ξ (a β b)), (forall (Ξ : t_ctx) (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> t1 ββα΅£ f1 = t1 ββα΅£ f2) -> forall t2 : term Ξ a, (forall (Ξ : t_ctx) (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> t2 ββα΅£ f1 = t2 ββα΅£ f2) -> forall (Ξ : t_ctx) (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> App t1 t2 ββα΅£ f1 = App t1 t2 ββα΅£ f2forall (Ξ : t_ctx) (a : ty0) (i : Ξ β + a) (Ξ : t_ctx) (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> Var i α΅₯βα΅£ f1 = Var i α΅₯βα΅£ f2forall (Ξ Ξ : t_ctx) (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> TT α΅₯βα΅£ f1 = TT α΅₯βα΅£ f2forall (Ξ : t_ctx) (a b : ty0) (t : term (Ξ βΆβ + (a β b) βΆβ + a) b), (forall (Ξ : t_ctx) (f1 f2 : (Ξ βΆβ + (a β b) βΆβ + a) β Ξ), f1 β‘β f2 -> t ββα΅£ f1 = t ββα΅£ f2) -> forall (Ξ : t_ctx) (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> Lam t α΅₯βα΅£ f1 = Lam t α΅₯βα΅£ f2forall (Ξ : t_ctx) (a : ty0) (i : Ξ β Β¬ a) (Ξ : t_ctx) (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> K0 i ββα΅£ f1 = K0 i ββα΅£ f2forall (Ξ : t_ctx) (a b : ty0) (t : term Ξ (a β b)), (forall (Ξ : t_ctx) (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> t ββα΅£ f1 = t ββα΅£ f2) -> forall Ο : ev_ctx Ξ b, (forall (Ξ : t_ctx) (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> Ο ββα΅£ f1 = Ο ββα΅£ f2) -> forall (Ξ : t_ctx) (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> K1 t Ο ββα΅£ f1 = K1 t Ο ββα΅£ f2forall (Ξ : t_ctx) (a b : ty0) (v : val Ξ a), (forall (Ξ : t_ctx) (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> v α΅₯βα΅£ f1 = v α΅₯βα΅£ f2) -> forall Ο : ev_ctx Ξ b, (forall (Ξ : t_ctx) (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> Ο ββα΅£ f1 = Ο ββα΅£ f2) -> forall (Ξ : t_ctx) (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> K2 v Ο ββα΅£ f1 = K2 v Ο ββα΅£ f2all: eapply H; now apply r_shift2_eq. Qed.Ξ: t_ctx
a: ty0
i: Ξ β + a
Ξ: t_ctx
f1, f2: Ξ β Ξ
H: f1 β‘β f2f1 + a i = f2 + a iΞ: t_ctx
a, b: ty0
t: term (Ξ βΆβ + (a β b) βΆβ + a) b
H: forall (Ξ : t_ctx) (f1 f2 : (Ξ βΆβ + (a β b) βΆβ + a) β Ξ), f1 β‘β f2 -> t ββα΅£ f1 = t ββα΅£ f2
Ξ: t_ctx
f1, f2: Ξ β Ξ
H0: f1 β‘β f2t ββα΅£ r_shift2 f1 = t ββα΅£ r_shift2 f2Ξ: t_ctx
a: ty0
i: Ξ β Β¬ a
Ξ: t_ctx
f1, f2: Ξ β Ξ
H: f1 β‘β f2f1 Β¬ a i = f2 Β¬ a iintros f1 f2 H1 a x y ->; now apply (term_ind_mut _ _ _ ren_proper_prf). Qed.Ξ, Ξ: t_ctxProper (asgn_eq Ξ Ξ ==> (ββ a, eq ==> eq)) t_renameintros f1 f2 H1 a x y ->; now apply (val_ind_mut _ _ _ ren_proper_prf). Qed.Ξ, Ξ: t_ctxProper (asgn_eq Ξ Ξ ==> (ββ a, eq ==> eq)) v_renameintros f1 f2 H1 a x y ->; now apply (ctx_ind_mut _ _ _ ren_proper_prf). Qed.Ξ, Ξ: t_ctxProper (asgn_eq Ξ Ξ ==> (ββ a, eq ==> eq)) e_renameintros ? ? H1 [] _ ? ->; cbn in *; now rewrite H1. Qed.Ξ, Ξ: t_ctxProper (asgn_eq Ξ Ξ ==> (ββ a, eq ==> eq)) m_renameintros ? ? H1 _ x ->; destruct x; unfold s_rename; cbn; now rewrite H1. Qed.Ξ, Ξ: t_ctxProper (asgn_eq Ξ Ξ ==> eq ==> eq) s_renameintros ? ? H1 ? ? H2 ? ?; apply (m_ren_eq _ _ H1), H2. Qed.Ξ1, Ξ2, Ξ3: t_ctxProper (asgn_eq Ξ2 Ξ3 ==> asgn_eq Ξ1 Ξ2 ==> asgn_eq Ξ1 Ξ3) a_renΞ, Ξ: t_ctx
x, y: tyProper (asgn_eq Ξ Ξ ==> asgn_eq (Ξ βΆβ x βΆβ y) (Ξ βΆβ x βΆβ y)) a_shift2Ξ, Ξ: t_ctx
x, y: ty
x0, y0: Ξ =[ val_m ]> Ξ
H: x0 β‘β y0
a: ty
v: Ξ βΆβ x βΆβ y β aa_shift2 x0 a v = a_shift2 y0 a vnow rewrite H. Qed.Ξ1: ctx ty
Ξ: t_ctx
y, y1: ty
x0, y0: Ξ1 =[ val_m ]> Ξ
H: x0 β‘β y0
a: ty
v: var a Ξ1m_shift2 a (x0 a v) = m_shift2 a (y0 a v)
Lemma 2: renaming-renaming assocativity. I say "associativity" because it definitely looks like associativity if we disregard the subscripts. More precisely it could be described as the composition law a right action.
Definition t_ren_ren_P Ξ1 a (t : term Ξ1 a) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 β Ξ2) (f2 : Ξ2 β Ξ3), (t ββα΅£ f1) ββα΅£ f2 = t ββα΅£ (f1 α΅£β f2). Definition v_ren_ren_P Ξ1 a (v : val Ξ1 a) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 β Ξ2) (f2 : Ξ2 β Ξ3), (v α΅₯βα΅£ f1) α΅₯βα΅£ f2 = v α΅₯βα΅£ (f1 α΅£β f2). Definition e_ren_ren_P Ξ1 a (Ο : ev_ctx Ξ1 a) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 β Ξ2) (f2 : Ξ2 β Ξ3), (Ο ββα΅£ f1) ββα΅£ f2 = Ο ββα΅£ (f1 α΅£β f2).syn_ind_args t_ren_ren_P v_ren_ren_P e_ren_ren_Pforall (Ξ : t_ctx) (a : ty0) (v : val Ξ a), v_ren_ren_P Ξ a v -> t_ren_ren_P Ξ a vforall (Ξ : t_ctx) (a b : ty0) (t1 : term Ξ (a β b)), t_ren_ren_P Ξ (a β b) t1 -> forall t2 : term Ξ a, t_ren_ren_P Ξ a t2 -> t_ren_ren_P Ξ b (App t1 t2)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β + a), v_ren_ren_P Ξ a (Var i)forall Ξ : t_ctx, v_ren_ren_P Ξ ΞΉ TTforall (Ξ : t_ctx) (a b : ty0) (t : term (Ξ βΆβ + (a β b) βΆβ + a) b), t_ren_ren_P (Ξ βΆβ + (a β b) βΆβ + a) b t -> v_ren_ren_P Ξ (a β b) (Lam t)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β Β¬ a), e_ren_ren_P Ξ a (K0 i)forall (Ξ : t_ctx) (a b : ty0) (t : term Ξ (a β b)), t_ren_ren_P Ξ (a β b) t -> forall Ο : ev_ctx Ξ b, e_ren_ren_P Ξ b Ο -> e_ren_ren_P Ξ a (K1 t Ο)forall (Ξ : t_ctx) (a b : ty0) (v : val Ξ a), v_ren_ren_P Ξ a v -> forall Ο : ev_ctx Ξ b, e_ren_ren_P Ξ b Ο -> e_ren_ren_P Ξ (a β b) (K2 v Ο)forall (Ξ : t_ctx) (a : ty0) (v : val Ξ a), (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 β Ξ3), (v α΅₯βα΅£ f1) α΅₯βα΅£ f2 = v α΅₯βα΅£ (f1 α΅£β f2)) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 β Ξ3), (v ββα΅£ f1) ββα΅£ f2 = v ββα΅£ (f1 α΅£β f2)forall (Ξ : t_ctx) (a b : ty0) (t1 : term Ξ (a β b)), (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 β Ξ3), (t1 ββα΅£ f1) ββα΅£ f2 = t1 ββα΅£ (f1 α΅£β f2)) -> forall t2 : term Ξ a, (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 β Ξ3), (t2 ββα΅£ f1) ββα΅£ f2 = t2 ββα΅£ (f1 α΅£β f2)) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 β Ξ3), (App t1 t2 ββα΅£ f1) ββα΅£ f2 = App t1 t2 ββα΅£ (f1 α΅£β f2)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β + a) (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 β Ξ3), (Var i α΅₯βα΅£ f1) α΅₯βα΅£ f2 = Var i α΅₯βα΅£ (f1 α΅£β f2)forall (Ξ Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 β Ξ3), (TT α΅₯βα΅£ f1) α΅₯βα΅£ f2 = TT α΅₯βα΅£ (f1 α΅£β f2)forall (Ξ : t_ctx) (a b : ty0) (t : term (Ξ βΆβ + (a β b) βΆβ + a) b), (forall (Ξ2 Ξ3 : t_ctx) (f1 : (Ξ βΆβ + (a β b) βΆβ + a) β Ξ2) (f2 : Ξ2 β Ξ3), (t ββα΅£ f1) ββα΅£ f2 = t ββα΅£ (f1 α΅£β f2)) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 β Ξ3), (Lam t α΅₯βα΅£ f1) α΅₯βα΅£ f2 = Lam t α΅₯βα΅£ (f1 α΅£β f2)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β Β¬ a) (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 β Ξ3), (K0 i ββα΅£ f1) ββα΅£ f2 = K0 i ββα΅£ (f1 α΅£β f2)forall (Ξ : t_ctx) (a b : ty0) (t : term Ξ (a β b)), (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 β Ξ3), (t ββα΅£ f1) ββα΅£ f2 = t ββα΅£ (f1 α΅£β f2)) -> forall Ο : ev_ctx Ξ b, (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 β Ξ3), (Ο ββα΅£ f1) ββα΅£ f2 = Ο ββα΅£ (f1 α΅£β f2)) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 β Ξ3), (K1 t Ο ββα΅£ f1) ββα΅£ f2 = K1 t Ο ββα΅£ (f1 α΅£β f2)forall (Ξ : t_ctx) (a b : ty0) (v : val Ξ a), (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 β Ξ3), (v α΅₯βα΅£ f1) α΅₯βα΅£ f2 = v α΅₯βα΅£ (f1 α΅£β f2)) -> forall Ο : ev_ctx Ξ b, (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 β Ξ3), (Ο ββα΅£ f1) ββα΅£ f2 = Ο ββα΅£ (f1 α΅£β f2)) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 β Ξ3), (K2 v Ο ββα΅£ f1) ββα΅£ f2 = K2 v Ο ββα΅£ (f1 α΅£β f2)Ξ: t_ctx
a, b: ty0
t: term (Ξ βΆβ + (a β b) βΆβ + a) b
H: forall (Ξ2 Ξ3 : t_ctx) (f1 : (Ξ βΆβ + (a β b) βΆβ + a) β Ξ2) (f2 : Ξ2 β Ξ3), (t ββα΅£ f1) ββα΅£ f2 = t ββα΅£ (f1 α΅£β f2)
Ξ2, Ξ3: t_ctx
f1: Ξ β Ξ2
f2: Ξ2 β Ξ3(t ββα΅£ r_shift2 f1) ββα΅£ r_shift2 f2 = t ββα΅£ r_shift2 (f1 α΅£β f2)intros ? v; now do 2 (dependent elimination v; eauto). Qed.Ξ: t_ctx
a, b: ty0
t: term (Ξ βΆβ + (a β b) βΆβ + a) b
H: forall (Ξ2 Ξ3 : t_ctx) (f1 : (Ξ βΆβ + (a β b) βΆβ + a) β Ξ2) (f2 : Ξ2 β Ξ3), (t ββα΅£ f1) ββα΅£ f2 = t ββα΅£ (f1 α΅£β f2)
Ξ2, Ξ3: t_ctx
f1: Ξ β Ξ2
f2: Ξ2 β Ξ3r_shift2 f1 α΅£β r_shift2 f2 β‘β r_shift2 (f1 α΅£β f2)now apply (term_ind_mut _ _ _ ren_ren_prf). Qed.Ξ1, Ξ2, Ξ3: ctx ty
f1: Ξ1 β Ξ2
f2: Ξ2 β Ξ3
a: ty0
t: term Ξ1 a(t ββα΅£ f1) ββα΅£ f2 = t ββα΅£ (f1 α΅£β f2)now apply (val_ind_mut _ _ _ ren_ren_prf). Qed.Ξ1, Ξ2, Ξ3: ctx ty
f1: Ξ1 β Ξ2
f2: Ξ2 β Ξ3
a: ty0
v: val Ξ1 a(v α΅₯βα΅£ f1) α΅₯βα΅£ f2 = v α΅₯βα΅£ (f1 α΅£β f2)now apply (ctx_ind_mut _ _ _ ren_ren_prf). Qed.Ξ1, Ξ2, Ξ3: ctx ty
f1: Ξ1 β Ξ2
f2: Ξ2 β Ξ3
a: ty0
Ο: ev_ctx Ξ1 a(Ο ββα΅£ f1) ββα΅£ f2 = Ο ββα΅£ (f1 α΅£β f2)destruct a; [ now apply v_ren_ren | now apply e_ren_ren ]. Qed.Ξ1, Ξ2, Ξ3: ctx ty
f1: Ξ1 β Ξ2
f2: Ξ2 β Ξ3
a: ty
v: val_m Ξ1 a(v ββα΅£ f1) ββα΅£ f2 = v ββα΅£ (f1 α΅£β f2)destruct s; apply (f_equal2 Cut); [ now apply t_ren_ren | now apply e_ren_ren ]. Qed.Ξ1, Ξ2, Ξ3: ctx ty
f1: Ξ1 β Ξ2
f2: Ξ2 β Ξ3
s: state Ξ1(s ββα΅£ f1) ββα΅£ f2 = s ββα΅£ (f1 α΅£β f2)
Lemma 3: left identity law of renaming.
Definition t_ren_id_l_P Ξ a (t : term Ξ a) : Prop := t ββα΅£ r_id = t . Definition v_ren_id_l_P Ξ a (v : val Ξ a) : Prop := v α΅₯βα΅£ r_id = v . Definition e_ren_id_l_P Ξ a (Ο : ev_ctx Ξ a) : Prop := Ο ββα΅£ r_id = Ο.syn_ind_args t_ren_id_l_P v_ren_id_l_P e_ren_id_l_Pforall (Ξ : t_ctx) (a : ty0) (v : val Ξ a), v_ren_id_l_P Ξ a v -> t_ren_id_l_P Ξ a vforall (Ξ : t_ctx) (a b : ty0) (t1 : term Ξ (a β b)), t_ren_id_l_P Ξ (a β b) t1 -> forall t2 : term Ξ a, t_ren_id_l_P Ξ a t2 -> t_ren_id_l_P Ξ b (App t1 t2)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β + a), v_ren_id_l_P Ξ a (Var i)forall Ξ : t_ctx, v_ren_id_l_P Ξ ΞΉ TTforall (Ξ : t_ctx) (a b : ty0) (t : term (Ξ βΆβ + (a β b) βΆβ + a) b), t_ren_id_l_P (Ξ βΆβ + (a β b) βΆβ + a) b t -> v_ren_id_l_P Ξ (a β b) (Lam t)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β Β¬ a), e_ren_id_l_P Ξ a (K0 i)forall (Ξ : t_ctx) (a b : ty0) (t : term Ξ (a β b)), t_ren_id_l_P Ξ (a β b) t -> forall Ο : ev_ctx Ξ b, e_ren_id_l_P Ξ b Ο -> e_ren_id_l_P Ξ a (K1 t Ο)forall (Ξ : t_ctx) (a b : ty0) (v : val Ξ a), v_ren_id_l_P Ξ a v -> forall Ο : ev_ctx Ξ b, e_ren_id_l_P Ξ b Ο -> e_ren_id_l_P Ξ (a β b) (K2 v Ο)forall (Ξ : t_ctx) (a : ty0) (v : val Ξ a), v α΅₯βα΅£ r_id = v -> v ββα΅£ r_id = vforall (Ξ : t_ctx) (a b : ty0) (t1 : term Ξ (a β b)), t1 ββα΅£ r_id = t1 -> forall t2 : term Ξ a, t2 ββα΅£ r_id = t2 -> App t1 t2 ββα΅£ r_id = App t1 t2forall (Ξ : t_ctx) (a : ty0) (i : Ξ β + a), Var i α΅₯βα΅£ r_id = Var iforall Ξ : t_ctx, TT α΅₯βα΅£ r_id = TTforall (Ξ : t_ctx) (a b : ty0) (t : term (Ξ βΆβ + (a β b) βΆβ + a) b), t ββα΅£ r_id = t -> Lam t α΅₯βα΅£ r_id = Lam tforall (Ξ : t_ctx) (a : ty0) (i : Ξ β Β¬ a), K0 i ββα΅£ r_id = K0 iforall (Ξ : t_ctx) (a b : ty0) (t : term Ξ (a β b)), t ββα΅£ r_id = t -> forall Ο : ev_ctx Ξ b, Ο ββα΅£ r_id = Ο -> K1 t Ο ββα΅£ r_id = K1 t Οforall (Ξ : t_ctx) (a b : ty0) (v : val Ξ a), v α΅₯βα΅£ r_id = v -> forall Ο : ev_ctx Ξ b, Ο ββα΅£ r_id = Ο -> K2 v Ο ββα΅£ r_id = K2 v ΟΞ: t_ctx
a, b: ty0
t: term (Ξ βΆβ + (a β b) βΆβ + a) b
H: t ββα΅£ r_id = tt ββα΅£ r_shift2 r_id = tintros ? v; now do 2 (dependent elimination v; eauto). Qed.Ξ: t_ctx
a, b: ty0
t: term (Ξ βΆβ + (a β b) βΆβ + a) b
H: t ββα΅£ r_id = tr_shift2 r_id β‘β r_idnow apply (term_ind_mut _ _ _ ren_id_l_prf). Qed.Ξ: t_ctx
a: ty0
t: term Ξ at ββα΅£ r_id = tnow apply (val_ind_mut _ _ _ ren_id_l_prf). Qed.Ξ: t_ctx
a: ty0
v: val Ξ av α΅₯βα΅£ r_id = vnow apply (ctx_ind_mut _ _ _ ren_id_l_prf). Qed.Ξ: t_ctx
a: ty0
Ο: ev_ctx Ξ aΟ ββα΅£ r_id = Οdestruct a; [ now apply v_ren_id_l | now apply e_ren_id_l ]. Qed.Ξ: t_ctx
a: ty
v: val_m Ξ av ββα΅£ r_id = vdestruct s; apply (f_equal2 Cut); [ now apply t_ren_id_l | now apply e_ren_id_l ]. Qed.Ξ: t_ctx
s: state Ξs ββα΅£ r_id = s
Lemma 4: right identity law of renaming. This one basically holds definitionally, it only needs a case split for some of the derived notions. We will also prove a consequence on weakenings: identity law.
now destruct a. Qed.Ξ, Ξ: ctx ty
f: Ξ β Ξ
a: ty
i: Ξ β aa_id a i ββα΅£ f = a_id a (f a i)intros ??; now apply m_ren_id_r. Qed.Ξ, Ξ: ctx ty
f: Ξ β Ξa_id βα΅£ f β‘β f α΅£β a_idΞ: t_ctx
x, y: tya_shift2 a_id β‘β a_idexact (m_ren_id_r _ _). Qed.Ξ1: ctx ty
y, y0, a: ty
v: var a Ξ1a_shift2 a_id a (pop (pop v)) = a_id a (pop (pop v))
Lemma 5: shifting assigments commutes with left and right renaming.
intros ? v; do 2 (dependent elimination v; auto). Qed.Ξ1, Ξ2: ctx ty
Ξ3: t_ctx
a, b: ty
f1: Ξ1 β Ξ2
f2: Ξ2 =[ val_m ]> Ξ3a_shift2 (f1 α΅£β f2) β‘β r_shift2 f1 α΅£β a_shift2 f2Ξ1, Ξ2, Ξ3: t_ctx
a, b: ty
f1: Ξ1 =[ val_m ]> Ξ2
f2: Ξ2 β Ξ3a_shift2 (f1 βα΅£ f2) β‘β a_shift2 f1 βα΅£ r_shift2 f2Ξ1, Ξ2, Ξ3: t_ctx
a, b: ty
f1: Ξ1 =[ val_m ]> Ξ2
f2: Ξ2 β Ξ3
a0: ty
v: Ξ1 βΆβ a βΆβ b β a0a_shift2 (f1 βα΅£ f2) a0 v = (a_shift2 f1 βα΅£ r_shift2 f2)%asgn a0 vunfold a_ren; cbn - [ m_rename ]; unfold m_shift2; now rewrite 2 m_ren_ren. Qed.Ξ0: ctx ty
Ξ2, Ξ3: t_ctx
y0, y: ty
f1: Ξ0 =[ val_m ]> Ξ2
f2: Ξ2 β Ξ3
a0: ty
v: var a0 Ξ0m_shift2 a0 ((f1 βα΅£ f2)%asgn a0 v) = (a_shift2 f1 βα΅£ r_shift2 f2)%asgn a0 (pop (pop v))
Lemma 6: substitution respects pointwise equality of assigments.
Definition t_sub_proper_P Ξ a (t : term Ξ a) : Prop := forall Ξ (f1 f2 : Ξ =[val_m]> Ξ), f1 β‘β f2 -> t `ββ f1 = t `ββ f2 . Definition v_sub_proper_P Ξ a (v : val Ξ a) : Prop := forall Ξ (f1 f2 : Ξ =[val_m]> Ξ), f1 β‘β f2 -> v `α΅₯β f1 = v `α΅₯β f2 . Definition e_sub_proper_P Ξ a (Ο : ev_ctx Ξ a) : Prop := forall Ξ (f1 f2 : Ξ =[val_m]> Ξ), f1 β‘β f2 -> Ο `ββ f1 = Ο `ββ f2.syn_ind_args t_sub_proper_P v_sub_proper_P e_sub_proper_Pforall (Ξ : t_ctx) (a : ty0) (v : val Ξ a), v_sub_proper_P Ξ a v -> t_sub_proper_P Ξ a vforall (Ξ : t_ctx) (a b : ty0) (t1 : term Ξ (a β b)), t_sub_proper_P Ξ (a β b) t1 -> forall t2 : term Ξ a, t_sub_proper_P Ξ a t2 -> t_sub_proper_P Ξ b (App t1 t2)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β + a), v_sub_proper_P Ξ a (Var i)forall Ξ : t_ctx, v_sub_proper_P Ξ ΞΉ TTforall (Ξ : t_ctx) (a b : ty0) (t : term (Ξ βΆβ + (a β b) βΆβ + a) b), t_sub_proper_P (Ξ βΆβ + (a β b) βΆβ + a) b t -> v_sub_proper_P Ξ (a β b) (Lam t)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β Β¬ a), e_sub_proper_P Ξ a (K0 i)forall (Ξ : t_ctx) (a b : ty0) (t : term Ξ (a β b)), t_sub_proper_P Ξ (a β b) t -> forall Ο : ev_ctx Ξ b, e_sub_proper_P Ξ b Ο -> e_sub_proper_P Ξ a (K1 t Ο)forall (Ξ : t_ctx) (a b : ty0) (v : val Ξ a), v_sub_proper_P Ξ a v -> forall Ο : ev_ctx Ξ b, e_sub_proper_P Ξ b Ο -> e_sub_proper_P Ξ (a β b) (K2 v Ο)forall (Ξ : t_ctx) (a : ty0) (v : val Ξ a), (forall (Ξ : t_ctx) (f1 f2 : Ξ =[ val_m ]> Ξ), f1 β‘β f2 -> v `α΅₯β f1 = v `α΅₯β f2) -> forall (Ξ : t_ctx) (f1 f2 : Ξ =[ val_m ]> Ξ), f1 β‘β f2 -> v `ββ f1 = v `ββ f2forall (Ξ : t_ctx) (a b : ty0) (t1 : term Ξ (a β b)), (forall (Ξ : t_ctx) (f1 f2 : Ξ =[ val_m ]> Ξ), f1 β‘β f2 -> t1 `ββ f1 = t1 `ββ f2) -> forall t2 : term Ξ a, (forall (Ξ : t_ctx) (f1 f2 : Ξ =[ val_m ]> Ξ), f1 β‘β f2 -> t2 `ββ f1 = t2 `ββ f2) -> forall (Ξ : t_ctx) (f1 f2 : Ξ =[ val_m ]> Ξ), f1 β‘β f2 -> App t1 t2 `ββ f1 = App t1 t2 `ββ f2forall (Ξ : t_ctx) (a : ty0) (i : Ξ β + a) (Ξ : t_ctx) (f1 f2 : Ξ =[ val_m ]> Ξ), f1 β‘β f2 -> Var i `α΅₯β f1 = Var i `α΅₯β f2forall (Ξ Ξ : t_ctx) (f1 f2 : Ξ =[ val_m ]> Ξ), f1 β‘β f2 -> TT `α΅₯β f1 = TT `α΅₯β f2forall (Ξ : t_ctx) (a b : ty0) (t : term (Ξ βΆβ + (a β b) βΆβ + a) b), (forall (Ξ : t_ctx) (f1 f2 : (Ξ βΆβ + (a β b) βΆβ + a) =[ val_m ]> Ξ), f1 β‘β f2 -> t `ββ f1 = t `ββ f2) -> forall (Ξ : t_ctx) (f1 f2 : Ξ =[ val_m ]> Ξ), f1 β‘β f2 -> Lam t `α΅₯β f1 = Lam t `α΅₯β f2forall (Ξ : t_ctx) (a : ty0) (i : Ξ β Β¬ a) (Ξ : t_ctx) (f1 f2 : Ξ =[ val_m ]> Ξ), f1 β‘β f2 -> K0 i `ββ f1 = K0 i `ββ f2forall (Ξ : t_ctx) (a b : ty0) (t : term Ξ (a β b)), (forall (Ξ : t_ctx) (f1 f2 : Ξ =[ val_m ]> Ξ), f1 β‘β f2 -> t `ββ f1 = t `ββ f2) -> forall Ο : ev_ctx Ξ b, (forall (Ξ : t_ctx) (f1 f2 : Ξ =[ val_m ]> Ξ), f1 β‘β f2 -> Ο `ββ f1 = Ο `ββ f2) -> forall (Ξ : t_ctx) (f1 f2 : Ξ =[ val_m ]> Ξ), f1 β‘β f2 -> K1 t Ο `ββ f1 = K1 t Ο `ββ f2forall (Ξ : t_ctx) (a b : ty0) (v : val Ξ a), (forall (Ξ : t_ctx) (f1 f2 : Ξ =[ val_m ]> Ξ), f1 β‘β f2 -> v `α΅₯β f1 = v `α΅₯β f2) -> forall Ο : ev_ctx Ξ b, (forall (Ξ : t_ctx) (f1 f2 : Ξ =[ val_m ]> Ξ), f1 β‘β f2 -> Ο `ββ f1 = Ο `ββ f2) -> forall (Ξ : t_ctx) (f1 f2 : Ξ =[ val_m ]> Ξ), f1 β‘β f2 -> K2 v Ο `ββ f1 = K2 v Ο `ββ f2now apply H, a_shift2_eq. Qed.Ξ: t_ctx
a, b: ty0
t: term (Ξ βΆβ + (a β b) βΆβ + a) b
H: forall (Ξ : t_ctx) (f1 f2 : (Ξ βΆβ + (a β b) βΆβ + a) =[ val_m ]> Ξ), f1 β‘β f2 -> t `ββ f1 = t `ββ f2
Ξ: t_ctx
f1, f2: Ξ =[ val_m ]> Ξ
H0: f1 β‘β f2t `ββ a_shift2 f1 = t `ββ a_shift2 f2intros ? ? H1 a _ ? ->; now apply (term_ind_mut _ _ _ sub_proper_prf). Qed.Ξ, Ξ: t_ctxProper (asgn_eq Ξ Ξ ==> (ββ a, eq ==> eq)) t_substintros ? ? H1 a _ ? ->; now apply (val_ind_mut _ _ _ sub_proper_prf). Qed.Ξ, Ξ: t_ctxProper (asgn_eq Ξ Ξ ==> (ββ a, eq ==> eq)) v_substintros ? ? H1 a _ ? ->; now apply (ctx_ind_mut _ _ _ sub_proper_prf). Qed.Ξ, Ξ: t_ctxProper (asgn_eq Ξ Ξ ==> (ββ a, eq ==> eq)) e_substintros ? [] ?? -> ??? H1; cbn in *; now rewrite H1. Qed.Proper (ββ Ξ, (ββ a, eq ==> (ββ Ξ, asgn_eq Ξ Ξ ==> eq))) m_substintros ??[] -> ??? H1; cbn; now rewrite H1. Qed. (* #[global] Instance a_comp_eq {Ξ1 Ξ2 Ξ3} : Proper (ass_eq _ _ ==> ass_eq _ _ ==> ass_eq _ _) (@a_comp Ξ1 Ξ2 Ξ3). intros ? ? H1 ? ? H2 ? ?; unfold a_comp, s_map; now rewrite H1, H2. Qed. *)Proper (ββ Ξ, eq ==> (ββ Ξ, asgn_eq Ξ Ξ ==> eq)) s_subst
Lemma 7: renaming-substitution "associativity".
Definition t_ren_sub_P Ξ1 a (t : term Ξ1 a) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 =[val_m]> Ξ2) (f2 : Ξ2 β Ξ3) , (t `ββ f1) ββα΅£ f2 = t `ββ (f1 βα΅£ f2) . Definition v_ren_sub_P Ξ1 a (v : val Ξ1 a) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 =[val_m]> Ξ2) (f2 : Ξ2 β Ξ3) , (v `α΅₯β f1) α΅₯βα΅£ f2 = v `α΅₯β (f1 βα΅£ f2) . Definition e_ren_sub_P Ξ1 a (Ο : ev_ctx Ξ1 a) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 =[val_m]> Ξ2) (f2 : Ξ2 β Ξ3) , (Ο `ββ f1) ββα΅£ f2 = Ο `ββ (f1 βα΅£ f2) .syn_ind_args t_ren_sub_P v_ren_sub_P e_ren_sub_Pforall (Ξ : t_ctx) (a : ty0) (v : val Ξ a), v_ren_sub_P Ξ a v -> t_ren_sub_P Ξ a vforall (Ξ : t_ctx) (a b : ty0) (t1 : term Ξ (a β b)), t_ren_sub_P Ξ (a β b) t1 -> forall t2 : term Ξ a, t_ren_sub_P Ξ a t2 -> t_ren_sub_P Ξ b (App t1 t2)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β + a), v_ren_sub_P Ξ a (Var i)forall Ξ : t_ctx, v_ren_sub_P Ξ ΞΉ TTforall (Ξ : t_ctx) (a b : ty0) (t : term (Ξ βΆβ + (a β b) βΆβ + a) b), t_ren_sub_P (Ξ βΆβ + (a β b) βΆβ + a) b t -> v_ren_sub_P Ξ (a β b) (Lam t)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β Β¬ a), e_ren_sub_P Ξ a (K0 i)forall (Ξ : t_ctx) (a b : ty0) (t : term Ξ (a β b)), t_ren_sub_P Ξ (a β b) t -> forall Ο : ev_ctx Ξ b, e_ren_sub_P Ξ b Ο -> e_ren_sub_P Ξ a (K1 t Ο)forall (Ξ : t_ctx) (a b : ty0) (v : val Ξ a), v_ren_sub_P Ξ a v -> forall Ο : ev_ctx Ξ b, e_ren_sub_P Ξ b Ο -> e_ren_sub_P Ξ (a β b) (K2 v Ο)forall (Ξ : t_ctx) (a : ty0) (v : val Ξ a), (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (v `α΅₯β f1) α΅₯βα΅£ f2 = v `α΅₯β f1 βα΅£ f2) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (v `ββ f1) ββα΅£ f2 = v `ββ f1 βα΅£ f2forall (Ξ : t_ctx) (a b : ty0) (t1 : term Ξ (a β b)), (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (t1 `ββ f1) ββα΅£ f2 = t1 `ββ f1 βα΅£ f2) -> forall t2 : term Ξ a, (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (t2 `ββ f1) ββα΅£ f2 = t2 `ββ f1 βα΅£ f2) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (App t1 t2 `ββ f1) ββα΅£ f2 = App t1 t2 `ββ f1 βα΅£ f2forall (Ξ : t_ctx) (a : ty0) (i : Ξ β + a) (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (Var i `α΅₯β f1) α΅₯βα΅£ f2 = Var i `α΅₯β f1 βα΅£ f2forall (Ξ Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (TT `α΅₯β f1) α΅₯βα΅£ f2 = TT `α΅₯β f1 βα΅£ f2forall (Ξ : t_ctx) (a b : ty0) (t : term (Ξ βΆβ + (a β b) βΆβ + a) b), (forall (Ξ2 Ξ3 : t_ctx) (f1 : (Ξ βΆβ + (a β b) βΆβ + a) =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (t `ββ f1) ββα΅£ f2 = t `ββ f1 βα΅£ f2) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (Lam t `α΅₯β f1) α΅₯βα΅£ f2 = Lam t `α΅₯β f1 βα΅£ f2forall (Ξ : t_ctx) (a : ty0) (i : Ξ β Β¬ a) (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (K0 i `ββ f1) ββα΅£ f2 = K0 i `ββ f1 βα΅£ f2forall (Ξ : t_ctx) (a b : ty0) (t : term Ξ (a β b)), (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (t `ββ f1) ββα΅£ f2 = t `ββ f1 βα΅£ f2) -> forall Ο : ev_ctx Ξ b, (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (Ο `ββ f1) ββα΅£ f2 = Ο `ββ f1 βα΅£ f2) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (K1 t Ο `ββ f1) ββα΅£ f2 = K1 t Ο `ββ f1 βα΅£ f2forall (Ξ : t_ctx) (a b : ty0) (v : val Ξ a), (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (v `α΅₯β f1) α΅₯βα΅£ f2 = v `α΅₯β f1 βα΅£ f2) -> forall Ο : ev_ctx Ξ b, (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (Ο `ββ f1) ββα΅£ f2 = Ο `ββ f1 βα΅£ f2) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (K2 v Ο `ββ f1) ββα΅£ f2 = K2 v Ο `ββ f1 βα΅£ f2all: try rewrite a_shift2_a_ren; auto. Qed.Ξ: t_ctx
a: ty0
v: val Ξ a
H: forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (v `α΅₯β f1) α΅₯βα΅£ f2 = v `α΅₯β f1 βα΅£ f2
Ξ2, Ξ3: t_ctx
f1: Ξ =[ val_m ]> Ξ2
f2: Ξ2 β Ξ3(v `α΅₯β f1) α΅₯βα΅£ f2 = v `α΅₯β f1 βα΅£ f2Ξ: t_ctx
a, b: ty0
t1: term Ξ (a β b)
H: forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (t1 `ββ f1) ββα΅£ f2 = t1 `ββ f1 βα΅£ f2
t2: term Ξ a
H0: forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (t2 `ββ f1) ββα΅£ f2 = t2 `ββ f1 βα΅£ f2
Ξ2, Ξ3: t_ctx
f1: Ξ =[ val_m ]> Ξ2
f2: Ξ2 β Ξ3(t1 `ββ f1) ββα΅£ f2 = t1 `ββ f1 βα΅£ f2Ξ: t_ctx
a, b: ty0
t1: term Ξ (a β b)
H: forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (t1 `ββ f1) ββα΅£ f2 = t1 `ββ f1 βα΅£ f2
t2: term Ξ a
H0: forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (t2 `ββ f1) ββα΅£ f2 = t2 `ββ f1 βα΅£ f2
Ξ2, Ξ3: t_ctx
f1: Ξ =[ val_m ]> Ξ2
f2: Ξ2 β Ξ3(t2 `ββ f1) ββα΅£ f2 = t2 `ββ f1 βα΅£ f2Ξ: t_ctx
a, b: ty0
t: term (Ξ βΆβ + (a β b) βΆβ + a) b
H: forall (Ξ2 Ξ3 : t_ctx) (f1 : (Ξ βΆβ + (a β b) βΆβ + a) =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (t `ββ f1) ββα΅£ f2 = t `ββ f1 βα΅£ f2
Ξ2, Ξ3: t_ctx
f1: Ξ =[ val_m ]> Ξ2
f2: Ξ2 β Ξ3(t `ββ a_shift2 f1) ββα΅£ r_shift2 f2 = t `ββ a_shift2 (f1 βα΅£ f2)Ξ: t_ctx
a, b: ty0
t: term Ξ (a β b)
H: forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (t `ββ f1) ββα΅£ f2 = t `ββ f1 βα΅£ f2
Ο: ev_ctx Ξ b
H0: forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (Ο `ββ f1) ββα΅£ f2 = Ο `ββ f1 βα΅£ f2
Ξ2, Ξ3: t_ctx
f1: Ξ =[ val_m ]> Ξ2
f2: Ξ2 β Ξ3(t `ββ f1) ββα΅£ f2 = t `ββ f1 βα΅£ f2Ξ: t_ctx
a, b: ty0
t: term Ξ (a β b)
H: forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (t `ββ f1) ββα΅£ f2 = t `ββ f1 βα΅£ f2
Ο: ev_ctx Ξ b
H0: forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (Ο `ββ f1) ββα΅£ f2 = Ο `ββ f1 βα΅£ f2
Ξ2, Ξ3: t_ctx
f1: Ξ =[ val_m ]> Ξ2
f2: Ξ2 β Ξ3(Ο `ββ f1) ββα΅£ f2 = Ο `ββ f1 βα΅£ f2Ξ: t_ctx
a, b: ty0
v: val Ξ a
H: forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (v `α΅₯β f1) α΅₯βα΅£ f2 = v `α΅₯β f1 βα΅£ f2
Ο: ev_ctx Ξ b
H0: forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (Ο `ββ f1) ββα΅£ f2 = Ο `ββ f1 βα΅£ f2
Ξ2, Ξ3: t_ctx
f1: Ξ =[ val_m ]> Ξ2
f2: Ξ2 β Ξ3(v `α΅₯β f1) α΅₯βα΅£ f2 = v `α΅₯β f1 βα΅£ f2Ξ: t_ctx
a, b: ty0
v: val Ξ a
H: forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (v `α΅₯β f1) α΅₯βα΅£ f2 = v `α΅₯β f1 βα΅£ f2
Ο: ev_ctx Ξ b
H0: forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 β Ξ3), (Ο `ββ f1) ββα΅£ f2 = Ο `ββ f1 βα΅£ f2
Ξ2, Ξ3: t_ctx
f1: Ξ =[ val_m ]> Ξ2
f2: Ξ2 β Ξ3(Ο `ββ f1) ββα΅£ f2 = Ο `ββ f1 βα΅£ f2now apply (term_ind_mut _ _ _ ren_sub_prf). Qed.Ξ1, Ξ2, Ξ3: t_ctx
f1: Ξ1 =[ val_m ]> Ξ2
f2: Ξ2 β Ξ3
a: ty0
t: term Ξ1 a(t `ββ f1) ββα΅£ f2 = t `ββ f1 βα΅£ f2now apply (val_ind_mut _ _ _ ren_sub_prf). Qed.Ξ1, Ξ2, Ξ3: t_ctx
f1: Ξ1 =[ val_m ]> Ξ2
f2: Ξ2 β Ξ3
a: ty0
v: val Ξ1 a(v `α΅₯β f1) α΅₯βα΅£ f2 = v `α΅₯β f1 βα΅£ f2now apply (ctx_ind_mut _ _ _ ren_sub_prf). Qed.Ξ1, Ξ2, Ξ3: t_ctx
f1: Ξ1 =[ val_m ]> Ξ2
f2: Ξ2 β Ξ3
a: ty0
Ο: ev_ctx Ξ1 a(Ο `ββ f1) ββα΅£ f2 = Ο `ββ f1 βα΅£ f2destruct a; [ now apply v_ren_sub | now apply e_ren_sub ]. Qed.Ξ1, Ξ2, Ξ3: t_ctx
f1: Ξ1 =[ val_m ]> Ξ2
f2: Ξ2 β Ξ3
a: ty
v: val_m Ξ1 a(v α΅₯β f1) ββα΅£ f2 = v α΅₯β f1 βα΅£ f2destruct s; cbn; now rewrite t_ren_sub, e_ren_sub. Qed.Ξ1, Ξ2, Ξ3: t_ctx
f1: Ξ1 =[ val_m ]> Ξ2
f2: Ξ2 β Ξ3
s: state Ξ1(s ββ f1) ββα΅£ f2 = s ββ f1 βα΅£ f2
Lemma 8: substitution-renaming "associativity".
Definition t_sub_ren_P Ξ1 a (t : term Ξ1 a) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 β Ξ2) (f2 : Ξ2 =[val_m]> Ξ3) , (t ββα΅£ f1) `ββ f2 = t `ββ (f1 α΅£β f2) . Definition v_sub_ren_P Ξ1 a (v : val Ξ1 a) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 β Ξ2) (f2 : Ξ2 =[val_m]> Ξ3) , (v α΅₯βα΅£ f1) `α΅₯β f2 = v `α΅₯β (f1 α΅£β f2) . Definition e_sub_ren_P Ξ1 a (Ο : ev_ctx Ξ1 a) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 β Ξ2) (f2 : Ξ2 =[val_m]> Ξ3) , (Ο ββα΅£ f1) `ββ f2 = Ο `ββ (f1 α΅£β f2) .syn_ind_args t_sub_ren_P v_sub_ren_P e_sub_ren_Pforall (Ξ : t_ctx) (a : ty0) (v : val Ξ a), v_sub_ren_P Ξ a v -> t_sub_ren_P Ξ a vforall (Ξ : t_ctx) (a b : ty0) (t1 : term Ξ (a β b)), t_sub_ren_P Ξ (a β b) t1 -> forall t2 : term Ξ a, t_sub_ren_P Ξ a t2 -> t_sub_ren_P Ξ b (App t1 t2)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β + a), v_sub_ren_P Ξ a (Var i)forall Ξ : t_ctx, v_sub_ren_P Ξ ΞΉ TTforall (Ξ : t_ctx) (a b : ty0) (t : term (Ξ βΆβ + (a β b) βΆβ + a) b), t_sub_ren_P (Ξ βΆβ + (a β b) βΆβ + a) b t -> v_sub_ren_P Ξ (a β b) (Lam t)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β Β¬ a), e_sub_ren_P Ξ a (K0 i)forall (Ξ : t_ctx) (a b : ty0) (t : term Ξ (a β b)), t_sub_ren_P Ξ (a β b) t -> forall Ο : ev_ctx Ξ b, e_sub_ren_P Ξ b Ο -> e_sub_ren_P Ξ a (K1 t Ο)forall (Ξ : t_ctx) (a b : ty0) (v : val Ξ a), v_sub_ren_P Ξ a v -> forall Ο : ev_ctx Ξ b, e_sub_ren_P Ξ b Ο -> e_sub_ren_P Ξ (a β b) (K2 v Ο)forall (Ξ : t_ctx) (a : ty0) (v : val Ξ a), (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), v α΅₯βα΅£ f1 `α΅₯β f2 = v `α΅₯β f1 α΅£β f2) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), v ββα΅£ f1 `ββ f2 = v `ββ f1 α΅£β f2forall (Ξ : t_ctx) (a b : ty0) (t1 : term Ξ (a β b)), (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), t1 ββα΅£ f1 `ββ f2 = t1 `ββ f1 α΅£β f2) -> forall t2 : term Ξ a, (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), t2 ββα΅£ f1 `ββ f2 = t2 `ββ f1 α΅£β f2) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), App t1 t2 ββα΅£ f1 `ββ f2 = App t1 t2 `ββ f1 α΅£β f2forall (Ξ : t_ctx) (a : ty0) (i : Ξ β + a) (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), Var i α΅₯βα΅£ f1 `α΅₯β f2 = Var i `α΅₯β f1 α΅£β f2forall (Ξ Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), TT α΅₯βα΅£ f1 `α΅₯β f2 = TT `α΅₯β f1 α΅£β f2forall (Ξ : t_ctx) (a b : ty0) (t : term (Ξ βΆβ + (a β b) βΆβ + a) b), (forall (Ξ2 Ξ3 : t_ctx) (f1 : (Ξ βΆβ + (a β b) βΆβ + a) β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), t ββα΅£ f1 `ββ f2 = t `ββ f1 α΅£β f2) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), Lam t α΅₯βα΅£ f1 `α΅₯β f2 = Lam t `α΅₯β f1 α΅£β f2forall (Ξ : t_ctx) (a : ty0) (i : Ξ β Β¬ a) (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), K0 i ββα΅£ f1 `ββ f2 = K0 i `ββ f1 α΅£β f2forall (Ξ : t_ctx) (a b : ty0) (t : term Ξ (a β b)), (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), t ββα΅£ f1 `ββ f2 = t `ββ f1 α΅£β f2) -> forall Ο : ev_ctx Ξ b, (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), Ο ββα΅£ f1 `ββ f2 = Ο `ββ f1 α΅£β f2) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), K1 t Ο ββα΅£ f1 `ββ f2 = K1 t Ο `ββ f1 α΅£β f2forall (Ξ : t_ctx) (a b : ty0) (v : val Ξ a), (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), v α΅₯βα΅£ f1 `α΅₯β f2 = v `α΅₯β f1 α΅£β f2) -> forall Ο : ev_ctx Ξ b, (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), Ο ββα΅£ f1 `ββ f2 = Ο `ββ f1 α΅£β f2) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), K2 v Ο ββα΅£ f1 `ββ f2 = K2 v Ο `ββ f1 α΅£β f2now rewrite a_shift2_s_ren. Qed.Ξ: t_ctx
a, b: ty0
t: term (Ξ βΆβ + (a β b) βΆβ + a) b
H: forall (Ξ2 Ξ3 : t_ctx) (f1 : (Ξ βΆβ + (a β b) βΆβ + a) β Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), t ββα΅£ f1 `ββ f2 = t `ββ f1 α΅£β f2
Ξ2, Ξ3: t_ctx
f1: Ξ β Ξ2
f2: Ξ2 =[ val_m ]> Ξ3t ββα΅£ r_shift2 f1 `ββ a_shift2 f2 = t `ββ a_shift2 (f1 α΅£β f2)now apply (term_ind_mut _ _ _ sub_ren_prf). Qed.Ξ1, Ξ2: ctx ty
Ξ3: t_ctx
f1: Ξ1 β Ξ2
f2: Ξ2 =[ val_m ]> Ξ3
a: ty0
t: term Ξ1 at ββα΅£ f1 `ββ f2 = t `ββ f1 α΅£β f2now apply (val_ind_mut _ _ _ sub_ren_prf). Qed.Ξ1, Ξ2: ctx ty
Ξ3: t_ctx
f1: Ξ1 β Ξ2
f2: Ξ2 =[ val_m ]> Ξ3
a: ty0
v: val Ξ1 av α΅₯βα΅£ f1 `α΅₯β f2 = v `α΅₯β f1 α΅£β f2now apply (ctx_ind_mut _ _ _ sub_ren_prf). Qed.Ξ1, Ξ2: ctx ty
Ξ3: t_ctx
f1: Ξ1 β Ξ2
f2: Ξ2 =[ val_m ]> Ξ3
a: ty0
Ο: ev_ctx Ξ1 aΟ ββα΅£ f1 `ββ f2 = Ο `ββ f1 α΅£β f2destruct a; [ now apply v_sub_ren | now apply e_sub_ren ]. Qed.Ξ1, Ξ2: ctx ty
Ξ3: t_ctx
f1: Ξ1 β Ξ2
f2: Ξ2 =[ val_m ]> Ξ3
a: ty
v: val_m Ξ1 av ββα΅£ f1 α΅₯β f2 = v α΅₯β f1 α΅£β f2destruct s; cbn; now rewrite t_sub_ren, e_sub_ren. Qed.Ξ1, Ξ2: ctx ty
Ξ3: t_ctx
f1: Ξ1 β Ξ2
f2: Ξ2 =[ val_m ]> Ξ3
s: state Ξ1s ββα΅£ f1 ββ f2 = s ββ f1 α΅£β f2
Lemma 9: left identity law of substitution.
Definition t_sub_id_l_P Ξ a (t : term Ξ a) : Prop := t `ββ a_id = t . Definition v_sub_id_l_P Ξ a (v : val Ξ a) : Prop := v `α΅₯β a_id = v . Definition e_sub_id_l_P Ξ a (Ο : ev_ctx Ξ a) : Prop := Ο `ββ a_id = Ο .syn_ind_args t_sub_id_l_P v_sub_id_l_P e_sub_id_l_Pforall (Ξ : t_ctx) (a : ty0) (v : val Ξ a), v_sub_id_l_P Ξ a v -> t_sub_id_l_P Ξ a vforall (Ξ : t_ctx) (a b : ty0) (t1 : term Ξ (a β b)), t_sub_id_l_P Ξ (a β b) t1 -> forall t2 : term Ξ a, t_sub_id_l_P Ξ a t2 -> t_sub_id_l_P Ξ b (App t1 t2)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β + a), v_sub_id_l_P Ξ a (Var i)forall Ξ : t_ctx, v_sub_id_l_P Ξ ΞΉ TTforall (Ξ : t_ctx) (a b : ty0) (t : term (Ξ βΆβ + (a β b) βΆβ + a) b), t_sub_id_l_P (Ξ βΆβ + (a β b) βΆβ + a) b t -> v_sub_id_l_P Ξ (a β b) (Lam t)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β Β¬ a), e_sub_id_l_P Ξ a (K0 i)forall (Ξ : t_ctx) (a b : ty0) (t : term Ξ (a β b)), t_sub_id_l_P Ξ (a β b) t -> forall Ο : ev_ctx Ξ b, e_sub_id_l_P Ξ b Ο -> e_sub_id_l_P Ξ a (K1 t Ο)forall (Ξ : t_ctx) (a b : ty0) (v : val Ξ a), v_sub_id_l_P Ξ a v -> forall Ο : ev_ctx Ξ b, e_sub_id_l_P Ξ b Ο -> e_sub_id_l_P Ξ (a β b) (K2 v Ο)forall (Ξ : t_ctx) (a : ty0) (v : val Ξ a), v `α΅₯β a_id = v -> v `ββ a_id = vforall (Ξ : t_ctx) (a b : ty0) (t1 : term Ξ (a β b)), t1 `ββ a_id = t1 -> forall t2 : term Ξ a, t2 `ββ a_id = t2 -> App t1 t2 `ββ a_id = App t1 t2forall (Ξ : t_ctx) (a : ty0) (i : Ξ β + a), Var i `α΅₯β a_id = Var iforall Ξ : t_ctx, TT `α΅₯β a_id = TTforall (Ξ : t_ctx) (a b : ty0) (t : term (Ξ βΆβ + (a β b) βΆβ + a) b), t `ββ a_id = t -> Lam t `α΅₯β a_id = Lam tforall (Ξ : t_ctx) (a : ty0) (i : Ξ β Β¬ a), K0 i `ββ a_id = K0 iforall (Ξ : t_ctx) (a b : ty0) (t : term Ξ (a β b)), t `ββ a_id = t -> forall Ο : ev_ctx Ξ b, Ο `ββ a_id = Ο -> K1 t Ο `ββ a_id = K1 t Οforall (Ξ : t_ctx) (a b : ty0) (v : val Ξ a), v `α΅₯β a_id = v -> forall Ο : ev_ctx Ξ b, Ο `ββ a_id = Ο -> K2 v Ο `ββ a_id = K2 v Οnow rewrite a_shift2_id. Qed.Ξ: t_ctx
a, b: ty0
t: term (Ξ βΆβ + (a β b) βΆβ + a) b
H: t `ββ a_id = tt `ββ a_shift2 a_id = tnow apply (term_ind_mut _ _ _ sub_id_l_prf). Qed.Ξ: t_ctx
a: ty0
t: term Ξ at `ββ a_id = tnow apply (val_ind_mut _ _ _ sub_id_l_prf). Qed.Ξ: t_ctx
a: ty0
v: val Ξ av `α΅₯β a_id = vnow apply (ctx_ind_mut _ _ _ sub_id_l_prf). Qed.Ξ: t_ctx
a: ty0
Ο: ev_ctx Ξ aΟ `ββ a_id = Οdestruct a; [ now apply v_sub_id_l | now apply e_sub_id_l ]. Qed.Ξ: t_ctx
a: ty
v: val_m Ξ av α΅₯β a_id = vdestruct s; cbn; now rewrite t_sub_id_l, e_sub_id_l. Qed.Ξ: t_ctx
s: state Ξs ββ a_id = s
Lemma 9: right identity law of substitution. As for renaming, this one is mostly by definition.
now destruct a. Qed.Ξ1: ctx ty
Ξ2: t_ctx
a: ty
i: Ξ1 β a
f: Ξ1 =[ val_m ]> Ξ2a_id a i α΅₯β f = f a i
Lemma 10: shifting assigments respects composition.
Ξ1, Ξ2, Ξ3: t_ctx
a, b: ty
f1: Ξ1 =[ val_m ]> Ξ2
f2: Ξ2 =[ val_m ]> Ξ3a_shift2 (f1 β f2) β‘β a_shift2 f1 β a_shift2 f2Ξ1, Ξ2, Ξ3: t_ctx
a, b: ty
f1: Ξ1 =[ val_m ]> Ξ2
f2: Ξ2 =[ val_m ]> Ξ3
a0: ty
v: Ξ1 βΆβ a βΆβ b β a0a_shift2 (f1 β f2) a0 v = (a_shift2 f1 β a_shift2 f2)%asgn a0 vcbn; unfold m_shift2; now rewrite m_ren_sub, m_sub_ren. Qed.Ξ0: ctx ty
Ξ2, Ξ3: t_ctx
y0, y: ty
f1: Ξ0 =[ val_m ]> Ξ2
f2: Ξ2 =[ val_m ]> Ξ3
a0: ty
v: var a0 Ξ0a_shift2 (f1 β f2) a0 (pop (pop v)) = (a_shift2 f1 β a_shift2 f2)%asgn a0 (pop (pop v))
Lemma 11: substitution-substitution associativity, ie composition law.
Definition t_sub_sub_P Ξ1 a (t : term Ξ1 a) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 =[val_m]> Ξ2) (f2 : Ξ2 =[val_m]> Ξ3) , t `ββ (f1 β f2) = (t `ββ f1) `ββ f2 . Definition v_sub_sub_P Ξ1 a (v : val Ξ1 a) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 =[val_m]> Ξ2) (f2 : Ξ2 =[val_m]> Ξ3) , v `α΅₯β (f1 β f2) = (v `α΅₯β f1) `α΅₯β f2 . Definition e_sub_sub_P Ξ1 a (Ο : ev_ctx Ξ1 a) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 =[val_m]> Ξ2) (f2 : Ξ2 =[val_m]> Ξ3) , Ο `ββ (f1 β f2) = (Ο `ββ f1) `ββ f2 .syn_ind_args t_sub_sub_P v_sub_sub_P e_sub_sub_Pforall (Ξ : t_ctx) (a : ty0) (v : val Ξ a), v_sub_sub_P Ξ a v -> t_sub_sub_P Ξ a vforall (Ξ : t_ctx) (a b : ty0) (t1 : term Ξ (a β b)), t_sub_sub_P Ξ (a β b) t1 -> forall t2 : term Ξ a, t_sub_sub_P Ξ a t2 -> t_sub_sub_P Ξ b (App t1 t2)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β + a), v_sub_sub_P Ξ a (Var i)forall Ξ : t_ctx, v_sub_sub_P Ξ ΞΉ TTforall (Ξ : t_ctx) (a b : ty0) (t : term (Ξ βΆβ + (a β b) βΆβ + a) b), t_sub_sub_P (Ξ βΆβ + (a β b) βΆβ + a) b t -> v_sub_sub_P Ξ (a β b) (Lam t)forall (Ξ : t_ctx) (a : ty0) (i : Ξ β Β¬ a), e_sub_sub_P Ξ a (K0 i)forall (Ξ : t_ctx) (a b : ty0) (t : term Ξ (a β b)), t_sub_sub_P Ξ (a β b) t -> forall Ο : ev_ctx Ξ b, e_sub_sub_P Ξ b Ο -> e_sub_sub_P Ξ a (K1 t Ο)forall (Ξ : t_ctx) (a b : ty0) (v : val Ξ a), v_sub_sub_P Ξ a v -> forall Ο : ev_ctx Ξ b, e_sub_sub_P Ξ b Ο -> e_sub_sub_P Ξ (a β b) (K2 v Ο)forall (Ξ : t_ctx) (a : ty0) (v : val Ξ a), (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), v `α΅₯β f1 β f2 = (v `α΅₯β f1) `α΅₯β f2) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), v `ββ f1 β f2 = (v `ββ f1) `ββ f2forall (Ξ : t_ctx) (a b : ty0) (t1 : term Ξ (a β b)), (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), t1 `ββ f1 β f2 = (t1 `ββ f1) `ββ f2) -> forall t2 : term Ξ a, (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), t2 `ββ f1 β f2 = (t2 `ββ f1) `ββ f2) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), App t1 t2 `ββ f1 β f2 = (App t1 t2 `ββ f1) `ββ f2forall (Ξ : t_ctx) (a : ty0) (i : Ξ β + a) (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), Var i `α΅₯β f1 β f2 = (Var i `α΅₯β f1) `α΅₯β f2forall (Ξ Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), TT `α΅₯β f1 β f2 = (TT `α΅₯β f1) `α΅₯β f2forall (Ξ : t_ctx) (a b : ty0) (t : term (Ξ βΆβ + (a β b) βΆβ + a) b), (forall (Ξ2 Ξ3 : t_ctx) (f1 : (Ξ βΆβ + (a β b) βΆβ + a) =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), t `ββ f1 β f2 = (t `ββ f1) `ββ f2) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), Lam t `α΅₯β f1 β f2 = (Lam t `α΅₯β f1) `α΅₯β f2forall (Ξ : t_ctx) (a : ty0) (i : Ξ β Β¬ a) (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), K0 i `ββ f1 β f2 = (K0 i `ββ f1) `ββ f2forall (Ξ : t_ctx) (a b : ty0) (t : term Ξ (a β b)), (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), t `ββ f1 β f2 = (t `ββ f1) `ββ f2) -> forall Ο : ev_ctx Ξ b, (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), Ο `ββ f1 β f2 = (Ο `ββ f1) `ββ f2) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), K1 t Ο `ββ f1 β f2 = (K1 t Ο `ββ f1) `ββ f2forall (Ξ : t_ctx) (a b : ty0) (v : val Ξ a), (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), v `α΅₯β f1 β f2 = (v `α΅₯β f1) `α΅₯β f2) -> forall Ο : ev_ctx Ξ b, (forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), Ο `ββ f1 β f2 = (Ο `ββ f1) `ββ f2) -> forall (Ξ2 Ξ3 : t_ctx) (f1 : Ξ =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), K2 v Ο `ββ f1 β f2 = (K2 v Ο `ββ f1) `ββ f2now rewrite a_shift2_comp. Qed.Ξ: t_ctx
a, b: ty0
t: term (Ξ βΆβ + (a β b) βΆβ + a) b
H: forall (Ξ2 Ξ3 : t_ctx) (f1 : (Ξ βΆβ + (a β b) βΆβ + a) =[ val_m ]> Ξ2) (f2 : Ξ2 =[ val_m ]> Ξ3), t `ββ f1 β f2 = (t `ββ f1) `ββ f2
Ξ2, Ξ3: t_ctx
f1: Ξ =[ val_m ]> Ξ2
f2: Ξ2 =[ val_m ]> Ξ3t `ββ a_shift2 (f1 β f2) = (t `ββ a_shift2 f1) `ββ a_shift2 f2now apply (term_ind_mut _ _ _ sub_sub_prf). Qed.Ξ1, Ξ2, Ξ3: t_ctx
f1: Ξ1 =[ val_m ]> Ξ2
f2: Ξ2 =[ val_m ]> Ξ3
a: ty0
t: term Ξ1 at `ββ f1 β f2 = (t `ββ f1) `ββ f2now apply (val_ind_mut _ _ _ sub_sub_prf). Qed.Ξ1, Ξ2, Ξ3: t_ctx
f1: Ξ1 =[ val_m ]> Ξ2
f2: Ξ2 =[ val_m ]> Ξ3
a: ty0
v: val Ξ1 av `α΅₯β f1 β f2 = (v `α΅₯β f1) `α΅₯β f2now apply (ctx_ind_mut _ _ _ sub_sub_prf). Qed.Ξ1, Ξ2, Ξ3: t_ctx
f1: Ξ1 =[ val_m ]> Ξ2
f2: Ξ2 =[ val_m ]> Ξ3
a: ty0
Ο: ev_ctx Ξ1 aΟ `ββ f1 β f2 = (Ο `ββ f1) `ββ f2destruct a; [ now apply v_sub_sub | now apply e_sub_sub ]. Qed.Ξ1, Ξ2, Ξ3: t_ctx
a: ty
v: val_m Ξ1 a
f1: Ξ1 =[ val_m ]> Ξ2
f2: Ξ2 =[ val_m ]> Ξ3v α΅₯β f1 β f2 = (v α΅₯β f1) α΅₯β f2destruct s; cbn; now rewrite t_sub_sub, e_sub_sub. Qed.Ξ1, Ξ2, Ξ3: t_ctx
s: state Ξ1
f1: Ξ1 =[ val_m ]> Ξ2
f2: Ξ2 =[ val_m ]> Ξ3s ββ f1 β f2 = (s ββ f1) ββ f2Ξ, Ξ: t_ctx
a, b: ty
f: Ξ =[ val_m ]> Ξ
v1: val_m Ξ a
v2: val_m Ξ ba_shift2 f β assign2 (v1 α΅₯β f) (v2 α΅₯β f) β‘β assign2 v1 v2 β fΞ, Ξ: t_ctx
a, b: ty
f: Ξ =[ val_m ]> Ξ
v1: val_m Ξ a
v2: val_m Ξ b
a0: ty
v: Ξ βΆβ a βΆβ b β a0(a_shift2 f β assign2 (v1 α΅₯β f) (v2 α΅₯β f))%asgn a0 v = (assign2 v1 v2 β f)%asgn a0 vΞ1: ctx ty
Ξ: t_ctx
y0, y: ty
f: Ξ1 =[ val_m ]> Ξ
v1: val_m Ξ1 y0
v2: val_m Ξ1 y
a0: ty
v: var a0 Ξ1(a_shift2 f β assign2 (v1 α΅₯β f) (v2 α΅₯β f))%asgn a0 (pop (pop v)) = (assign2 v1 v2 β f)%asgn a0 (pop (pop v))now apply m_sub_id_l. Qed.Ξ1: ctx ty
Ξ: t_ctx
y0, y: ty
f: Ξ1 =[ val_m ]> Ξ
v1: val_m Ξ1 y0
v2: val_m Ξ1 y
a0: ty
v: var a0 Ξ1f a0 v α΅₯β (r_pop α΅£β r_pop) α΅£β assign2 (m_subst Ξ1 y0 v1 Ξ f) (m_subst Ξ1 y v2 Ξ f) = f a0 vunfold t_subst2; now rewrite <- 2 t_sub_sub, a_sub2_sub. Qed.Ξ, Ξ: t_ctx
x, y: ty
z: ty0
f: Ξ =[ val_m ]> Ξ
t: term (Ξ βΆβ x βΆβ y) z
v1: val_m Ξ x
v2: val_m Ξ yt `ββ a_shift2 f /[ v1 α΅₯β f, v2 α΅₯β f] = (t /[ v1, v2]) `ββ f
Having proved all the basic syntactic properties of STLC, we are now ready to instanciate our framework!
As we only have negative types, we instanciate the interaction specification with types and observations. Beware that in more involved cases, the notion of "types" we give to the OGS construction does not coincide with the "language types": you should only give the negative types, or more intuitively, "non-shareable" types.
As hinted at the beginning, we instanciate the abstract value notion with our "machine values". They form a suitable monoid, which means we get a category of assigments, for which we now provide the proof of the laws.
#[global] Instance stlc_val_laws : subst_monoid_laws val_m :=
{| v_sub_proper := @m_sub_eq ;
v_sub_var := @m_sub_id_r ;
v_var_sub := @m_sub_id_l ;
Subst.v_sub_sub := @m_sub_sub |} .
Configurations are instanciated with our states, and what we have proved earlier amounts to showing they are a right-module on values.
#[global] Instance stlc_conf_laws : subst_module_laws val_m state :=
{| c_sub_proper := @s_sub_eq ;
c_var_sub := @s_sub_id_l ;
c_sub_sub := @s_sub_sub |} .
In our generic theorem, there is a finicky lemma that is the counter-part to
the exclusion of any "infinite chit-chat" that one finds in other accounts of
OGS and other game semantics. The way we have proved it requires a little bit
more structure on values. Specifically, we need to show that a_id
is
injective and that its fibers are decidable and invert renamings. These
technicalities are easily shown by induction on values but help us to
distinguish conveniently between values which are variables and others.
var_assumptions val_mforall (Ξ : t_ctx) (x : ty), injective (Subst.a_id (x:=x))forall (Ξ : t_ctx) (x : ty) (v : val_m Ξ x), decidable (is_var v)forall (Ξ1 Ξ2 : t_ctx) (x : ty) (v : val_m Ξ1 x) (r : Ξ1 β Ξ2), is_var (v_ren v r) -> is_var vintros ? [] ?? H; now dependent destruction H.forall (Ξ : t_ctx) (x : ty), injective (Subst.a_id (x:=x))forall (Ξ : t_ctx) (x : ty) (v : val_m Ξ x), decidable (is_var v)all: apply No; intro H; dependent destruction H.Ξ: t_ctx
t: ty0decidable (is_var TT)Ξ: t_ctx
t, a, b: ty0
t0: term (Ξ βΆβ + (a β b) βΆβ + a) bdecidable (is_var (Lam t0))Ξ: t_ctx
t, a, b: ty0
t0: term Ξ (a β b)
e: ev_ctx Ξ bdecidable (is_var (K1 t0 e))Ξ: t_ctx
t, a, b: ty0
v: val Ξ a
e: ev_ctx Ξ bdecidable (is_var (K2 v e))intros ?? [] v r H; induction v; dependent destruction H; exact (Vvar _). Qed.forall (Ξ1 Ξ2 : t_ctx) (x : ty) (v : val_m Ξ1 x) (r : Ξ1 β Ξ2), is_var (v_ren v r) -> is_var v
We now instanciate the machine with stlc_eval
as the active step ("compute
the next observable action") and obs_app
as the passive step ("resume from
a stuck state").
#[global] Instance stlc_machine : machine val_m state obs_op :=
{| eval := @stlc_eval ;
oapp := @obs_app |} .
All that is left is to prove our theorem-specific hypotheses. All but another
technical lemma for the chit-chat problem are again coherence conditions
between eval
and app
and the monoidal structure of values and
configurations.
machine_laws val_m state obs_opΞ: t_ctx
x: ty
v: val_m Ξ x
o: obs xProper (asgn_eq (obs_dom o) Ξ ==> eq) (obs_app v o)Ξ1, Ξ2: t_ctx
x: ty
v: val_m Ξ1 x
o: obs x
a: obs_dom o =[ val_m ]> Ξ1
b: Ξ1 =[ val_m ]> Ξ2m_var (obs_app v o a) `ββ b β m_obs (obs_app v o a) `ββ b = obs_app (m_subst Ξ1 x v Ξ2 b) o (a β b)Ξ, Ξ: t_ctx
c: state Ξ
a: Ξ =[ val_m ]> Ξstlc_eval (m_var c `ββ a β m_obs c `ββ a) β bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a))Ξ: t_ctx
u: Obs.nf obs_op val_m Ξstlc_eval (obs_app (a_id (nf_ty u) (nf_var u)) (nf_obs u) (nf_args u)) β ret_delay uwell_founded head_inst_nostep
The first one proves that obs_app
respects pointwise equality of assigments.
intros ?? H1; dependent elimination o; cbn; repeat (f_equal; auto).Ξ: t_ctx
x: ty
v: val_m Ξ x
o: obs xProper (asgn_eq (obs_dom o) Ξ ==> eq) (obs_app v o)
The second one proves a commutation law of obs_app
with renamings.
destruct x; dependent elimination o; cbn; f_equal.Ξ1, Ξ2: t_ctx
x: ty
v: val_m Ξ1 x
o: obs x
a: obs_dom o =[ val_m ]> Ξ1
b: Ξ1 =[ val_m ]> Ξ2m_var (obs_app v o a) `ββ b β m_obs (obs_app v o a) `ββ b = obs_app (m_subst Ξ1 x v Ξ2 b) o (a β b)
The meat of our abstract proof is this next one. We need to prove that our evaluator respects substitution in a suitable sense: evaluating a substituted configuration must be the same thing as evaluating the configuration, then "substituting" the normal form and continuing the evaluation.
While potentially scary, the proof is direct and this actually amount to checking that indeed, when unrolling our evaluator, this is what happens.
Ξ, Ξ: t_ctx
c: state Ξ
a: Ξ =[ val_m ]> Ξstlc_eval (m_var c `ββ a β m_obs c `ββ a) β bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a))Ξ, Ξ: t_ctx
R: relα΅’ (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ)) (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ))
CIH: forall (c : state Ξ) (a : Ξ =[ val_m ]> Ξ), it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ a β m_obs c `ββ a)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a)))
c: state Ξ
e: Ξ =[ val_m ]> Ξit_eq_bt Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ e β m_obs c `ββ e)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ e β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ e)))Ξ: t_ctx
a0: ty0
v: val Ξ a0
i: Ξ β Β¬ a0
Ξ: t_ctx
R: relα΅’ (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ)) (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ))
CIH: forall (c : state Ξ) (a : Ξ =[ val_m ]> Ξ), it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ a β m_obs c `ββ a)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a)))
e: Ξ =[ val_m ]> Ξ
H: {| pr1 := ORet; pr2 := (! βΆβ v)%asgn |} = {| pr1 := ORet; pr2 := (! βΆβ v)%asgn |}it_eqF Event.emptyβ (fun _ : T1 => nf_eq) (it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R) T1_0 match match e Β¬ a0 i in (ev_ctx _ t) return (val Ξ t -> state Ξ + nf Ξ) with | @K0 _ a c => fun v : val Ξ a => inr (c β ORet β¦ ! βΆβ v β¦) | @K1 _ a b t e => fun v : val Ξ a => inl (t β K2 v e) | @K2 _ a b v e => fun v0 : val Ξ (a β b) => match v0 in (val _ t) return (val Ξ a -> ev_ctx Ξ b -> t = a β b -> state Ξ + nf Ξ) with | @Var _ a0 c => fun (v1 : val Ξ a) (e0 : ev_ctx Ξ b) (H : a0 = a β b) => DepElim.solution_left (a β b) (fun (c0 : cvar Ξ + (a β b)) (v2 : val Ξ a) (e1 : ev_ctx Ξ b) => inr (c0 β OApp β¦ (! βΆβ v2) βΆβ e1 β¦)) a0 H c v1 e0 | TT => fun (_ : val Ξ a) (_ : ev_ctx Ξ b) => apply_noConfusion ΞΉ (a β b) (False_rect (state Ξ + nf Ξ)) | @Lam _ a0 b0 t => fun (v1 : val Ξ a) (e0 : ev_ctx Ξ b) => apply_noConfusion (a0 β b0) (a β b) (DepElim.eq_simplification_sigma1 a0 a b0 b (fun H : a0 = a => DepElim.solution_left a (fun (b1 : ty0) (t0 : term (Ξ βΆβ ... βΆβ + a) b1) (v2 : val Ξ a) (e1 : ev_ctx Ξ b) (H0 : b1 = b) => DepElim.solution_left b (fun (t1 : term ... b) (v3 : val Ξ a) => inl β Cut (...)) b1 H0 t0 v2 e1) a0 H b0 t v1 e0)) end v e eq_refl end (v `α΅₯β e) with | inl x => TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x0 := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x0) in ret_delay β eval_step) T1_0 x) | inr y => RetF y end match match e Β¬ a0 i in (ev_ctx _ t) return (val Ξ t -> state Ξ + nf Ξ) with | @K0 _ a c => fun v : val Ξ a => inr (c β ORet β¦ ! βΆβ v β¦) | @K1 _ a b t e => fun v : val Ξ a => inl (t β K2 v e) | @K2 _ a b v e => fun v0 : val Ξ (a β b) => match v0 in (val _ t) return (val Ξ a -> ev_ctx Ξ b -> t = a β b -> state Ξ + nf Ξ) with | @Var _ a0 c => fun (v1 : val Ξ a) (e0 : ev_ctx Ξ b) (H : a0 = a β b) => DepElim.solution_left (a β b) (fun (c0 : cvar Ξ + (a β b)) (v2 : val Ξ a) (e1 : ev_ctx Ξ b) => inr (c0 β OApp β¦ (! βΆβ v2) βΆβ e1 β¦)) a0 H c v1 e0 | TT => fun (_ : val Ξ a) (_ : ev_ctx Ξ b) => apply_noConfusion ΞΉ (a β b) (False_rect (state Ξ + nf Ξ)) | @Lam _ a0 b0 t => fun (v1 : val Ξ a) (e0 : ev_ctx Ξ b) => apply_noConfusion (a0 β b0) (a β b) (DepElim.eq_simplification_sigma1 a0 a b0 b (fun H : a0 = a => DepElim.solution_left a (fun (b1 : ty0) (t0 : term (Ξ βΆβ ... βΆβ + a) b1) (v2 : val Ξ a) (e1 : ev_ctx Ξ b) (H0 : b1 = b) => DepElim.solution_left b (fun (t1 : term ... b) (v3 : val Ξ a) => inl β Cut (...)) b1 H0 t0 v2 e1) a0 H b0 t v1 e0)) end v e eq_refl end (v `α΅₯β e) with | inl x => TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x0 := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x0) in ret_delay β eval_step) T1_0 x) | inr y => RetF y endΞ: t_ctx
a1: ty0
v: val Ξ a1
b: ty0
t: term Ξ (a1 β b)
Ο: ev_ctx Ξ b
Ξ: t_ctx
R: relα΅’ (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ)) (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ))
CIH: forall (c : state Ξ) (a : Ξ =[ val_m ]> Ξ), it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ a β m_obs c `ββ a)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a)))
e: Ξ =[ val_m ]> Ξ
H: K2 v Ο = K2 v Οit_eqF Event.emptyβ (fun _ : T1 => nf_eq) (it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R) T1_0 (TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x) in ret_delay β eval_step) T1_0 (t `ββ e β K2 (v `α΅₯β e) (Ο `ββ e)))) (TauF (Structure.subst (fun pat : T1 => let 'T1_0 as x := pat return (Obs.nf obs_op val_m Ξ -> itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ) x) in fun y : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty y) (nf_var y)) (nf_obs y) (nf_args y)) `ββ e β m_obs (obs_app (a_id (nf_ty y) (nf_var y)) (nf_obs y) (nf_args y)) `ββ e)) T1_0 (Structure.iter (fun pat : T1 => let 'T1_0 as x := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x) in ret_delay β eval_step) T1_0 (t β K2 v Ο))))Ξ: t_ctx
a2, b0: ty0
i: Ξ β + (a2 β b0)
v: val Ξ a2
Ο: ev_ctx Ξ b0
Ξ: t_ctx
R: relα΅’ (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ)) (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ))
CIH: forall (c : state Ξ) (a : Ξ =[ val_m ]> Ξ), it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ a β m_obs c `ββ a)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a)))
e: Ξ =[ val_m ]> Ξ
H: {| pr1 := OApp; pr2 := ((! βΆβ v) βΆβ Ο)%asgn |} = {| pr1 := OApp; pr2 := ((! βΆβ v) βΆβ Ο)%asgn |}it_eqF Event.emptyβ (fun _ : T1 => nf_eq) (it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R) T1_0 match match e + (a2 β b0) i in (val _ t) return (val Ξ a2 -> ev_ctx Ξ b0 -> t = a2 β b0 -> state Ξ + nf Ξ) with | @Var _ a c => fun (v0 : val Ξ a2) (e0 : ev_ctx Ξ b0) (H : a = a2 β b0) => DepElim.solution_left (a2 β b0) (fun (c0 : cvar Ξ + (a2 β b0)) (v1 : val Ξ a2) (e1 : ev_ctx Ξ b0) => inr (c0 β OApp β¦ (! βΆβ v1) βΆβ e1 β¦)) a H c v0 e0 | TT => fun (_ : val Ξ a2) (_ : ev_ctx Ξ b0) => apply_noConfusion ΞΉ (a2 β b0) (False_rect (state Ξ + nf Ξ)) | @Lam _ a b t => fun (v0 : val Ξ a2) (e0 : ev_ctx Ξ b0) => apply_noConfusion (a β b) (a2 β b0) (DepElim.eq_simplification_sigma1 a a2 b b0 (fun H : a = a2 => DepElim.solution_left a2 (fun (b1 : ty0) (t0 : term (Ξ βΆβ + (a2 β b1) βΆβ + a2) b1) (v1 : val Ξ a2) (e1 : ev_ctx Ξ b0) (H0 : b1 = b0) => DepElim.solution_left b0 (fun (t1 : term (Ξ βΆβ + ... βΆβ + a2) b0) (v2 : val Ξ a2) => inl β Cut (t1 /[ Lam t1, v2])) b1 H0 t0 v1 e1) a H b t v0 e0)) end (v `α΅₯β e) (Ο `ββ e) eq_refl with | inl x => TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x0 := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x0) in ret_delay β eval_step) T1_0 x) | inr y => RetF y end match match e + (a2 β b0) i in (val _ t) return (val Ξ a2 -> ev_ctx Ξ b0 -> t = a2 β b0 -> state Ξ + nf Ξ) with | @Var _ a c => fun (v0 : val Ξ a2) (e0 : ev_ctx Ξ b0) (H : a = a2 β b0) => DepElim.solution_left (a2 β b0) (fun (c0 : cvar Ξ + (a2 β b0)) (v1 : val Ξ a2) (e1 : ev_ctx Ξ b0) => inr (c0 β OApp β¦ (! βΆβ v1) βΆβ e1 β¦)) a H c v0 e0 | TT => fun (_ : val Ξ a2) (_ : ev_ctx Ξ b0) => apply_noConfusion ΞΉ (a2 β b0) (False_rect (state Ξ + nf Ξ)) | @Lam _ a b t => fun (v0 : val Ξ a2) (e0 : ev_ctx Ξ b0) => apply_noConfusion (a β b) (a2 β b0) (DepElim.eq_simplification_sigma1 a a2 b b0 (fun H : a = a2 => DepElim.solution_left a2 (fun (b1 : ty0) (t0 : term (Ξ βΆβ + (a2 β b1) βΆβ + a2) b1) (v1 : val Ξ a2) (e1 : ev_ctx Ξ b0) (H0 : b1 = b0) => DepElim.solution_left b0 (fun (t1 : term (Ξ βΆβ + ... βΆβ + a2) b0) (v2 : val Ξ a2) => inl β Cut (t1 /[ Lam t1, v2])) b1 H0 t0 v1 e1) a H b t v0 e0)) end (v `α΅₯β e) (Ο `ββ e) eq_refl with | inl x => TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x0 := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x0) in ret_delay β eval_step) T1_0 x) | inr y => RetF y endΞ: t_ctx
a0, b: ty0
t: term (Ξ βΆβ + (a0 β b) βΆβ + a0) b
v: val Ξ a0
Ο: ev_ctx Ξ b
Ξ: t_ctx
R: relα΅’ (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ)) (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ))
CIH: forall (c : state Ξ) (a : Ξ =[ val_m ]> Ξ), it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ a β m_obs c `ββ a)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a)))
e: Ξ =[ val_m ]> Ξit_eqF Event.emptyβ (fun _ : T1 => nf_eq) (it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R) T1_0 (TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x) in ret_delay β eval_step) T1_0 ((t `ββ a_shift2 e /[ Lam (t `ββ a_shift2 e), v `α΅₯β e]) β Ο `ββ e))) (TauF (Structure.subst (fun pat : T1 => let 'T1_0 as x := pat return (Obs.nf obs_op val_m Ξ -> itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ) x) in fun y : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty y) (nf_var y)) (nf_obs y) (nf_args y)) `ββ e β m_obs (obs_app (a_id (nf_ty y) (nf_var y)) (nf_obs y) (nf_args y)) `ββ e)) T1_0 (Structure.iter (fun pat : T1 => let 'T1_0 as x := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x) in ret_delay β eval_step) T1_0 ((t /[ Lam t, v]) β Ο))))Ξ: t_ctx
b, a0: ty0
t1: term Ξ (a0 β b)
t2: term Ξ a0
Ο: ev_ctx Ξ b
Ξ: t_ctx
R: relα΅’ (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ)) (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ))
CIH: forall (c : state Ξ) (a : Ξ =[ val_m ]> Ξ), it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ a β m_obs c `ββ a)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a)))
e: Ξ =[ val_m ]> Ξit_eqF Event.emptyβ (fun _ : T1 => nf_eq) (it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R) T1_0 (TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x) in ret_delay β eval_step) T1_0 (t2 `ββ e β K1 (t1 `ββ e) (Ο `ββ e)))) (TauF (Structure.subst (fun pat : T1 => let 'T1_0 as x := pat return (Obs.nf obs_op val_m Ξ -> itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ) x) in fun y : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty y) (nf_var y)) (nf_obs y) (nf_args y)) `ββ e β m_obs (obs_app (a_id (nf_ty y) (nf_var y)) (nf_obs y) (nf_args y)) `ββ e)) T1_0 (Structure.iter (fun pat : T1 => let 'T1_0 as x := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x) in ret_delay β eval_step) T1_0 (t2 β K1 t1 Ο))))Ξ: t_ctx
a0: ty0
v: val Ξ a0
i: Ξ β Β¬ a0
Ξ: t_ctx
R: relα΅’ (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ)) (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ))
CIH: forall (c : state Ξ) (a : Ξ =[ val_m ]> Ξ), it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ a β m_obs c `ββ a)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a)))
e: Ξ =[ val_m ]> Ξ
H: {| pr1 := ORet; pr2 := (! βΆβ v)%asgn |} = {| pr1 := ORet; pr2 := (! βΆβ v)%asgn |}it_eqF Event.emptyβ (fun _ : T1 => nf_eq) (it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R) T1_0 match match e Β¬ a0 i in (ev_ctx _ t) return (val Ξ t -> state Ξ + nf Ξ) with | @K0 _ a c => fun v : val Ξ a => inr (c β ORet β¦ ! βΆβ v β¦) | @K1 _ a b t e => fun v : val Ξ a => inl (t β K2 v e) | @K2 _ a b v e => fun v0 : val Ξ (a β b) => match v0 in (val _ t) return (val Ξ a -> ev_ctx Ξ b -> t = a β b -> state Ξ + nf Ξ) with | @Var _ a0 c => fun (v1 : val Ξ a) (e0 : ev_ctx Ξ b) (H : a0 = a β b) => DepElim.solution_left (a β b) (fun (c0 : cvar Ξ + (a β b)) (v2 : val Ξ a) (e1 : ev_ctx Ξ b) => inr (c0 β OApp β¦ (! βΆβ v2) βΆβ e1 β¦)) a0 H c v1 e0 | TT => fun (_ : val Ξ a) (_ : ev_ctx Ξ b) => apply_noConfusion ΞΉ (a β b) (False_rect (state Ξ + nf Ξ)) | @Lam _ a0 b0 t => fun (v1 : val Ξ a) (e0 : ev_ctx Ξ b) => apply_noConfusion (a0 β b0) (a β b) (DepElim.eq_simplification_sigma1 a0 a b0 b (fun H : a0 = a => DepElim.solution_left a (fun (b1 : ty0) (t0 : term (Ξ βΆβ ... βΆβ + a) b1) (v2 : val Ξ a) (e1 : ev_ctx Ξ b) (H0 : b1 = b) => DepElim.solution_left b (fun (t1 : term ... b) (v3 : val Ξ a) => inl β Cut (...)) b1 H0 t0 v2 e1) a0 H b0 t v1 e0)) end v e eq_refl end (v `α΅₯β e) with | inl x => TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x0 := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x0) in ret_delay β eval_step) T1_0 x) | inr y => RetF y end match match e Β¬ a0 i in (ev_ctx _ t) return (val Ξ t -> state Ξ + nf Ξ) with | @K0 _ a c => fun v : val Ξ a => inr (c β ORet β¦ ! βΆβ v β¦) | @K1 _ a b t e => fun v : val Ξ a => inl (t β K2 v e) | @K2 _ a b v e => fun v0 : val Ξ (a β b) => match v0 in (val _ t) return (val Ξ a -> ev_ctx Ξ b -> t = a β b -> state Ξ + nf Ξ) with | @Var _ a0 c => fun (v1 : val Ξ a) (e0 : ev_ctx Ξ b) (H : a0 = a β b) => DepElim.solution_left (a β b) (fun (c0 : cvar Ξ + (a β b)) (v2 : val Ξ a) (e1 : ev_ctx Ξ b) => inr (c0 β OApp β¦ (! βΆβ v2) βΆβ e1 β¦)) a0 H c v1 e0 | TT => fun (_ : val Ξ a) (_ : ev_ctx Ξ b) => apply_noConfusion ΞΉ (a β b) (False_rect (state Ξ + nf Ξ)) | @Lam _ a0 b0 t => fun (v1 : val Ξ a) (e0 : ev_ctx Ξ b) => apply_noConfusion (a0 β b0) (a β b) (DepElim.eq_simplification_sigma1 a0 a b0 b (fun H : a0 = a => DepElim.solution_left a (fun (b1 : ty0) (t0 : term (Ξ βΆβ ... βΆβ + a) b1) (v2 : val Ξ a) (e1 : ev_ctx Ξ b) (H0 : b1 = b) => DepElim.solution_left b (fun (t1 : term ... b) (v3 : val Ξ a) => inl β Cut (...)) b1 H0 t0 v2 e1) a0 H b0 t v1 e0)) end v e eq_refl end (v `α΅₯β e) with | inl x => TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x0 := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x0) in ret_delay β eval_step) T1_0 x) | inr y => RetF y endΞ: t_ctx
a, b: ty0
v: val Ξ (a β b)
i: Ξ β Β¬ (a β b)
Ξ: t_ctx
R: relα΅’ (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ)) (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ))
CIH: forall (c : state Ξ) (a : Ξ =[ val_m ]> Ξ), it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ a β m_obs c `ββ a)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a)))
e: Ξ =[ val_m ]> Ξ
H: {| pr1 := ORet; pr2 := (! βΆβ v)%asgn |} = {| pr1 := ORet; pr2 := (! βΆβ v)%asgn |}
v0: val Ξ a
v1: ev_ctx Ξ bit_eqF Event.emptyβ (fun _ : T1 => nf_eq) (it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R) T1_0 match match v `α΅₯β e in (val _ t) return (val Ξ a -> ev_ctx Ξ b -> t = a β b -> state Ξ + nf Ξ) with | @Var _ a0 c => fun (v0 : val Ξ a) (e0 : ev_ctx Ξ b) (H : a0 = a β b) => DepElim.solution_left (a β b) (fun (c0 : cvar Ξ + (a β b)) (v1 : val Ξ a) (e1 : ev_ctx Ξ b) => inr (c0 β OApp β¦ (! βΆβ v1) βΆβ e1 β¦)) a0 H c v0 e0 | TT => fun (_ : val Ξ a) (_ : ev_ctx Ξ b) => apply_noConfusion ΞΉ (a β b) (False_rect (state Ξ + nf Ξ)) | @Lam _ a0 b0 t => fun (v0 : val Ξ a) (e0 : ev_ctx Ξ b) => apply_noConfusion (a0 β b0) (a β b) (DepElim.eq_simplification_sigma1 a0 a b0 b (fun H : a0 = a => DepElim.solution_left a (fun (b1 : ty0) (t0 : term (Ξ βΆβ + (a β b1) βΆβ + a) b1) (v1 : val Ξ a) (e1 : ev_ctx Ξ b) (H0 : b1 = b) => DepElim.solution_left b (fun (t1 : term (Ξ βΆβ + ... βΆβ + a) b) (v2 : val Ξ a) => inl β Cut (t1 /[ Lam t1, v2])) b1 H0 t0 v1 e1) a0 H b0 t v0 e0)) end v0 v1 eq_refl with | inl x => TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x0 := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x0) in ret_delay β eval_step) T1_0 x) | inr y => RetF y end match match v `α΅₯β e in (val _ t) return (val Ξ a -> ev_ctx Ξ b -> t = a β b -> state Ξ + nf Ξ) with | @Var _ a0 c => fun (v0 : val Ξ a) (e0 : ev_ctx Ξ b) (H : a0 = a β b) => DepElim.solution_left (a β b) (fun (c0 : cvar Ξ + (a β b)) (v1 : val Ξ a) (e1 : ev_ctx Ξ b) => inr (c0 β OApp β¦ (! βΆβ v1) βΆβ e1 β¦)) a0 H c v0 e0 | TT => fun (_ : val Ξ a) (_ : ev_ctx Ξ b) => apply_noConfusion ΞΉ (a β b) (False_rect (state Ξ + nf Ξ)) | @Lam _ a0 b0 t => fun (v0 : val Ξ a) (e0 : ev_ctx Ξ b) => apply_noConfusion (a0 β b0) (a β b) (DepElim.eq_simplification_sigma1 a0 a b0 b (fun H : a0 = a => DepElim.solution_left a (fun (b1 : ty0) (t0 : term (Ξ βΆβ + (a β b1) βΆβ + a) b1) (v1 : val Ξ a) (e1 : ev_ctx Ξ b) (H0 : b1 = b) => DepElim.solution_left b (fun (t1 : term (Ξ βΆβ + ... βΆβ + a) b) (v2 : val Ξ a) => inl β Cut (t1 /[ Lam t1, v2])) b1 H0 t0 v1 e1) a0 H b0 t v0 e0)) end v0 v1 eq_refl with | inl x => TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x0 := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x0) in ret_delay β eval_step) T1_0 x) | inr y => RetF y enddependent elimination v'; cbn; auto.Ξ: t_ctx
a, b: ty0
i: Ξ β Β¬ (a β b)
Ξ: t_ctx
R: relα΅’ (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ)) (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ))
CIH: forall (c : state Ξ) (a : Ξ =[ val_m ]> Ξ), it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ a β m_obs c `ββ a)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a)))
e: Ξ =[ val_m ]> Ξ
v0: val Ξ a
v1: ev_ctx Ξ b
v': val Ξ (a β b)it_eqF Event.emptyβ (fun _ : T1 => nf_eq) (it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R) T1_0 match match v' in (val _ t) return (val Ξ a -> ev_ctx Ξ b -> t = a β b -> state Ξ + nf Ξ) with | @Var _ a0 c => fun (v0 : val Ξ a) (e0 : ev_ctx Ξ b) (H : a0 = a β b) => DepElim.solution_left (a β b) (fun (c0 : cvar Ξ + (a β b)) (v1 : val Ξ a) (e1 : ev_ctx Ξ b) => inr (c0 β OApp β¦ (! βΆβ v1) βΆβ e1 β¦)) a0 H c v0 e0 | TT => fun (_ : val Ξ a) (_ : ev_ctx Ξ b) => apply_noConfusion ΞΉ (a β b) (False_rect (state Ξ + nf Ξ)) | @Lam _ a0 b0 t => fun (v0 : val Ξ a) (e0 : ev_ctx Ξ b) => apply_noConfusion (a0 β b0) (a β b) (DepElim.eq_simplification_sigma1 a0 a b0 b (fun H : a0 = a => DepElim.solution_left a (fun (b1 : ty0) (t0 : term (Ξ βΆβ + (a β b1) βΆβ + a) b1) (v1 : val Ξ a) (e1 : ev_ctx Ξ b) (H0 : b1 = b) => DepElim.solution_left b (fun (t1 : term (Ξ βΆβ + ... βΆβ + a) b) (v2 : val Ξ a) => inl β Cut (t1 /[ Lam t1, v2])) b1 H0 t0 v1 e1) a0 H b0 t v0 e0)) end v0 v1 eq_refl with | inl x => TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x0 := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x0) in ret_delay β eval_step) T1_0 x) | inr y => RetF y end match match v' in (val _ t) return (val Ξ a -> ev_ctx Ξ b -> t = a β b -> state Ξ + nf Ξ) with | @Var _ a0 c => fun (v0 : val Ξ a) (e0 : ev_ctx Ξ b) (H : a0 = a β b) => DepElim.solution_left (a β b) (fun (c0 : cvar Ξ + (a β b)) (v1 : val Ξ a) (e1 : ev_ctx Ξ b) => inr (c0 β OApp β¦ (! βΆβ v1) βΆβ e1 β¦)) a0 H c v0 e0 | TT => fun (_ : val Ξ a) (_ : ev_ctx Ξ b) => apply_noConfusion ΞΉ (a β b) (False_rect (state Ξ + nf Ξ)) | @Lam _ a0 b0 t => fun (v0 : val Ξ a) (e0 : ev_ctx Ξ b) => apply_noConfusion (a0 β b0) (a β b) (DepElim.eq_simplification_sigma1 a0 a b0 b (fun H : a0 = a => DepElim.solution_left a (fun (b1 : ty0) (t0 : term (Ξ βΆβ + (a β b1) βΆβ + a) b1) (v1 : val Ξ a) (e1 : ev_ctx Ξ b) (H0 : b1 = b) => DepElim.solution_left b (fun (t1 : term (Ξ βΆβ + ... βΆβ + a) b) (v2 : val Ξ a) => inl β Cut (t1 /[ Lam t1, v2])) b1 H0 t0 v1 e1) a0 H b0 t v0 e0)) end v0 v1 eq_refl with | inl x => TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x0 := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x0) in ret_delay β eval_step) T1_0 x) | inr y => RetF y endeconstructor; refold_eval; apply CIH.Ξ: t_ctx
a1: ty0
v: val Ξ a1
b: ty0
t: term Ξ (a1 β b)
Ο: ev_ctx Ξ b
Ξ: t_ctx
R: relα΅’ (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ)) (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ))
CIH: forall (c : state Ξ) (a : Ξ =[ val_m ]> Ξ), it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ a β m_obs c `ββ a)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a)))
e: Ξ =[ val_m ]> Ξ
H: K2 v Ο = K2 v Οit_eqF Event.emptyβ (fun _ : T1 => nf_eq) (it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R) T1_0 (TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x) in ret_delay β eval_step) T1_0 (t `ββ e β K2 (v `α΅₯β e) (Ο `ββ e)))) (TauF (Structure.subst (fun pat : T1 => let 'T1_0 as x := pat return (Obs.nf obs_op val_m Ξ -> itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ) x) in fun y : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty y) (nf_var y)) (nf_obs y) (nf_args y)) `ββ e β m_obs (obs_app (a_id (nf_ty y) (nf_var y)) (nf_obs y) (nf_args y)) `ββ e)) T1_0 (Structure.iter (fun pat : T1 => let 'T1_0 as x := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x) in ret_delay β eval_step) T1_0 (t β K2 v Ο))))Ξ: t_ctx
a2, b0: ty0
i: Ξ β + (a2 β b0)
v: val Ξ a2
Ο: ev_ctx Ξ b0
Ξ: t_ctx
R: relα΅’ (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ)) (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ))
CIH: forall (c : state Ξ) (a : Ξ =[ val_m ]> Ξ), it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ a β m_obs c `ββ a)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a)))
e: Ξ =[ val_m ]> Ξ
H: {| pr1 := OApp; pr2 := ((! βΆβ v) βΆβ Ο)%asgn |} = {| pr1 := OApp; pr2 := ((! βΆβ v) βΆβ Ο)%asgn |}it_eqF Event.emptyβ (fun _ : T1 => nf_eq) (it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R) T1_0 match match e + (a2 β b0) i in (val _ t) return (val Ξ a2 -> ev_ctx Ξ b0 -> t = a2 β b0 -> state Ξ + nf Ξ) with | @Var _ a c => fun (v0 : val Ξ a2) (e0 : ev_ctx Ξ b0) (H : a = a2 β b0) => DepElim.solution_left (a2 β b0) (fun (c0 : cvar Ξ + (a2 β b0)) (v1 : val Ξ a2) (e1 : ev_ctx Ξ b0) => inr (c0 β OApp β¦ (! βΆβ v1) βΆβ e1 β¦)) a H c v0 e0 | TT => fun (_ : val Ξ a2) (_ : ev_ctx Ξ b0) => apply_noConfusion ΞΉ (a2 β b0) (False_rect (state Ξ + nf Ξ)) | @Lam _ a b t => fun (v0 : val Ξ a2) (e0 : ev_ctx Ξ b0) => apply_noConfusion (a β b) (a2 β b0) (DepElim.eq_simplification_sigma1 a a2 b b0 (fun H : a = a2 => DepElim.solution_left a2 (fun (b1 : ty0) (t0 : term (Ξ βΆβ + (a2 β b1) βΆβ + a2) b1) (v1 : val Ξ a2) (e1 : ev_ctx Ξ b0) (H0 : b1 = b0) => DepElim.solution_left b0 (fun (t1 : term (Ξ βΆβ + ... βΆβ + a2) b0) (v2 : val Ξ a2) => inl β Cut (t1 /[ Lam t1, v2])) b1 H0 t0 v1 e1) a H b t v0 e0)) end (v `α΅₯β e) (Ο `ββ e) eq_refl with | inl x => TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x0 := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x0) in ret_delay β eval_step) T1_0 x) | inr y => RetF y end match match e + (a2 β b0) i in (val _ t) return (val Ξ a2 -> ev_ctx Ξ b0 -> t = a2 β b0 -> state Ξ + nf Ξ) with | @Var _ a c => fun (v0 : val Ξ a2) (e0 : ev_ctx Ξ b0) (H : a = a2 β b0) => DepElim.solution_left (a2 β b0) (fun (c0 : cvar Ξ + (a2 β b0)) (v1 : val Ξ a2) (e1 : ev_ctx Ξ b0) => inr (c0 β OApp β¦ (! βΆβ v1) βΆβ e1 β¦)) a H c v0 e0 | TT => fun (_ : val Ξ a2) (_ : ev_ctx Ξ b0) => apply_noConfusion ΞΉ (a2 β b0) (False_rect (state Ξ + nf Ξ)) | @Lam _ a b t => fun (v0 : val Ξ a2) (e0 : ev_ctx Ξ b0) => apply_noConfusion (a β b) (a2 β b0) (DepElim.eq_simplification_sigma1 a a2 b b0 (fun H : a = a2 => DepElim.solution_left a2 (fun (b1 : ty0) (t0 : term (Ξ βΆβ + (a2 β b1) βΆβ + a2) b1) (v1 : val Ξ a2) (e1 : ev_ctx Ξ b0) (H0 : b1 = b0) => DepElim.solution_left b0 (fun (t1 : term (Ξ βΆβ + ... βΆβ + a2) b0) (v2 : val Ξ a2) => inl β Cut (t1 /[ Lam t1, v2])) b1 H0 t0 v1 e1) a H b t v0 e0)) end (v `α΅₯β e) (Ο `ββ e) eq_refl with | inl x => TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x0 := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x0) in ret_delay β eval_step) T1_0 x) | inr y => RetF y enddependent elimination vv; cbn; auto.Ξ: t_ctx
a2, b0: ty0
v: val Ξ a2
Ο: ev_ctx Ξ b0
Ξ: t_ctx
R: relα΅’ (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ)) (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ))
CIH: forall (c : state Ξ) (a : Ξ =[ val_m ]> Ξ), it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ a β m_obs c `ββ a)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a)))
e: Ξ =[ val_m ]> Ξ
vv: val_m Ξ + (a2 β b0)it_eqF Event.emptyβ (fun _ : T1 => nf_eq) (it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R) T1_0 match match vv in (val _ t) return (val Ξ a2 -> ev_ctx Ξ b0 -> t = a2 β b0 -> state Ξ + nf Ξ) with | @Var _ a c => fun (v0 : val Ξ a2) (e0 : ev_ctx Ξ b0) (H : a = a2 β b0) => DepElim.solution_left (a2 β b0) (fun (c0 : cvar Ξ + (a2 β b0)) (v1 : val Ξ a2) (e1 : ev_ctx Ξ b0) => inr (c0 β OApp β¦ (! βΆβ v1) βΆβ e1 β¦)) a H c v0 e0 | TT => fun (_ : val Ξ a2) (_ : ev_ctx Ξ b0) => apply_noConfusion ΞΉ (a2 β b0) (False_rect (state Ξ + nf Ξ)) | @Lam _ a b t => fun (v0 : val Ξ a2) (e0 : ev_ctx Ξ b0) => apply_noConfusion (a β b) (a2 β b0) (DepElim.eq_simplification_sigma1 a a2 b b0 (fun H : a = a2 => DepElim.solution_left a2 (fun (b1 : ty0) (t0 : term (Ξ βΆβ + (a2 β b1) βΆβ + a2) b1) (v1 : val Ξ a2) (e1 : ev_ctx Ξ b0) (H0 : b1 = b0) => DepElim.solution_left b0 (fun (t1 : term (Ξ βΆβ + ... βΆβ + a2) b0) (v2 : val Ξ a2) => inl β Cut (t1 /[ Lam t1, v2])) b1 H0 t0 v1 e1) a H b t v0 e0)) end (v `α΅₯β e) (Ο `ββ e) eq_refl with | inl x => TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x0 := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x0) in ret_delay β eval_step) T1_0 x) | inr y => RetF y end match match vv in (val _ t) return (val Ξ a2 -> ev_ctx Ξ b0 -> t = a2 β b0 -> state Ξ + nf Ξ) with | @Var _ a c => fun (v0 : val Ξ a2) (e0 : ev_ctx Ξ b0) (H : a = a2 β b0) => DepElim.solution_left (a2 β b0) (fun (c0 : cvar Ξ + (a2 β b0)) (v1 : val Ξ a2) (e1 : ev_ctx Ξ b0) => inr (c0 β OApp β¦ (! βΆβ v1) βΆβ e1 β¦)) a H c v0 e0 | TT => fun (_ : val Ξ a2) (_ : ev_ctx Ξ b0) => apply_noConfusion ΞΉ (a2 β b0) (False_rect (state Ξ + nf Ξ)) | @Lam _ a b t => fun (v0 : val Ξ a2) (e0 : ev_ctx Ξ b0) => apply_noConfusion (a β b) (a2 β b0) (DepElim.eq_simplification_sigma1 a a2 b b0 (fun H : a = a2 => DepElim.solution_left a2 (fun (b1 : ty0) (t0 : term (Ξ βΆβ + (a2 β b1) βΆβ + a2) b1) (v1 : val Ξ a2) (e1 : ev_ctx Ξ b0) (H0 : b1 = b0) => DepElim.solution_left b0 (fun (t1 : term (Ξ βΆβ + ... βΆβ + a2) b0) (v2 : val Ξ a2) => inl β Cut (t1 /[ Lam t1, v2])) b1 H0 t0 v1 e1) a H b t v0 e0)) end (v `α΅₯β e) (Ο `ββ e) eq_refl with | inl x => TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x0 := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x0) in ret_delay β eval_step) T1_0 x) | inr y => RetF y endΞ: t_ctx
a0, b: ty0
t: term (Ξ βΆβ + (a0 β b) βΆβ + a0) b
v: val Ξ a0
Ο: ev_ctx Ξ b
Ξ: t_ctx
R: relα΅’ (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ)) (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ))
CIH: forall (c : state Ξ) (a : Ξ =[ val_m ]> Ξ), it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ a β m_obs c `ββ a)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a)))
e: Ξ =[ val_m ]> Ξit_eqF Event.emptyβ (fun _ : T1 => nf_eq) (it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R) T1_0 (TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x) in ret_delay β eval_step) T1_0 ((t `ββ a_shift2 e /[ Lam (t `ββ a_shift2 e), v `α΅₯β e]) β Ο `ββ e))) (TauF (Structure.subst (fun pat : T1 => let 'T1_0 as x := pat return (Obs.nf obs_op val_m Ξ -> itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ) x) in fun y : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty y) (nf_var y)) (nf_obs y) (nf_args y)) `ββ e β m_obs (obs_app (a_id (nf_ty y) (nf_var y)) (nf_obs y) (nf_args y)) `ββ e)) T1_0 (Structure.iter (fun pat : T1 => let 'T1_0 as x := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x) in ret_delay β eval_step) T1_0 ((t /[ Lam t, v]) β Ο))))Ξ: t_ctx
a0, b: ty0
t: term (Ξ βΆβ + (a0 β b) βΆβ + a0) b
v: val Ξ a0
Ο: ev_ctx Ξ b
Ξ: t_ctx
R: relα΅’ (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ)) (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ))
CIH: forall (c : state Ξ) (a : Ξ =[ val_m ]> Ξ), it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ a β m_obs c `ββ a)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a)))
e: Ξ =[ val_m ]> Ξit_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval ((t `ββ a_shift2 e /[ (Lam t : val_m Ξ + (a0 β b)) α΅₯β e, (v : val_m Ξ + a0) α΅₯β e]) β Ο `ββ e)) (bind_delay' (stlc_eval ((t /[ Lam t, v]) β Ο)) (fun y : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty y) (nf_var y)) (nf_obs y) (nf_args y)) `ββ e β m_obs (obs_app (a_id (nf_ty y) (nf_var y)) (nf_obs y) (nf_args y)) `ββ e)))apply CIH.Ξ: t_ctx
a0, b: ty0
t: term (Ξ βΆβ + (a0 β b) βΆβ + a0) b
v: val Ξ a0
Ο: ev_ctx Ξ b
Ξ: t_ctx
R: relα΅’ (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ)) (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ))
CIH: forall (c : state Ξ) (a : Ξ =[ val_m ]> Ξ), it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ a β m_obs c `ββ a)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a)))
e: Ξ =[ val_m ]> Ξit_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval ((t /[ Lam t, v]) `ββ e β Ο `ββ e)) (bind_delay' (stlc_eval ((t /[ Lam t, v]) β Ο)) (fun y : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty y) (nf_var y)) (nf_obs y) (nf_args y)) `ββ e β m_obs (obs_app (a_id (nf_ty y) (nf_var y)) (nf_obs y) (nf_args y)) `ββ e)))econstructor; refold_eval; apply CIH.Ξ: t_ctx
b, a0: ty0
t1: term Ξ (a0 β b)
t2: term Ξ a0
Ο: ev_ctx Ξ b
Ξ: t_ctx
R: relα΅’ (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ)) (itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ))
CIH: forall (c : state Ξ) (a : Ξ =[ val_m ]> Ξ), it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R T1_0 (stlc_eval (m_var c `ββ a β m_obs c `ββ a)) (bind_delay' (stlc_eval c) (fun n : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a β m_obs (obs_app (a_id (nf_ty n) (nf_var n)) (nf_obs n) (nf_args n)) `ββ a)))
e: Ξ =[ val_m ]> Ξit_eqF Event.emptyβ (fun _ : T1 => nf_eq) (it_eq_t Event.emptyβ (fun _ : T1 => nf_eq) R) T1_0 (TauF (Structure.iter (fun pat : T1 => let 'T1_0 as x := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x) in ret_delay β eval_step) T1_0 (t2 `ββ e β K1 (t1 `ββ e) (Ο `ββ e)))) (TauF (Structure.subst (fun pat : T1 => let 'T1_0 as x := pat return (Obs.nf obs_op val_m Ξ -> itree Event.emptyβ (fun _ : T1 => Obs.nf obs_op val_m Ξ) x) in fun y : Obs.nf obs_op val_m Ξ => stlc_eval (m_var (obs_app (a_id (nf_ty y) (nf_var y)) (nf_obs y) (nf_args y)) `ββ e β m_obs (obs_app (a_id (nf_ty y) (nf_var y)) (nf_obs y) (nf_args y)) `ββ e)) T1_0 (Structure.iter (fun pat : T1 => let 'T1_0 as x := pat return (state Ξ -> itree Event.emptyβ ((fun _ : T1 => state Ξ) +α΅’ (fun _ : T1 => nf Ξ)) x) in ret_delay β eval_step) T1_0 (t2 β K1 t1 Ο))))
Just like the above proof had the flavor of a composition law of module, this one has the flavor of an identity law. It states that evaluating a normal form is the identity computation.
Ξ: t_ctx
u: Obs.nf obs_op val_m Ξstlc_eval (obs_app (a_id (nf_ty u) (nf_var u)) (nf_obs u) (nf_args u)) β ret_delay uΞ: t_ctx
a: ty
i: Ξ β a
p: obs_op a
Ξ³: dom p =[ val_m ]> Ξstlc_eval (obs_app (a_id a i) p (nf_args (i β p β¦ Ξ³ β¦))) β ret_delay (i β p β¦ Ξ³ β¦)Ξ: t_ctx
a0: ty0
i: Ξ β Β¬ a0
Ξ³: dom ORet =[ val_m ]> Ξstlc_eval (Ξ³ + a0 Ctx.top β K0 i) β ret_delay (i β ORet β¦ Ξ³ β¦)Ξ: t_ctx
a1, b: ty0
i: Ξ β + (a1 β b)
Ξ³: dom OApp =[ val_m ]> Ξstlc_eval (Var i β K2 (Ξ³ + a1 (pop Ctx.top)) (Ξ³ Β¬ b Ctx.top)) β ret_delay (i β OApp β¦ Ξ³ β¦)all: econstructor; intros ? v; do 3 (dependent elimination v; auto).Ξ: t_ctx
a0: ty0
i: Ξ β Β¬ a0
Ξ³: dom ORet =[ val_m ]> Ξnf_eq (i β ORet β¦ ! βΆβ Ξ³ + a0 Ctx.top β¦) (i β ORet β¦ Ξ³ β¦)Ξ: t_ctx
a1, b: ty0
i: Ξ β + (a1 β b)
Ξ³: dom OApp =[ val_m ]> Ξnf_eq (i β OApp β¦ (! βΆβ Ξ³ + a1 (pop Ctx.top)) βΆβ Ξ³ Β¬ b Ctx.top β¦) (i β OApp β¦ Ξ³ β¦)
This last proof is the technical condition we hinted at. It is a proof of well-foundedness of some relation, and what it amounts to is that if we repeatedly instantiate the head variable of a normal form by a value which is not a variable, after a finite number of times doing so we will eventually reach something that is not a normal form.
For our calculus this number is at most 2, the pathological state being
β¨ x | y β©
, which starts by being stuck on y
, but when instanciating by
some non-variable Ο
, β¨ x | Ο β©
is still stuck, this time on x
. After
another step it will definitely be unstuck and evaluation will be able to do
a reduction step.
It is slightly tedious to prove but amount again to a "proof by case splitting".
well_founded head_inst_nostepx: ty
p: obs xAcc head_inst_nostep (x,' p)a0, b: ty0forall y : {x : ty & obs x}, head_inst_nostep y (+ (a0 β b),' OApp) -> Acc head_inst_nostep ya: ty0forall y : {x : ty & obs x}, head_inst_nostep y (Β¬ a,' ORet) -> Acc head_inst_nostep ya0, b: ty0forall y : {x : ty & obs x}, head_inst_nostep y (+ (a0 β b),' OApp) -> Acc head_inst_nostep ya0, b: ty0
z: ty
p: obs z
H: head_inst_nostep (z,' p) (+ (a0 β b),' OApp)Acc head_inst_nostep (z,' p)a0, b, a: ty0
Ξ: t_ctx
v: val_m Ξ + (a0 β b)
a1: dom OApp =[ val_m ]> Ξ
i: Ξ β projT1 (Β¬ a,' ORet)
t0: is_var v -> T0
i0: evalβ (v β OApp β¦ a1 β¦) β ret_delay (i β projT2 (Β¬ a,' ORet))Acc head_inst_nostep (Β¬ a,' ORet)a0, b, a1, b0: ty0
Ξ: t_ctx
v: val_m Ξ + (a0 β b)
a: dom OApp =[ val_m ]> Ξ
i: Ξ β projT1 (+ (a1 β b0),' OApp)
t0: is_var v -> T0
i0: evalβ (v β OApp β¦ a β¦) β ret_delay (i β projT2 (+ (a1 β b0),' OApp))Acc head_inst_nostep (+ (a1 β b0),' OApp)all: apply it_eq_step in i0; now inversion i0.a3, b0, a: ty0
Ξ: t_ctx
t1: term (Ξ βΆβ + (a3 β b0) βΆβ + a3) b0
a1: dom OApp =[ val_m ]> Ξ
i: Ξ β projT1 (Β¬ a,' ORet)
t0: is_var (Lam t1) -> T0
i0: evalβ (Lam t1 β OApp β¦ a1 β¦) β ret_delay (i β projT2 (Β¬ a,' ORet))Acc head_inst_nostep (Β¬ a,' ORet)a3, b1, a1, b0: ty0
Ξ: t_ctx
t1: term (Ξ βΆβ + (a3 β b1) βΆβ + a3) b1
a: dom OApp =[ val_m ]> Ξ
i: Ξ β projT1 (+ (a1 β b0),' OApp)
t0: is_var (Lam t1) -> T0
i0: evalβ (Lam t1 β OApp β¦ a β¦) β ret_delay (i β projT2 (+ (a1 β b0),' OApp))Acc head_inst_nostep (+ (a1 β b0),' OApp)a: ty0forall y : {x : ty & obs x}, head_inst_nostep y (Β¬ a,' ORet) -> Acc head_inst_nostep ya: ty0
z: ty
p: obs z
H: head_inst_nostep (z,' p) (Β¬ a,' ORet)Acc head_inst_nostep (z,' p)a, a0: ty0
Ξ: t_ctx
v: ev_ctx Ξ a
a1: (β β βΆβ + a) =[ val_m ]> Ξ
i: cvar Ξ Β¬ a0
t0: is_var v -> T0
i0: evalβ (a1 + a Ctx.top β v) β ret_delay (i β ORet)Acc head_inst_nostep (Β¬ a0,' ORet)a, a1, b: ty0
Ξ: t_ctx
v: ev_ctx Ξ a
a0: (β β βΆβ + a) =[ val_m ]> Ξ
i: cvar Ξ + (a1 β b)
t0: is_var v -> T0
i0: evalβ (a0 + a Ctx.top β v) β ret_delay (i β OApp)Acc head_inst_nostep (+ (a1 β b),' OApp)a3, a0: ty0
Ξ: t_ctx
b: ty0
t1: term Ξ (a3 β b)
e: ev_ctx Ξ b
a1: (β β βΆβ + a3) =[ val_m ]> Ξ
i: cvar Ξ Β¬ a0
t0: is_var (K1 t1 e) -> T0
i0: evalβ (a1 + a3 Ctx.top β K1 t1 e) β ret_delay (i β ORet)Acc head_inst_nostep (Β¬ a0,' ORet)a4, b0, a0: ty0
Ξ: t_ctx
v: val Ξ a4
e0: ev_ctx Ξ b0
a1: (β β βΆβ + (a4 β b0)) =[ val_m ]> Ξ
i: cvar Ξ Β¬ a0
t0: is_var (K2 v e0) -> T0
i0: evalβ (a1 + (a4 β b0) Ctx.top β K2 v e0) β ret_delay (i β ORet)Acc head_inst_nostep (Β¬ a0,' ORet)a, a1, b: ty0
Ξ: t_ctx
v: ev_ctx Ξ a
a0: (β β βΆβ + a) =[ val_m ]> Ξ
i: cvar Ξ + (a1 β b)
t0: is_var v -> T0
i0: evalβ (a0 + a Ctx.top β v) β ret_delay (i β OApp)Acc head_inst_nostep (+ (a1 β b),' OApp)apply it_eq_step in i0; now inversion i0.a3, a0: ty0
Ξ: t_ctx
b: ty0
t1: term Ξ (a3 β b)
e: ev_ctx Ξ b
a1: (β β βΆβ + a3) =[ val_m ]> Ξ
i: cvar Ξ Β¬ a0
t0: is_var (K1 t1 e) -> T0
i0: evalβ (a1 + a3 Ctx.top β K1 t1 e) β ret_delay (i β ORet)Acc head_inst_nostep (Β¬ a0,' ORet)a4, b0, a0: ty0
Ξ: t_ctx
v: val Ξ a4
e0: ev_ctx Ξ b0
a1: (β β βΆβ + (a4 β b0)) =[ val_m ]> Ξ
i: cvar Ξ Β¬ a0
t0: is_var (K2 v e0) -> T0
i0: evalβ (a1 + (a4 β b0) Ctx.top β K2 v e0) β ret_delay (i β ORet)Acc head_inst_nostep (Β¬ a0,' ORet)a4, b0, a0: ty0
Ξ: t_ctx
v: val Ξ a4
e0: ev_ctx Ξ b0
i: cvar Ξ Β¬ a0
t0: is_var (K2 v e0) -> T0
vv: val_m Ξ + (a4 β b0)
i0: evalβ (vv β K2 v e0) β ret_delay (i β ORet)Acc head_inst_nostep (Β¬ a0,' ORet)inversion r_rel.a4, b0, a0: ty0
Ξ: t_ctx
v: val Ξ a4
e0: ev_ctx Ξ b0
i: cvar Ξ Β¬ a0
t0: is_var (K2 v e0) -> T0
c: Ξ β + (a4 β b0)
r_rel: eqα΅’ (fun _ : T1 => obs_op β Ξ) T1_0 (c β OApp β¦ (! βΆβ v) βΆβ e0 β¦) (i β ORet)Acc head_inst_nostep (Β¬ a0,' ORet)a, a1, b: ty0
Ξ: t_ctx
v: ev_ctx Ξ a
a0: (β β βΆβ + a) =[ val_m ]> Ξ
i: cvar Ξ + (a1 β b)
t0: is_var v -> T0
i0: evalβ (a0 + a Ctx.top β v) β ret_delay (i β OApp)Acc head_inst_nostep (+ (a1 β b),' OApp)a, a1, b: ty0
Ξ: t_ctx
v: ev_ctx Ξ a
a0: (β β βΆβ + a) =[ val_m ]> Ξ
i: cvar Ξ + (a1 β b)
t0: is_var v -> T0
i0: evalβ (a0 + a Ctx.top β v) β ret_delay (i β OApp)
z: ty
p: obs z
H: head_inst_nostep (z,' p) (+ (a1 β b),' OApp)Acc head_inst_nostep (z,' p)a, a1, b: ty0
Ξ: t_ctx
v: ev_ctx Ξ a
a0: (β β βΆβ + a) =[ val_m ]> Ξ
i: cvar Ξ + (a1 β b)
t0: is_var v -> T0
i0: evalβ (a0 + a Ctx.top β v) β ret_delay (i β OApp)
a2: ty0
Ξ0: t_ctx
v0: val_m Ξ0 + (a1 β b)
a3: dom OApp =[ val_m ]> Ξ0
i1: Ξ0 β projT1 (Β¬ a2,' ORet)
t1: is_var v0 -> T0
i2: evalβ (v0 β OApp β¦ a3 β¦) β ret_delay (i1 β projT2 (Β¬ a2,' ORet))Acc head_inst_nostep (Β¬ a2,' ORet)a, a1, b: ty0
Ξ: t_ctx
v: ev_ctx Ξ a
a0: (β β βΆβ + a) =[ val_m ]> Ξ
i: cvar Ξ + (a1 β b)
t0: is_var v -> T0
i0: evalβ (a0 + a Ctx.top β v) β ret_delay (i β OApp)
a3, b0: ty0
Ξ0: t_ctx
v0: val_m Ξ0 + (a1 β b)
a2: dom OApp =[ val_m ]> Ξ0
i1: Ξ0 β projT1 (+ (a3 β b0),' OApp)
t1: is_var v0 -> T0
i2: evalβ (v0 β OApp β¦ a2 β¦) β ret_delay (i1 β projT2 (+ (a3 β b0),' OApp))Acc head_inst_nostep (+ (a3 β b0),' OApp)all: apply it_eq_step in i2; now inversion i2. Qed.a, a5, b0: ty0
Ξ: t_ctx
v: ev_ctx Ξ a
a0: (β β βΆβ + a) =[ val_m ]> Ξ
i: cvar Ξ + (a5 β b0)
t0: is_var v -> T0
i0: evalβ (a0 + a Ctx.top β v) β ret_delay (i β OApp)
a2: ty0
Ξ0: t_ctx
t2: term (Ξ0 βΆβ + (a5 β b0) βΆβ + a5) b0
a3: dom OApp =[ val_m ]> Ξ0
i1: Ξ0 β projT1 (Β¬ a2,' ORet)
t1: is_var (Lam t2) -> T0
i2: evalβ (Lam t2 β OApp β¦ a3 β¦) β ret_delay (i1 β projT2 (Β¬ a2,' ORet))Acc head_inst_nostep (Β¬ a2,' ORet)a, a5, b1: ty0
Ξ: t_ctx
v: ev_ctx Ξ a
a0: (β β βΆβ + a) =[ val_m ]> Ξ
i: cvar Ξ + (a5 β b1)
t0: is_var v -> T0
i0: evalβ (a0 + a Ctx.top β v) β ret_delay (i β OApp)
a3, b0: ty0
Ξ0: t_ctx
t2: term (Ξ0 βΆβ + (a5 β b1) βΆβ + a5) b1
a2: dom OApp =[ val_m ]> Ξ0
i1: Ξ0 β projT1 (+ (a3 β b0),' OApp)
t1: is_var (Lam t2) -> T0
i2: evalβ (Lam t2 β OApp β¦ a2 β¦) β ret_delay (i1 β projT2 (+ (a3 β b0),' OApp))Acc head_inst_nostep (+ (a3 β b0),' OApp)
At this point we have finished all the hard work! We already enjoy the generic correctness theorem but don't know it yet! Lets define some shorthands for some generic notions applied to our case, to make it a welcoming nest.
The whole semantic is parametrized by typing scope Ξ
of "final channels".
Typically this can be instanciated with the singleton [ Β¬ ans ]
for some
chosen type ans
, which will correspond with the outside type of the
testing-contexts from CIU-equivalence. Usually this answer type is taken among
the positive (or shareable) types of our language, but in fact using our
observation machinery we can project the value of any type onto its "shareable
part". This is why our generic proof abstracts over this answer type and even
allows several of them at the same time (that is, Ξ
). In our case, as all
types in our language are unshareable, the positive part of any value is
pretty useless: it is always a singleton. Yet our notion of testing still
distinguishes terminating from non-terminating programs.
As discussed in the paper, the "native output" of the generic theorem is correctness with respect to an equivalence we call "substitution equivalence". We will recover a more standard CIU later on.
Definition subst_eq Ξ {Ξ} : relation (state Ξ) := fun u v => forall Ο : Ξ =[val_m]> Ξ, evalβ (u ββ Ο) β evalβ (v ββ Ο) . Notation "x βS[ Ξ ]β y" := (subst_eq Ξ x y) (at level 10).
Our semantic objects live in what is defined in the generic construction as
ogs_act
, that is active strategies for the OGS game. They come with their
own notion of equivalence, weak bisimilarity and we get to interpret states
into semantic objects.
Definition sem_act Ξ Ξ := ogs_act (obs := obs_op) Ξ (β βΆβ Ξ) . Definition ogs_weq_act Ξ {Ξ} : relation (sem_act Ξ Ξ) := fun u v => u β v . Notation "u β[ Ξ ]β v" := (ogs_weq_act Ξ u v) (at level 40). Definition interp_act_s Ξ {Ξ} (c : state Ξ) : sem_act Ξ Ξ := m_strat (β βΆβ Ξ) (inj_init_act Ξ c) . Notation "OGSβ¦ t β§" := (interp_act_s _ t) .
We can now obtain our instance of the correctness result!
exact (ogs_correction Ξ x y). Qed.Ξ, Ξ: t_ctx
x, y: state ΞOGSβ¦ x β§ β[ Ξ ]β OGSβ¦ y β§ -> x βS[ Ξ ]β y
CIU-equivalence more usually defined as a relation on terms (and not some states), and involves an evaluation context. In our formalism it amounts to the following definition.
Definition ciu_eq Ξ {Ξ a} : relation (term Ξ a) := fun u v => forall (Ο : Ξ =[val_m]> Ξ) (Ο : ev_ctx Ξ a), evalβ ((u `ββ Ο) β Ο) β evalβ ((v `ββ Ο) β Ο) . Notation "x βC[ Ξ ]β y" := (ciu_eq Ξ x y) (at level 10).
Now from a term we can always construct a state by naming it, that is, placing the term opposite of a fresh context variable.
Definition c_init {Ξ a} (t : term Ξ a) : state (Ξ βΆβ Β¬ a) := t_shift _ t β K0 Ctx.top . Notation "Tβ¦ t β§" := (OGSβ¦ c_init t β§) .
Similarly, from an evaluation context and a substitution, we can form an extended substitution. Without surprise these two constructions simplify well in terms of substitution.
Definition a_of_sk {Ξ Ξ a} (Ο : Ξ =[val_m]> Ξ) (Ο : ev_ctx Ξ a) : (Ξ βΆβ Β¬ a) =[val_m]> Ξ := Ο βΆβ (Ο : val_m _ (Β¬ _)) .cbn; unfold t_shift; now rewrite t_sub_ren. Qed.Ξ, Ξ: t_ctx
a: ty0
t: term Ξ a
Ο: Ξ =[ val_m ]> Ξ
Ο: ev_ctx Ξ at `ββ Ο β Ο = c_init t ββ a_of_sk Ο Ο
We can now obtain a correctness theorem with respect to standard CIU-equivalence by embedding terms into states. Proving that CIU-equivalence entails our substitution equivalence is left to the reader!
Ξ, Ξ: t_ctx
a: ty0
x, y: term Ξ aTβ¦ x β§ β[ Ξ ]β Tβ¦ y β§ -> x βC[ Ξ ]β ynow apply stlc_subst_correct. Qed.Ξ, Ξ: t_ctx
a: ty0
x, y: term Ξ a
H: Tβ¦ x β§ β[ Ξ ]β Tβ¦ y β§
Ο: Ξ =[ val_m ]> Ξ
k: ev_ctx Ξ aevalβ (c_init x ββ a_of_sk Ο k) β evalβ (c_init y ββ a_of_sk Ο k)
[AACMM21] | Guillaume Allais et al, "A type- and scope-safe universe of syntaxes with binding: their semantics and proofs", 2021. |
[FS22] | Marcelo Fiore & Dmitrij Szamozvancev, "Formal Metatheory of Second-Order Abstract Syntax", 2022. |
[L05] | Soren Lassen, "Eager Normal Form Bisimulation", 2005. |