From OGS Require Import Prelude. From OGS.Utils Require Import Psh Rel. From OGS.Ctx Require Import All Ctx Covering Subset Subst. From OGS.ITree Require Import Event ITree Eq Delay Structure Properties. From OGS.OGS Require Import Soundness.
In this file we instanciate our OGS construction with the fully-dual polarized mu-mu-tilde calculus 'System D' from P. Downen & Z. Ariola. The presentation may be slightly unusual as we go for one-sided sequent. The only real divergence from the original calculus is the addition of a restricted form of recursion, making the language non-normalizing.
Type have polarities, basically whether their values are CBV-biased or CBN-biased
Variant pol : Type := pos | neg .
Syntax of types. We have a fully dual type system with:
0
, positive void (no constructor),β€
, negative unit (no destructor),β₯
, negative void (one trivial destructor),1
, positive unit (one trivial constructor),A β B
, positive product (pairs with pattern-matching),A β
B
, negative sum (one binary destructor),A β B
, positive sum (usual coproduct with injections),A & B
, negative product (usual product with projections),β A
, positive shift (thunking),β A
, negative shift ('returners'),β A
, positive negation (approximately continuations accepting an A
),Β¬ A
, negative negation (approximately refutations of A
).We opt for an explicit treatment of polarity, by indexing the family of types.
Inductive pre_ty : pol -> Type :=
| Zer : pre_ty pos
| Top : pre_ty neg
| One : pre_ty pos
| Bot : pre_ty neg
| Tens : pre_ty pos -> pre_ty pos -> pre_ty pos
| Par : pre_ty neg -> pre_ty neg -> pre_ty neg
| Or : pre_ty pos -> pre_ty pos -> pre_ty pos
| And : pre_ty neg -> pre_ty neg -> pre_ty neg
| ShiftP : pre_ty neg -> pre_ty pos
| ShiftN : pre_ty pos -> pre_ty neg
| NegP : pre_ty neg -> pre_ty pos
| NegN : pre_ty pos -> pre_ty neg
.
Notation "0" := (Zer) : ty_scope . Notation "1" := (One) : ty_scope . Notation "β€" := (Top) : ty_scope . Notation "β₯" := (Bot) : ty_scope . Notation "A β B" := (Tens A B) (at level 40) : ty_scope. Notation "A β B" := (Par A B) (at level 40) : ty_scope . Notation "A β B" := (Or A B) (at level 40) : ty_scope. Notation "A & B" := (And A B) (at level 40) : ty_scope. Notation "β A" := (ShiftP A) (at level 40) : ty_scope. Notation "β A" := (ShiftN A) (at level 40) : ty_scope. Notation "β A" := (NegP A) (at level 5) : ty_scope . Notation "Β¬ A" := (NegN A) (at level 5) : ty_scope .
As hinted above, we go for one-sided sequents. This enables to have only one context
instead of two, simplifying the theory of substitution. On the flip-side, as we still
need two kinds of variables, the 'normal' ones and the co-variables, our contexts will
not contain bare types but side-annotated types. A variable of type A
will thus be
stored as \`-A
in the context while a co-variable of type A
will be stored as \`-A
.
Variant ty : Type :=
| LTy {p} : pre_ty p -> ty
| RTy {p} : pre_ty p -> ty
.
Notation "'`+' t" := (LTy t) (at level 5) : ty_scope . Notation "'`-' t" := (RTy t) (at level 5) : ty_scope . Equations t_neg : ty -> ty := t_neg `+a := `-a ; t_neg `-a := `+a . Notation "a β " := (t_neg a) (at level 5) : ty_scope.
Finally we define contexts as backward lists of side-annotated types.
We define the well-typed syntax of the language with 3 mutually defined syntactic categories: terms, weak head-normal forms and states ('language configurations' in the paper).
Nothing should be too surprising. A first notable point is that by choosing to have an
explicit notion of 'side' of a variable, we can have a single construct
for both mu and mu-tilde. A second notable point is our new slightly exotic RecL
and
RecR
constructions. They allow arbitrary recursion at co-terms of positive types and
at terms of negative types. These polarity restrictions allow us to have minimal
disruption of the evaluation rules.
Inductive term : t_ctx -> ty -> Type :=
| Mu {Ξ A} : state (Ξ βΆβ Aβ ) -> term Ξ A
| RecL {Ξ} {A : pre_ty pos} : term (Ξ βΆβ `-A) `-A -> term Ξ `-A
| RecR {Ξ} {A : pre_ty neg} : term (Ξ βΆβ `+A) `+A -> term Ξ `+A
| Whn {Ξ A} : whn Ξ A -> term Ξ A
with whn : t_ctx -> ty -> Type :=
| Var {Ξ A} : Ξ β A -> whn Ξ A
| ZerL {Ξ} : whn Ξ `-0
| TopR {Ξ} : whn Ξ `+β€
| OneR {Ξ} : whn Ξ `+1
| OneL {Ξ} : state Ξ -> whn Ξ `-1
| BotR {Ξ} : state Ξ -> whn Ξ `+β₯
| BotL {Ξ} : whn Ξ `-β₯
| TenR {Ξ A B} : whn Ξ `+A -> whn Ξ `+B -> whn Ξ `+(A β B)
| TenL {Ξ A B} : state (Ξ βΆβ `+A βΆβ `+B) -> whn Ξ `-(A β B)
| ParR {Ξ A B} : state (Ξ βΆβ `-A βΆβ `-B) -> whn Ξ `+(A β
B)
| ParL {Ξ A B} : whn Ξ `-A -> whn Ξ `-B -> whn Ξ `-(A β
B)
| OrR1 {Ξ A B} : whn Ξ `+A -> whn Ξ `+(A β B)
| OrR2 {Ξ A B} : whn Ξ `+B -> whn Ξ `+(A β B)
| OrL {Ξ A B} : state (Ξ βΆβ `+A) -> state (Ξ βΆβ `+B) -> whn Ξ `-(A β B)
| AndR {Ξ A B} : state (Ξ βΆβ `-A) -> state (Ξ βΆβ `-B) -> whn Ξ `+(A & B)
| AndL1 {Ξ A B} : whn Ξ `-A -> whn Ξ `-(A & B)
| AndL2 {Ξ A B} : whn Ξ `-B -> whn Ξ `-(A & B)
| ShiftPR {Ξ A} : term Ξ `+A -> whn Ξ `+(β A)
| ShiftPL {Ξ A} : state (Ξ βΆβ `+A) -> whn Ξ `-(β A)
| ShiftNR {Ξ A} : state (Ξ βΆβ `-A) -> whn Ξ `+(β A)
| ShiftNL {Ξ A} : term Ξ `-A -> whn Ξ `-(β A)
| NegPR {Ξ A} : whn Ξ `-A -> whn Ξ `+(β A)
| NegPL {Ξ A} : state (Ξ βΆβ `-A) -> whn Ξ `-(β A)
| NegNR {Ξ A} : state (Ξ βΆβ `+A) -> whn Ξ `+(Β¬ A)
| NegNL {Ξ A} : whn Ξ `+A -> whn Ξ `-(Β¬ A)
with state : t_ctx -> Type :=
| Cut {Ξ} p {A : pre_ty p} : term Ξ `+A -> term Ξ `-A -> state Ξ
.
Definition Cut' {Ξ A} : term Ξ A -> term Ξ Aβ -> state Ξ :=
match A with
| `+A => fun t1 t2 => Cut _ t1 t2
| `-A => fun t1 t2 => Cut _ t2 t1
end .
Values are not exactly weak head-normal forms, but depend on the polarity of the type. As positive types have CBV evaluation, their values are weak head-normal forms, but their co-values (evaluation contexts) are just any co-term (context) as they are delayed anyways. Dually for negative types, values are delayed hence can be any term while co-values must be weak head-normal form contexts.
Equations val : t_ctx -> ty -> Type := val Ξ (@LTy pos A) := whn Ξ `+A ; val Ξ (@RTy pos A) := term Ξ `-A ; val Ξ (@LTy neg A) := term Ξ `+A ; val Ξ (@RTy neg A) := whn Ξ `-A . Arguments val _ _ /.
We provide a 'smart-constructor' for variables, embedding variables in values.
Equations var : c_var ββ val :=
var _ (@LTy pos _) i := Var i ;
var _ (@RTy pos _) i := Whn (Var i) ;
var _ (@LTy neg _) i := Whn (Var i) ;
var _ (@RTy neg _) i := Var i .
#[global] Arguments var {Ξ} [x] / i.
Without surprise parallel renaming goes by a big mutual induction, shifting the renaming apropriately while going under binders. Note the use of the internal substitution hom to type it.
Equations t_rename : term ββ β¦ c_var , term β§β :=
t_rename _ _ (Mu c) _ f := Mu (s_rename _ c _ (r_shift1 f)) ;
t_rename _ _ (RecL t) _ f := RecL (t_rename _ _ t _ (r_shift1 f)) ;
t_rename _ _ (RecR t) _ f := RecR (t_rename _ _ t _ (r_shift1 f)) ;
t_rename _ _ (Whn v) _ f := Whn (w_rename _ _ v _ f) ;
with w_rename : whn ββ β¦ c_var , whn β§β :=
w_rename _ _ (Var i) _ f := Var (f _ i) ;
w_rename _ _ (ZerL) _ f := ZerL ;
w_rename _ _ (TopR) _ f := TopR ;
w_rename _ _ (OneR) _ f := OneR ;
w_rename _ _ (OneL c) _ f := OneL (s_rename _ c _ f) ;
w_rename _ _ (BotR c) _ f := BotR (s_rename _ c _ f) ;
w_rename _ _ (BotL) _ f := BotL ;
w_rename _ _ (TenR v1 v2) _ f := TenR (w_rename _ _ v1 _ f) (w_rename _ _ v2 _ f) ;
w_rename _ _ (TenL c) _ f := TenL (s_rename _ c _ (r_shift2 f)) ;
w_rename _ _ (ParR c) _ f := ParR (s_rename _ c _ (r_shift2 f)) ;
w_rename _ _ (ParL k1 k2) _ f := ParL (w_rename _ _ k1 _ f) (w_rename _ _ k2 _ f) ;
w_rename _ _ (OrR1 v) _ f := OrR1 (w_rename _ _ v _ f) ;
w_rename _ _ (OrR2 v) _ f := OrR2 (w_rename _ _ v _ f) ;
w_rename _ _ (OrL c1 c2) _ f := OrL (s_rename _ c1 _ (r_shift1 f))
(s_rename _ c2 _ (r_shift1 f)) ;
w_rename _ _ (AndR c1 c2) _ f := AndR (s_rename _ c1 _ (r_shift1 f))
(s_rename _ c2 _ (r_shift1 f)) ;
w_rename _ _ (AndL1 k) _ f := AndL1 (w_rename _ _ k _ f) ;
w_rename _ _ (AndL2 k) _ f := AndL2 (w_rename _ _ k _ f) ;
w_rename _ _ (ShiftPR t) _ f := ShiftPR (t_rename _ _ t _ f) ;
w_rename _ _ (ShiftPL c) _ f := ShiftPL (s_rename _ c _ (r_shift1 f)) ;
w_rename _ _ (ShiftNR c) _ f := ShiftNR (s_rename _ c _ (r_shift1 f)) ;
w_rename _ _ (ShiftNL t) _ f := ShiftNL (t_rename _ _ t _ f) ;
w_rename _ _ (NegPR k) _ f := NegPR (w_rename _ _ k _ f) ;
w_rename _ _ (NegPL c) _ f := NegPL (s_rename _ c _ (r_shift1 f)) ;
w_rename _ _ (NegNR c) _ f := NegNR (s_rename _ c _ (r_shift1 f)) ;
w_rename _ _ (NegNL v) _ f := NegNL (w_rename _ _ v _ f) ;
with s_rename : state ββ β¦ c_var , state β§β :=
s_rename _ (Cut _ v k) _ f := Cut _ (t_rename _ _ v _ f) (t_rename _ _ k _ f) .
We extend it to values...
Equations v_rename : val ββ β¦ c_var , val β§β :=
v_rename _ (@LTy pos a) := w_rename _ _ ;
v_rename _ (@RTy pos a) := t_rename _ _ ;
v_rename _ (@LTy neg a) := t_rename _ _ ;
v_rename _ (@RTy neg a) := w_rename _ _ .
... provide a couple infix notations...
Notation "t ββα΅£ r" := (t_rename _ _ t _ r%asgn) (at level 14).
Notation "w `α΅₯βα΅£ r" := (w_rename _ _ w _ r%asgn) (at level 14).
Notation "v α΅₯βα΅£ r" := (v_rename _ _ v _ r%asgn) (at level 14).
Notation "s ββα΅£ r" := (s_rename _ s _ r%asgn) (at level 14).
... and extend it to assignments.
Definition a_ren {Ξ1 Ξ2 Ξ3} : Ξ1 =[val]> Ξ2 -> Ξ2 β Ξ3 -> Ξ1 =[val]> Ξ3 :=
fun f g _ i => v_rename _ _ (f _ i) _ g .
Arguments a_ren {_ _ _} _ _ _ _ /.
Notation "a βα΅£ r" := (a_ren a r%asgn) (at level 14) : asgn_scope.
The following bunch of shifting functions will help us define parallel substitution.
Definition t_shift1 {Ξ y} : term Ξ βα΅’ term (Ξ βΆβ y) := fun _ t => t ββα΅£ r_pop.
Definition w_shift1 {Ξ y} : whn Ξ βα΅’ whn (Ξ βΆβ y) := fun _ w => w `α΅₯βα΅£ r_pop.
Definition s_shift1 {Ξ y} : state Ξ -> state (Ξ βΆβ y) := fun s => s ββα΅£ r_pop.
Definition v_shift1 {Ξ y} : val Ξ βα΅’ val (Ξ βΆβ y) := fun _ v => v α΅₯βα΅£ r_pop.
Definition v_shift2 {Ξ y z} : val Ξ βα΅’ val (Ξ βΆβ y βΆβ z) := fun _ v => v α΅₯βα΅£ (r_pop α΅£β r_pop).
Definition a_shift1 {Ξ Ξ} [y] (a : Ξ =[val]> Ξ) : (Ξ βΆβ y) =[val]> (Ξ βΆβ y)
:= [ fun _ i => v_shift1 _ (a _ i) ,β var top ].
Definition a_shift2 {Ξ Ξ} [y z] (a : Ξ =[val]> Ξ) : (Ξ βΆβ y βΆβ z) =[val]> (Ξ βΆβ y βΆβ z)
:= [ [ fun _ i => v_shift2 _ (a _ i) ,β var (pop top) ] ,β var top ].
We also define two embeddings linking the various syntactical categories.
Equations v_of_w Ξ A : whn Ξ A -> val Ξ A := v_of_w _ (@LTy pos _) v := v ; v_of_w _ (@RTy pos _) u := Whn u ; v_of_w _ (@LTy neg _) u := Whn u ; v_of_w _ (@RTy neg _) k := k . Arguments v_of_w {Ξ A} v. #[global] Coercion v_of_w : whn >-> val. Equations t_of_v Ξ A : val Ξ A -> term Ξ A := t_of_v _ (@LTy pos _) v := Whn v ; t_of_v _ (@RTy pos _) u := u ; t_of_v _ (@LTy neg _) u := u ; t_of_v _ (@RTy neg _) k := Whn k . Arguments t_of_v {Ξ A} v. #[global] Coercion t_of_v : val >-> term.
Having done with renaming, we reapply the same pattern to define parallel substitution. Note that substituting a weak head-normal form with values may not yield a weak head-normal form, but only a value!
Equations t_subst : term ββ β¦ val , term β§β :=
t_subst _ _ (Mu c) _ f := Mu (s_subst _ c _ (a_shift1 f)) ;
t_subst _ _ (RecL t) _ f := RecL (t_subst _ _ t _ (a_shift1 f)) ;
t_subst _ _ (RecR t) _ f := RecR (t_subst _ _ t _ (a_shift1 f)) ;
t_subst _ _ (Whn v) _ f := w_subst _ _ v _ f ;
with w_subst : whn ββ β¦ val , val β§β :=
w_subst _ _ (Var i) _ f := f _ i ;
w_subst _ _ (ZerL) _ f := Whn ZerL ;
w_subst _ _ (TopR) _ f := Whn TopR ;
w_subst _ _ (OneR) _ f := OneR ;
w_subst _ _ (OneL c) _ f := Whn (OneL (s_subst _ c _ f)) ;
w_subst _ _ (BotR c) _ f := Whn (BotR (s_subst _ c _ f)) ;
w_subst _ _ (BotL) _ f := BotL ;
w_subst _ _ (TenR v1 v2) _ f := TenR (w_subst _ _ v1 _ f) (w_subst _ _ v2 _ f) ;
w_subst _ _ (TenL c) _ f := Whn (TenL (s_subst _ c _ (a_shift2 f))) ;
w_subst _ _ (ParR c) _ f := Whn (ParR (s_subst _ c _ (a_shift2 f))) ;
w_subst _ _ (ParL k1 k2) _ f := ParL (w_subst _ _ k1 _ f) (w_subst _ _ k2 _ f) ;
w_subst _ _ (OrR1 v) _ f := OrR1 (w_subst _ _ v _ f) ;
w_subst _ _ (OrR2 v) _ f := OrR2 (w_subst _ _ v _ f) ;
w_subst _ _ (OrL c1 c2) _ f := Whn (OrL (s_subst _ c1 _ (a_shift1 f))
(s_subst _ c2 _ (a_shift1 f))) ;
w_subst _ _ (AndR c1 c2) _ f := Whn (AndR (s_subst _ c1 _ (a_shift1 f))
(s_subst _ c2 _ (a_shift1 f))) ;
w_subst _ _ (AndL1 k) _ f := AndL1 (w_subst _ _ k _ f) ;
w_subst _ _ (AndL2 k) _ f := AndL2 (w_subst _ _ k _ f) ;
w_subst _ _ (ShiftPR t) _ f := ShiftPR (t_subst _ _ t _ f) ;
w_subst _ _ (ShiftPL c) _ f := Whn (ShiftPL (s_subst _ c _ (a_shift1 f))) ;
w_subst _ _ (ShiftNR c) _ f := Whn (ShiftNR (s_subst _ c _ (a_shift1 f))) ;
w_subst _ _ (ShiftNL t) _ f := ShiftNL (t_subst _ _ t _ f) ;
w_subst _ _ (NegPR k) _ f := NegPR (w_subst _ _ k _ f) ;
w_subst _ _ (NegPL c) _ f := Whn (NegPL (s_subst _ c _ (a_shift1 f))) ;
w_subst _ _ (NegNR c) _ f := Whn (NegNR (s_subst _ c _ (a_shift1 f))) ;
w_subst _ _ (NegNL v) _ f := NegNL (w_subst _ _ v _ f) ;
with s_subst : state ββ β¦ val , state β§β :=
s_subst _ (Cut p v k) _ f := Cut p (t_subst _ _ v _ f) (t_subst _ _ k _ f) .
Notation "t `ββ a" := (t_subst _ _ t _ a%asgn) (at level 30).
Notation "w `α΅₯β a" := (w_subst _ _ w _ a%asgn) (at level 30).
Equations v_subst : val ββ β¦ val , val β§β :=
v_subst _ (@LTy pos a) v _ f := v `α΅₯β f ;
v_subst _ (@RTy pos a) t _ f := t `ββ f ;
v_subst _ (@LTy neg a) t _ f := t `ββ f ;
v_subst _ (@RTy neg a) k _ f := k `α΅₯β f .
With this in hand we can instanciate the relevant part of substitution monoid and module structures for values and states. This will provide us with the missing infix notations.
#[global] Instance val_m_monoid : subst_monoid val := {| v_var := @var ; v_sub := v_subst |} . #[global] Instance state_module : subst_module val state := {| c_sub := s_subst |} .
We now define helpers for substituting the top one or top two variables from a context.
Definition asgn1 {Ξ a} (v : val Ξ a) : (Ξ βΆβ a) =[val]> Ξ := [ var ,β v ] .
Definition asgn2 {Ξ a b} (v1 : val Ξ a) (v2 : val Ξ b) : (Ξ βΆβ a βΆβ b) =[val]> Ξ
:= [ [ var ,β v1 ] ,β v2 ].
Arguments asgn1 {_ _} & _.
Arguments asgn2 {_ _ _} & _ _.
Notation "β[ v ]" := (asgn1 v).
Notation "β[ v1 , v2 ]" := (asgn2 v1 v2).
When defining (co-)patterns, we will enforce a form of focalisation, where no negative variables are introduced. In this context, 'negative' is a new notion applying to side-annotated types, mixing both type polarity and side annotation: a side-annotated variable is positive iff it is a positive variable or a negative co-variable.
Equations is_neg : ty -> SProp :=
is_neg (@LTy pos a) := sEmpty ;
is_neg (@RTy pos a) := sUnit ;
is_neg (@LTy neg a) := sUnit ;
is_neg (@RTy neg a) := sEmpty .
We define negative types as a subset of types, and negative contexts as a subset of
contexts. Our generic infrastructure for contexts and variables really shines here as
the type of variables in a negative context is convertible to the type of variables in
the underlying context. See Ctx/Subset.v
.
Definition neg_ty : Type := sigS is_neg. Definition neg_coe : neg_ty -> ty := sub_elt. Global Coercion neg_coe : neg_ty >-> ty. Definition neg_ctx : Type := ctxS ty t_ctx is_neg. Definition neg_c_coe : neg_ctx -> ctx ty := sub_elt. Global Coercion neg_c_coe : neg_ctx >-> ctx.
We can now define patterns...
Inductive pat : ty -> Type :=
| PVarP (A : pre_ty neg) : pat `+A
| PVarN (A : pre_ty pos) : pat `-A
| POne : pat `+1
| PBot : pat `-β₯
| PTen {A B} : pat `+A -> pat `+B -> pat `+(A β B)
| PPar {A B} : pat `-A -> pat `-B -> pat `-(A β
B)
| POr1 {A B} : pat `+A -> pat `+(A β B)
| POr2 {A B} : pat `+B -> pat `+(A β B)
| PAnd1 {A B} : pat `-A -> pat `-(A & B)
| PAnd2 {A B} : pat `-B -> pat `-(A & B)
| PShiftP A : pat `+(β A)
| PShiftN A : pat `-(β A)
| PNegP {A} : pat `-A -> pat `+(β A)
| PNegN {A} : pat `+A -> pat `-(Β¬ A)
.
... and their domain, i.e. the context they bind.
Equations p_dom {t} : pat t -> neg_ctx :=
p_dom (PVarP A) := β
β βΆβ {| sub_elt := `+A ; sub_prf := stt |} ;
p_dom (PVarN A) := β
β βΆβ {| sub_elt := `-A ; sub_prf := stt |} ;
p_dom (POne) := β
β ;
p_dom (PBot) := β
β ;
p_dom (PTen p1 p2) := p_dom p1 +βΆβ p_dom p2 ;
p_dom (PPar p1 p2) := p_dom p1 +βΆβ p_dom p2 ;
p_dom (POr1 p) := p_dom p ;
p_dom (POr2 p) := p_dom p ;
p_dom (PAnd1 p) := p_dom p ;
p_dom (PAnd2 p) := p_dom p ;
p_dom (PShiftP A) := β
β βΆβ {| sub_elt := `+A ; sub_prf := stt |} ;
p_dom (PShiftN A) := β
β βΆβ {| sub_elt := `-A ; sub_prf := stt |} ;
p_dom (PNegP p) := p_dom p ;
p_dom (PNegN p) := p_dom p .
We finally instanciate the observation structure. Note that our generic formalization mostly cares about 'observations', that is co-patterns. As such we instanciate observations by patterns at the dual type.
Definition obs_op : Oper ty neg_ctx :=
{| o_op A := pat Aβ ; o_dom _ p := p_dom p |} .
Now come a rather tedious set of embeddings between syntactic categories related to patterns. We start by embedding patterns into weak head-normal forms.
Equations w_of_p {a} (p : pat a) : whn (p_dom p) a :=
w_of_p (PVarP _) := Var top ;
w_of_p (PVarN _) := Var top ;
w_of_p (POne) := OneR ;
w_of_p (PBot) := BotL ;
w_of_p (PTen p1 p2) := TenR (w_of_p p1 `α΅₯βα΅£ r_cat_l) (w_of_p p2 `α΅₯βα΅£ r_cat_r) ;
w_of_p (PPar p1 p2) := ParL (w_of_p p1 `α΅₯βα΅£ r_cat_l) (w_of_p p2 `α΅₯βα΅£ r_cat_r) ;
w_of_p (POr1 p) := OrR1 (w_of_p p) ;
w_of_p (POr2 p) := OrR2 (w_of_p p) ;
w_of_p (PAnd1 p) := AndL1 (w_of_p p) ;
w_of_p (PAnd2 p) := AndL2 (w_of_p p) ;
w_of_p (PShiftP _) := ShiftPR (Whn (Var top)) ;
w_of_p (PShiftN _) := ShiftNL (Whn (Var top)) ;
w_of_p (PNegP p) := NegPR (w_of_p p) ;
w_of_p (PNegN p) := NegNL (w_of_p p) .
#[global] Coercion w_of_p : pat >-> whn.
Now we explain how to split (some) weak head-normal forms into a pattern filled with
values. I am sorry in advance for your CPU-cycles wasted to typechecking these quite
hard dependent pattern matchings. We start off by two helpers for refuting impossible
variables in negative context, which because of the use of SProp
give trouble to
Equations
for deriving functional elimination principles if inlined.
Definition elim_var_p {Ξ : neg_ctx} {A : pre_ty pos} {X : Type} : Ξ β `+A -> X
:= fun i => match s_prf i with end .
Definition elim_var_n {Ξ : neg_ctx} {A : pre_ty neg} {X : Type} : Ξ β `-A -> X
:= fun i => match s_prf i with end .
Equations p_of_w_0p {Ξ : neg_ctx} (A : pre_ty pos) : whn Ξ `+A -> pat `+A :=
p_of_w_0p (0) (Var i) := elim_var_p i ;
p_of_w_0p (1) (Var i) := elim_var_p i ;
p_of_w_0p (A β B) (Var i) := elim_var_p i ;
p_of_w_0p (A β B) (Var i) := elim_var_p i ;
p_of_w_0p (β A) (Var i) := elim_var_p i ;
p_of_w_0p (β A) (Var i) := elim_var_p i ;
p_of_w_0p (1) (OneR) := POne ;
p_of_w_0p (A β B) (TenR v1 v2) := PTen (p_of_w_0p A v1) (p_of_w_0p B v2) ;
p_of_w_0p (A β B) (OrR1 v) := POr1 (p_of_w_0p A v) ;
p_of_w_0p (A β B) (OrR2 v) := POr2 (p_of_w_0p B v) ;
p_of_w_0p (β A) (ShiftPR _) := PShiftP A ;
p_of_w_0p (β A) (NegPR k) := PNegP (p_of_w_0n A k) ;
with p_of_w_0n {Ξ : neg_ctx} (A : pre_ty neg) : whn Ξ `-A -> pat `-A :=
p_of_w_0n (β€) (Var i) := elim_var_n i ;
p_of_w_0n (β₯) (Var i) := elim_var_n i ;
p_of_w_0n (A β
B) (Var i) := elim_var_n i ;
p_of_w_0n (A & B) (Var i) := elim_var_n i ;
p_of_w_0n (β A) (Var i) := elim_var_n i ;
p_of_w_0n (Β¬ A) (Var i) := elim_var_n i ;
p_of_w_0n (β₯) (BotL) := PBot ;
p_of_w_0n (A β
B) (ParL k1 k2) := PPar (p_of_w_0n A k1) (p_of_w_0n B k2) ;
p_of_w_0n (A & B) (AndL1 k) := PAnd1 (p_of_w_0n A k) ;
p_of_w_0n (A & B) (AndL2 k) := PAnd2 (p_of_w_0n B k) ;
p_of_w_0n (β A) (ShiftNL _) := PShiftN A ;
p_of_w_0n (Β¬ A) (NegNL v) := PNegN (p_of_w_0p A v) .
Equations p_dom_of_w_0p {Ξ : neg_ctx} (A : pre_ty pos) (v : whn Ξ `+A)
: p_dom (p_of_w_0p A v) =[val]> Ξ by struct A :=
p_dom_of_w_0p (0) (Var i) := elim_var_p i ;
p_dom_of_w_0p (1) (Var i) := elim_var_p i ;
p_dom_of_w_0p (A β B) (Var i) := elim_var_p i ;
p_dom_of_w_0p (A β B) (Var i) := elim_var_p i ;
p_dom_of_w_0p (β A) (Var i) := elim_var_p i ;
p_dom_of_w_0p (β A) (Var i) := elim_var_p i ;
p_dom_of_w_0p (1) (OneR) := a_empty ;
p_dom_of_w_0p (A β B) (TenR v1 v2) := [ p_dom_of_w_0p A v1 , p_dom_of_w_0p B v2 ] ;
p_dom_of_w_0p (A β B) (OrR1 v) := p_dom_of_w_0p A v ;
p_dom_of_w_0p (A β B) (OrR2 v) := p_dom_of_w_0p B v ;
p_dom_of_w_0p (β A) (ShiftPR x) := a_append a_empty x ;
p_dom_of_w_0p (β A) (NegPR k) := p_dom_of_w_0n A k ;
with p_dom_of_w_0n {Ξ : neg_ctx} (A : pre_ty neg) (k : whn Ξ `-A)
: p_dom (p_of_w_0n A k) =[val]> Ξ by struct A :=
p_dom_of_w_0n (β€) (Var i) := elim_var_n i ;
p_dom_of_w_0n (β₯) (Var i) := elim_var_n i ;
p_dom_of_w_0n (A β
B) (Var i) := elim_var_n i ;
p_dom_of_w_0n (A & B) (Var i) := elim_var_n i ;
p_dom_of_w_0n (β A) (Var i) := elim_var_n i ;
p_dom_of_w_0n (Β¬ A) (Var i) := elim_var_n i ;
p_dom_of_w_0n (β₯) (BotL) := a_empty ;
p_dom_of_w_0n (A β
B) (ParL k1 k2) := [ p_dom_of_w_0n A k1 , p_dom_of_w_0n B k2 ] ;
p_dom_of_w_0n (A & B) (AndL1 k) := p_dom_of_w_0n A k ;
p_dom_of_w_0n (A & B) (AndL2 k) := p_dom_of_w_0n B k ;
p_dom_of_w_0n (β A) (ShiftNL x) := a_append a_empty x ;
p_dom_of_w_0n (Β¬ A) (NegNL v) := p_dom_of_w_0p A v .
We can now package up all these auxiliary functions into the following ones, abstracting polarity and side-annotation.
Equations p_of_v {Ξ : neg_ctx} A : val Ξ A -> pat A := p_of_v (@LTy pos A) v := p_of_w_0p A v ; p_of_v (@RTy pos A) _ := PVarN A ; p_of_v (@LTy neg A) _ := PVarP A ; p_of_v (@RTy neg A) k := p_of_w_0n A k . Equations p_dom_of_v {Ξ : neg_ctx} A (v : val Ξ A) : p_dom (p_of_v A v) =[val]> Ξ := p_dom_of_v (@LTy pos A) v := p_dom_of_w_0p A v ; p_dom_of_v (@RTy pos A) x := [ ! ,β x ] ; p_dom_of_v (@LTy neg A) x := [ ! ,β x ] ; p_dom_of_v (@RTy neg A) k := p_dom_of_w_0n A k . Definition v_split_p {Ξ : neg_ctx} {A} (v : whn Ξ `+A) : (obs_op # val) Ξ `-A := (p_of_w_0p A v : o_op obs_op `-A) β¦ p_dom_of_w_0p A v β¦. Definition v_split_n {Ξ : neg_ctx} {A} (v : whn Ξ `-A) : (obs_op # val) Ξ `+A := (p_of_w_0n A v : o_op obs_op `+_) β¦ p_dom_of_w_0n A v β¦.
With patterns and observations now in hand we prepare for the definition of evaluation and define a shorthand for normal forms. 'Normal forms' are here understood---as in the paper---in our slightly non-standard presentation of triplets of a variable, an observation and an assignment.
Definition nf : Famβ ty neg_ctx := c_var β₯β (obs_op # val).
Now the bulk of evaluation: the step function. Once again we are greatful for
Equations
providing us with a justification for the fact that this complex
dependent pattern-matching is indeed total.
Equations eval_aux {Ξ : neg_ctx} : state Ξ -> (state Ξ + nf Ξ) :=
eval_aux (Cut pos (Mu c) (x)) := inl (c ββ β[ x ]) ;
eval_aux (Cut neg (x) (Mu c)) := inl (c ββ β[ x ]) ;
eval_aux (Cut pos (Whn v) (Mu c)) := inl (c ββ β[ v ]) ;
eval_aux (Cut neg (Mu c) (Whn k)) := inl (c ββ β[ k ]) ;
eval_aux (Cut pos (Whn v) (RecL k)) := inl (Cut pos (Whn v) (k `ββ β[ RecL k ])) ;
eval_aux (Cut neg (RecR t) (Whn k)) := inl (Cut neg (t `ββ β[ RecR t ]) (Whn k)) ;
eval_aux (Cut pos (Whn v) (Whn (Var i))) := inr (s_var_upg i β
v_split_p v) ;
eval_aux (Cut neg (Whn (Var i)) (Whn k)) := inr (s_var_upg i β
v_split_n k) ;
eval_aux (Cut pos (Whn (Var i)) (Whn _)) := elim_var_p i ;
eval_aux (Cut neg (Whn _) (Whn (Var i))) := elim_var_n i ;
eval_aux (Cut pos (Whn (OneR)) (Whn (OneL c))) := inl c ;
eval_aux (Cut neg (Whn (BotR c)) (Whn (BotL))) := inl c ;
eval_aux (Cut pos (Whn (TenR v1 v2)) (Whn (TenL c))) := inl (c ββ β[ v1 , v2 ]) ;
eval_aux (Cut neg (Whn (ParR c)) (Whn (ParL k1 k2))) := inl (c ββ β[ k1 , k2 ]) ;
eval_aux (Cut pos (Whn (OrR1 v)) (Whn (OrL c1 c2))) := inl (c1 ββ β[ v ]) ;
eval_aux (Cut pos (Whn (OrR2 v)) (Whn (OrL c1 c2))) := inl (c2 ββ β[ v ]) ;
eval_aux (Cut neg (Whn (AndR c1 c2)) (Whn (AndL1 k))) := inl (c1 ββ β[ k ]) ;
eval_aux (Cut neg (Whn (AndR c1 c2)) (Whn (AndL2 k))) := inl (c2 ββ β[ k ]) ;
eval_aux (Cut pos (Whn (ShiftPR x)) (Whn (ShiftPL c))) := inl (c ββ β[ x ]) ;
eval_aux (Cut neg (Whn (ShiftNR c)) (Whn (ShiftNL x))) := inl (c ββ β[ x ]) ;
eval_aux (Cut pos (Whn (NegPR k)) (Whn (NegPL c))) := inl (c ββ β[ k ]) ;
eval_aux (Cut neg (Whn (NegNR c)) (Whn (NegNL v))) := inl (c ββ β[ v ]) .
Finally we define evaluation as the iteration of the step function in the Delay monad, and also define application of an observation with arguments to a value.
Definition eval {Ξ : neg_ctx} : state Ξ -> delay (nf Ξ) := iter_delay (fun c => Ret' (eval_aux c)). Definition p_app {Ξ A} (v : val Ξ A) (m : pat Aβ ) (e : p_dom m =[val]> Ξ) : state Ξ := Cut' v (m `α΅₯β e) .
Now comes a rather ugly part: the metatheory of our syntax. Comments will be rather more
sparse. For a thorough explaination of its structure, see Examples/Lambda/CBLTyped.v
.
We will here be concerned with extensional equality preservation, identity and composition
laws for renaming and substitution, and also refolding lemmas for splitting and embedding
patterns. You are encouraged to just skip until line ~1300.
Scheme term_mut := Induction for term Sort Prop with whn_mut := Induction for whn Sort Prop with state_mut := Induction for state Sort Prop. Record syn_ind_args (P_t : forall Ξ A, term Ξ A -> Prop) (P_w : forall Ξ A, whn Ξ A -> Prop) (P_s : forall Ξ, state Ξ -> Prop) := { ind_mu : forall Ξ A s (H : P_s _ s), P_t Ξ A (Mu s) ; ind_recp : forall Ξ A t (H : P_t _ _ t), P_t Ξ `-A (RecL t) ; ind_recn : forall Ξ A t (H : P_t _ _ t), P_t Ξ `+A (RecR t) ; ind_whn : forall Ξ A w (H : P_w _ _ w), P_t Ξ A (Whn w) ; ind_var : forall Ξ A h, P_w Ξ A (Var h) ; ind_zerl : forall Ξ, P_w Ξ `-0 ZerL ; ind_topr : forall Ξ, P_w Ξ `+β€ TopR ; ind_oner : forall Ξ, P_w Ξ `+1 OneR ; ind_onel : forall Ξ s, P_s Ξ s -> P_w Ξ `-1 (OneL s) ; ind_botr : forall Ξ s, P_s Ξ s -> P_w Ξ `+β₯ (BotR s) ; ind_botl : forall Ξ, P_w Ξ `-β₯ BotL ; ind_tenr : forall Ξ A B w1 (H1 : P_w _ _ w1) w2 (H2 : P_w _ _ w2), P_w Ξ `+(A β B) (TenR w1 w2) ; ind_tenl : forall Ξ A B s (H : P_s _ s), P_w Ξ `-(A β B) (TenL s) ; ind_parr : forall Ξ A B s (H : P_s _ s), P_w Ξ `+(A β B) (ParR s) ; ind_parl : forall Ξ A B w1 (H1 : P_w _ _ w1) w2 (H2 : P_w Ξ `-B w2), P_w Ξ `-(A β B) (ParL w1 w2) ; ind_orr1 : forall Ξ A B w (H : P_w _ _ w), P_w Ξ `+(A β B) (OrR1 w) ; ind_orr2 : forall Ξ A B w (H : P_w _ _ w), P_w Ξ `+(A β B) (OrR2 w) ; ind_orl : forall Ξ A B s1 (H1 : P_s _ s1) s2 (H2 : P_s _ s2), P_w Ξ `-(A β B) (OrL s1 s2) ; ind_andr : forall Ξ A B s1 (H1 : P_s _ s1) s2 (H2 : P_s _ s2), P_w Ξ `+(A & B) (AndR s1 s2) ; ind_andl1 : forall Ξ A B w (H : P_w _ _ w), P_w Ξ `-(A & B) (AndL1 w) ; ind_andl2 : forall Ξ A B w (H : P_w _ _ w), P_w Ξ `-(A & B) (AndL2 w) ; ind_shiftpr : forall Ξ A t (H : P_t _ _ t), P_w Ξ `+(β A) (ShiftPR t) ; ind_shiftpl : forall Ξ A s (H : P_s _ s), P_w Ξ `-(β A) (ShiftPL s) ; ind_shiftnr : forall Ξ A s (H : P_s _ s), P_w Ξ `+(β A) (ShiftNR s) ; ind_shiftnl : forall Ξ A t (H : P_t _ _ t), P_w Ξ `-(β A) (ShiftNL t) ; ind_negpr : forall Ξ A w (H : P_w _ _ w), P_w Ξ `+(β A) (NegPR w) ; ind_negpl : forall Ξ A s (H : P_s _ s), P_w Ξ `-(β A) (NegPL s) ; ind_negnr : forall Ξ A s (H : P_s _ s), P_w Ξ `+(Β¬ A) (NegNR s) ; ind_negnl : forall Ξ A w (H : P_w _ _ w), P_w Ξ `-(Β¬ A) (NegNL w) ; ind_cut : forall Ξ p A t1 (H1 : P_t _ _ t1) t2 (H2 : P_t _ _ t2), P_s Ξ (@Cut _ p A t1 t2) } . Lemma term_ind_mut P_t P_w P_s (H : syn_ind_args P_t P_w P_s) Ξ A t : P_t Ξ A t . destruct H; now apply (term_mut P_t P_w P_s). Qed. Lemma whn_ind_mut P_t P_w P_s (H : syn_ind_args P_t P_w P_s) Ξ A w : P_w Ξ A w . destruct H; now apply (whn_mut P_t P_w P_s). Qed. Lemma state_ind_mut P_t P_w P_s (H : syn_ind_args P_t P_w P_s) Ξ s : P_s Ξ s . destruct H; now apply (state_mut P_t P_w P_s). Qed. Definition t_ren_proper_P Ξ A (t : term Ξ A) : Prop := forall Ξ (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> t ββα΅£ f1 = t ββα΅£ f2 . Definition w_ren_proper_P Ξ A (v : whn Ξ A) : Prop := forall Ξ (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> v `α΅₯βα΅£ f1 = v `α΅₯βα΅£ f2 . Definition s_ren_proper_P Ξ (s : state Ξ) : Prop := forall Ξ (f1 f2 : Ξ β Ξ), f1 β‘β f2 -> s ββα΅£ f1 = s ββα΅£ f2 . Lemma ren_proper_prf : syn_ind_args t_ren_proper_P w_ren_proper_P s_ren_proper_P. econstructor. all: unfold t_ren_proper_P, w_ren_proper_P, s_ren_proper_P. all: intros; cbn; f_equal; eauto. all: first [ apply H | apply H1 | apply H2 ]; auto. all: first [ apply r_shift1_eq | apply r_shift2_eq ]; auto. Qed. #[global] Instance t_ren_eq {Ξ a t Ξ} : Proper (asgn_eq _ _ ==> eq) (t_rename Ξ a t Ξ). intros f1 f2 H1; now apply (term_ind_mut _ _ _ ren_proper_prf). Qed. #[global] Instance w_ren_eq {Ξ a v Ξ} : Proper (asgn_eq _ _ ==> eq) (w_rename Ξ a v Ξ). intros f1 f2 H1; now apply (whn_ind_mut _ _ _ ren_proper_prf). Qed. #[global] Instance s_ren_eq {Ξ s Ξ} : Proper (asgn_eq _ _ ==> eq) (s_rename Ξ s Ξ). intros f1 f2 H1; now apply (state_ind_mut _ _ _ ren_proper_prf). Qed. #[global] Instance v_ren_eq {Ξ a v Ξ} : Proper (asgn_eq _ _ ==> eq) (v_rename Ξ a v Ξ). destruct a as [ [] | [] ]. now apply w_ren_eq. now apply t_ren_eq. now apply t_ren_eq. now apply w_ren_eq. Qed. #[global] Instance a_ren_eq {Ξ1 Ξ2 Ξ3} : Proper (asgn_eq _ _ ==> asgn_eq _ _ ==> asgn_eq _ _) (@a_ren Ξ1 Ξ2 Ξ3). intros r1 r2 H1 a1 a2 H2 ? i; cbn; now rewrite H1, (v_ren_eq _ _ H2). Qed. #[global] Instance a_shift1_eq {Ξ Ξ A} : Proper (asgn_eq _ _ ==> asgn_eq _ _) (@a_shift1 Ξ Ξ A). intros ? ? H ? h. dependent elimination h; auto; cbn; now rewrite H. Qed. #[global] Instance a_shift2_eq {Ξ Ξ A B} : Proper (asgn_eq _ _ ==> asgn_eq _ _) (@a_shift2 Ξ Ξ A B). intros ? ? H ? v. do 2 (dependent elimination v; auto). cbn; now rewrite H. Qed. 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 w_ren_ren_P Ξ1 A (v : whn Ξ1 A) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 β Ξ2) (f2 : Ξ2 β Ξ3), (v `α΅₯βα΅£ f1) `α΅₯βα΅£ f2 = v `α΅₯βα΅£ (f1 α΅£β f2) . Definition s_ren_ren_P Ξ1 (s : state Ξ1) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 β Ξ2) (f2 : Ξ2 β Ξ3), (s ββα΅£ f1) ββα΅£ f2 = s ββα΅£ (f1 α΅£β f2) . Lemma ren_ren_prf : syn_ind_args t_ren_ren_P w_ren_ren_P s_ren_ren_P. econstructor. all: unfold t_ren_ren_P, w_ren_ren_P, s_ren_ren_P. all: intros; cbn; f_equal; eauto. all: first [ rewrite r_shift1_comp | rewrite r_shift2_comp ]; eauto. Qed. Lemma t_ren_ren {Ξ1 Ξ2 Ξ3} (f1 : Ξ1 β Ξ2) (f2 : Ξ2 β Ξ3) A (t : term Ξ1 A) : (t ββα΅£ f1) ββα΅£ f2 = t ββα΅£ (f1 α΅£β f2) . now apply (term_ind_mut _ _ _ ren_ren_prf). Qed. Lemma w_ren_ren {Ξ1 Ξ2 Ξ3} (f1 : Ξ1 β Ξ2) (f2 : Ξ2 β Ξ3) A (v : whn Ξ1 A) : (v `α΅₯βα΅£ f1) `α΅₯βα΅£ f2 = v `α΅₯βα΅£ (f1 α΅£β f2) . now apply (whn_ind_mut _ _ _ ren_ren_prf). Qed. Lemma s_ren_ren {Ξ1 Ξ2 Ξ3} (f1 : Ξ1 β Ξ2) (f2 : Ξ2 β Ξ3) (s : state Ξ1) : (s ββα΅£ f1) ββα΅£ f2 = s ββα΅£ (f1 α΅£β f2) . now apply (state_ind_mut _ _ _ ren_ren_prf). Qed. Lemma v_ren_ren {Ξ1 Ξ2 Ξ3} (f1 : Ξ1 β Ξ2) (f2 : Ξ2 β Ξ3) A (v : val Ξ1 A) : (v α΅₯βα΅£ f1) α΅₯βα΅£ f2 = v α΅₯βα΅£ (f1 α΅£β f2) . destruct A as [ [] | [] ]. now apply w_ren_ren. now apply t_ren_ren. now apply t_ren_ren. now apply w_ren_ren. Qed. Definition t_ren_id_l_P Ξ A (t : term Ξ A) : Prop := t ββα΅£ r_id = t. Definition w_ren_id_l_P Ξ A (v : whn Ξ A) : Prop := v `α΅₯βα΅£ r_id = v. Definition s_ren_id_l_P Ξ (s : state Ξ) : Prop := s ββα΅£ r_id = s. Lemma ren_id_l_prf : syn_ind_args t_ren_id_l_P w_ren_id_l_P s_ren_id_l_P. econstructor. all: unfold t_ren_id_l_P, w_ren_id_l_P, s_ren_id_l_P. all: intros; cbn; f_equal; eauto. all: first [ rewrite r_shift1_id | rewrite r_shift2_id ]; eauto. Qed. Lemma t_ren_id_l {Ξ} A (t : term Ξ A) : t ββα΅£ r_id = t. now apply (term_ind_mut _ _ _ ren_id_l_prf). Qed. Lemma w_ren_id_l {Ξ} A (v : whn Ξ A) : v `α΅₯βα΅£ r_id = v. now apply (whn_ind_mut _ _ _ ren_id_l_prf). Qed. Lemma s_ren_id_l {Ξ} (s : state Ξ) : s ββα΅£ r_id = s. now apply (state_ind_mut _ _ _ ren_id_l_prf). Qed. Lemma v_ren_id_l {Ξ} A (v : val Ξ A) : v α΅₯βα΅£ r_id = v. destruct A as [ [] | [] ]. now apply w_ren_id_l. now apply t_ren_id_l. now apply t_ren_id_l. now apply w_ren_id_l. Qed. Lemma v_ren_id_r {Ξ Ξ} (f : Ξ β Ξ) A (i : Ξ β A) : (var i) α΅₯βα΅£ f = var (f _ i). now destruct A as [ [] | [] ]. Qed. Lemma a_shift1_id {Ξ A} : @a_shift1 Ξ Ξ A var β‘β var. intros [ [] | [] ] i; dependent elimination i; auto. Qed. Lemma a_shift2_id {Ξ A B} : @a_shift2 Ξ Ξ A B var β‘β var. intros ? v; cbn. do 2 (dependent elimination v; cbn; auto). now destruct a as [[]|[]]. Qed. Arguments var : simpl never. Lemma a_shift1_ren_r {Ξ1 Ξ2 Ξ3 y} (f1 : Ξ1 =[ val ]> Ξ2) (f2 : Ξ2 β Ξ3) : a_shift1 (y:=y) (f1 βα΅£ f2) β‘β a_shift1 f1 βα΅£ r_shift1 f2 . intros ? h; dependent elimination h; cbn. - now rewrite v_ren_id_r. - now unfold v_shift1; rewrite 2 v_ren_ren. Qed. Lemma a_shift2_ren_r {Ξ1 Ξ2 Ξ3 y z} (f1 : Ξ1 =[ val ]> Ξ2) (f2 : Ξ2 β Ξ3) : a_shift2 (y:=y) (z:=z) (f1 βα΅£ f2) β‘β a_shift2 f1 βα΅£ r_shift2 f2 . intros ? v; do 2 (dependent elimination v; cbn; [ now rewrite v_ren_id_r | ]). unfold v_shift2; now rewrite 2 v_ren_ren. Qed. Lemma a_shift1_ren_l {Ξ1 Ξ2 Ξ3 y} (f1 : Ξ1 β Ξ2) (f2 : Ξ2 =[val]> Ξ3) : a_shift1 (y:=y) (f1 α΅£β f2) β‘β r_shift1 f1 α΅£β a_shift1 f2 . intros ? i; dependent elimination i; auto. Qed. Lemma a_shift2_ren_l {Ξ1 Ξ2 Ξ3 y z} (f1 : Ξ1 β Ξ2) (f2 : Ξ2 =[val]> Ξ3) : a_shift2 (y:=y) (z:=z) (f1 α΅£β f2) β‘β r_shift2 f1 α΅£β a_shift2 f2 . intros ? v; do 2 (dependent elimination v; auto). Qed. Definition t_sub_proper_P Ξ A (t : term Ξ A) : Prop := forall Ξ (f1 f2 : Ξ =[val]> Ξ), f1 β‘β f2 -> t `ββ f1 = t `ββ f2 . Definition w_sub_proper_P Ξ A (v : whn Ξ A) : Prop := forall Ξ (f1 f2 : Ξ =[val]> Ξ), f1 β‘β f2 -> v `α΅₯β f1 = v `α΅₯β f2 . Definition s_sub_proper_P Ξ (s : state Ξ) : Prop := forall Ξ (f1 f2 : Ξ =[val]> Ξ), f1 β‘β f2 -> s ββ f1 = s ββ f2 . Lemma sub_proper_prf : syn_ind_args t_sub_proper_P w_sub_proper_P s_sub_proper_P. econstructor. all: unfold t_sub_proper_P, w_sub_proper_P, s_sub_proper_P. all: intros; cbn. all: match goal with | |- Whn _ = Whn _ => do 2 f_equal | _ => f_equal end . all: first [ apply H | apply H1 | apply H2 ]; auto. all: first [ apply a_shift1_eq | apply a_shift2_eq ]; auto. Qed. #[global] Instance t_sub_eq {Ξ a t Ξ} : Proper (asgn_eq _ _ ==> eq) (t_subst Ξ a t Ξ). intros f1 f2 H1; now apply (term_ind_mut _ _ _ sub_proper_prf). Qed. #[global] Instance w_sub_eq {Ξ a v Ξ} : Proper (asgn_eq _ _ ==> eq) (w_subst Ξ a v Ξ). intros f1 f2 H1; now apply (whn_ind_mut _ _ _ sub_proper_prf). Qed. #[global] Instance s_sub_eq {Ξ s Ξ} : Proper (asgn_eq _ _ ==> eq) (s_subst Ξ s Ξ). intros f1 f2 H1; now apply (state_ind_mut _ _ _ sub_proper_prf). Qed. #[global] Instance v_sub_eq {Ξ a v Ξ} : Proper (asgn_eq _ _ ==> eq) (v_subst Ξ a v Ξ). destruct a as [[]|[]]. - now apply w_sub_eq. - now apply t_sub_eq. - now apply t_sub_eq. - now apply w_sub_eq. Qed. #[global] Instance a_comp_eq {Ξ1 Ξ2 Ξ3} : Proper (asgn_eq _ _ ==> asgn_eq _ _ ==> asgn_eq _ _) (@a_comp _ _ _ _ _ Ξ1 Ξ2 Ξ3). intros ? ? H1 ? ? H2 ? ?; cbn; rewrite H1; now eapply v_sub_eq. Qed. Definition t_ren_sub_P Ξ1 A (t : term Ξ1 A) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 =[val]> Ξ2) (f2 : Ξ2 β Ξ3), (t `ββ f1) ββα΅£ f2 = t `ββ (f1 βα΅£ f2) . Definition w_ren_sub_P Ξ1 A (v : whn Ξ1 A) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 =[val]> Ξ2) (f2 : Ξ2 β Ξ3), (v `α΅₯β f1) α΅₯βα΅£ f2 = v `α΅₯β (f1 βα΅£ f2) . Definition s_ren_sub_P Ξ1 (s : state Ξ1) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 =[val]> Ξ2) (f2 : Ξ2 β Ξ3), (s ββ f1) ββα΅£ f2 = s ββ (f1 βα΅£ f2) . Lemma ren_sub_prf : syn_ind_args t_ren_sub_P w_ren_sub_P s_ren_sub_P. econstructor. all: unfold t_ren_sub_P, w_ren_sub_P, s_ren_sub_P. all: intros; cbn. 4: destruct A as [ [] | [] ]; cbn. all: match goal with | |- Whn _ = Whn _ => do 2 f_equal | _ => f_equal end ; eauto. all: first [ rewrite a_shift1_ren_r | rewrite a_shift2_ren_r ]; auto. Qed. Lemma t_ren_sub {Ξ1 Ξ2 Ξ3} (f1 : Ξ1 =[val]> Ξ2) (f2 : Ξ2 β Ξ3) A (t : term Ξ1 A) : (t `ββ f1) ββα΅£ f2 = t `ββ (f1 βα΅£ f2) . now apply (term_ind_mut _ _ _ ren_sub_prf). Qed. Lemma w_ren_sub {Ξ1 Ξ2 Ξ3} (f1 : Ξ1 =[val]> Ξ2) (f2 : Ξ2 β Ξ3) A (v : whn Ξ1 A) : (v `α΅₯β f1) α΅₯βα΅£ f2 = v `α΅₯β (f1 βα΅£ f2) . now apply (whn_ind_mut _ _ _ ren_sub_prf). Qed. Lemma s_ren_sub {Ξ1 Ξ2 Ξ3} (f1 : Ξ1 =[val]> Ξ2) (f2 : Ξ2 β Ξ3) (s : state Ξ1) : (s ββ f1) ββα΅£ f2 = s ββ (f1 βα΅£ f2) . now apply (state_ind_mut _ _ _ ren_sub_prf). Qed. Lemma v_ren_sub {Ξ1 Ξ2 Ξ3} (f1 : Ξ1 =[val]> Ξ2) (f2 : Ξ2 β Ξ3) A (v : val Ξ1 A) : (v α΅₯β f1) α΅₯βα΅£ f2 = v α΅₯β (f1 βα΅£ f2) . destruct A as [ [] | [] ]; cbn [ v_subst ]. - now apply w_ren_sub. - now apply t_ren_sub. - now apply t_ren_sub. - now apply w_ren_sub. Qed. Definition t_sub_ren_P Ξ1 A (t : term Ξ1 A) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 β Ξ2) (f2 : Ξ2 =[val]> Ξ3), (t ββα΅£ f1) `ββ f2 = t `ββ (f1 α΅£β f2). Definition w_sub_ren_P Ξ1 A (v : whn Ξ1 A) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 β Ξ2) (f2 : Ξ2 =[val]> Ξ3), (v `α΅₯βα΅£ f1) `α΅₯β f2 = v `α΅₯β (f1 α΅£β f2). Definition s_sub_ren_P Ξ1 (s : state Ξ1) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 β Ξ2) (f2 : Ξ2 =[val]> Ξ3), (s ββα΅£ f1) ββ f2 = s ββ (f1 α΅£β f2). Lemma sub_ren_prf : syn_ind_args t_sub_ren_P w_sub_ren_P s_sub_ren_P. econstructor. all: unfold t_sub_ren_P, w_sub_ren_P, s_sub_ren_P. all: intros; cbn. all: match goal with | |- Whn _ = Whn _ => do 2 f_equal | _ => f_equal end ; eauto. all: first [ rewrite a_shift1_ren_l | rewrite a_shift2_ren_l ]; auto. Qed. Lemma t_sub_ren {Ξ1 Ξ2 Ξ3} (f1 : Ξ1 β Ξ2) (f2 : Ξ2 =[val]> Ξ3) A (t : term Ξ1 A) : (t ββα΅£ f1) `ββ f2 = t `ββ (f1 α΅£β f2). now apply (term_ind_mut _ _ _ sub_ren_prf). Qed. Lemma w_sub_ren {Ξ1 Ξ2 Ξ3} (f1 : Ξ1 β Ξ2) (f2 : Ξ2 =[val]> Ξ3) A (v : whn Ξ1 A) : (v `α΅₯βα΅£ f1) `α΅₯β f2 = v `α΅₯β (f1 α΅£β f2). now apply (whn_ind_mut _ _ _ sub_ren_prf). Qed. Lemma s_sub_ren {Ξ1 Ξ2 Ξ3} (f1 : Ξ1 β Ξ2) (f2 : Ξ2 =[val]> Ξ3) (s : state Ξ1) : (s ββα΅£ f1) ββ f2 = s ββ (f1 α΅£β f2). now apply (state_ind_mut _ _ _ sub_ren_prf). Qed. Lemma v_sub_ren {Ξ1 Ξ2 Ξ3} (f1 : Ξ1 β Ξ2) (f2 : Ξ2 =[val]> Ξ3) A (v : val Ξ1 A) : (v α΅₯βα΅£ f1) α΅₯β f2 = v α΅₯β (f1 α΅£β f2). destruct A as [ [] | [] ]. - now apply w_sub_ren. - now apply t_sub_ren. - now apply t_sub_ren. - now apply w_sub_ren. Qed. Lemma v_sub_id_r {Ξ Ξ} (f : Ξ =[val]> Ξ) A (i : Ξ β A) : var i α΅₯β f = f A i. destruct A as [ [] | [] ]; auto. Qed. Lemma a_shift1_comp {Ξ1 Ξ2 Ξ3 A} (f1 : Ξ1 =[val]> Ξ2) (f2 : Ξ2 =[val]> Ξ3) : @a_shift1 _ _ A (f1 β f2) β‘β a_shift1 f1 β a_shift1 f2 . intros x i; dependent elimination i; cbn. - now rewrite v_sub_id_r. - now unfold v_shift1; rewrite v_ren_sub, v_sub_ren. Qed. Lemma a_shift2_comp {Ξ1 Ξ2 Ξ3 A B} (f1 : Ξ1 =[val]> Ξ2) (f2 : Ξ2 =[val]> Ξ3) : @a_shift2 _ _ A B (f1 β f2) β‘β a_shift2 f1 β a_shift2 f2 . intros ? v; do 2 (dependent elimination v; cbn; [ now rewrite v_sub_id_r | ]). now unfold v_shift2; rewrite v_ren_sub, v_sub_ren. Qed. Definition t_sub_sub_P Ξ1 A (t : term Ξ1 A) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 =[val]> Ξ2) (f2 : Ξ2 =[val]> Ξ3), (t `ββ f1) `ββ f2 = t `ββ (f1 β f2) . Definition w_sub_sub_P Ξ1 A (v : whn Ξ1 A) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 =[val]> Ξ2) (f2 : Ξ2 =[val]> Ξ3), (v `α΅₯β f1) α΅₯β f2 = v `α΅₯β (f1 β f2) . Definition s_sub_sub_P Ξ1 (s : state Ξ1) : Prop := forall Ξ2 Ξ3 (f1 : Ξ1 =[val]> Ξ2) (f2 : Ξ2 =[val]> Ξ3), (s ββ f1) ββ f2 = s ββ (f1 β f2) . Lemma sub_sub_prf : syn_ind_args t_sub_sub_P w_sub_sub_P s_sub_sub_P. econstructor. all: unfold t_sub_sub_P, w_sub_sub_P, s_sub_sub_P; intros; cbn. 4: destruct A as [ [] | [] ]; cbn. all: match goal with | |- Whn _ = Whn _ => do 2 f_equal | _ => f_equal end ; eauto. all: first [ rewrite a_shift1_comp | rewrite a_shift2_comp ]; auto. Qed. Lemma t_sub_sub {Ξ1 Ξ2 Ξ3} (f1 : Ξ1 =[val]> Ξ2) (f2 : Ξ2 =[val]> Ξ3) A (t : term Ξ1 A) : (t `ββ f1) `ββ f2 = t `ββ (f1 β f2) . now apply (term_ind_mut _ _ _ sub_sub_prf). Qed. Lemma w_sub_sub {Ξ1 Ξ2 Ξ3} (f1 : Ξ1 =[val]> Ξ2) (f2 : Ξ2 =[val]> Ξ3) A (v : whn Ξ1 A) : (v `α΅₯β f1) α΅₯β f2 = v `α΅₯β (f1 β f2) . now apply (whn_ind_mut _ _ _ sub_sub_prf). Qed. Lemma s_sub_sub {Ξ1 Ξ2 Ξ3} (f1 : Ξ1 =[val]> Ξ2) (f2 : Ξ2 =[val]> Ξ3) (s : state Ξ1) : (s ββ f1) ββ f2 = s ββ (f1 β f2) . now apply (state_ind_mut _ _ _ sub_sub_prf). Qed. Lemma v_sub_sub {Ξ1 Ξ2 Ξ3} (f1 : Ξ1 =[val]> Ξ2) (f2 : Ξ2 =[val]> Ξ3) A (v : val Ξ1 A) : (v α΅₯β f1) α΅₯β f2 = v α΅₯β (f1 β f2) . destruct A as [ [] | [] ]. - now apply w_sub_sub. - now apply t_sub_sub. - now apply t_sub_sub. - now apply w_sub_sub. Qed. Lemma a_comp_assoc {Ξ1 Ξ2 Ξ3 Ξ4} (u : Ξ1 =[val]> Ξ2) (v : Ξ2 =[val]> Ξ3) (w : Ξ3 =[val]> Ξ4) : (u β v) β w β‘β u β (v β w). intros ? i; unfold a_comp; now apply v_sub_sub. Qed. Definition t_sub_id_l_P Ξ A (t : term Ξ A) : Prop := t `ββ var = t. Definition w_sub_id_l_P Ξ A (v : whn Ξ A) : Prop := v `α΅₯β var = v. Definition s_sub_id_l_P Ξ (s : state Ξ) : Prop := s ββ var = s. Lemma sub_id_l_prf : syn_ind_args t_sub_id_l_P w_sub_id_l_P s_sub_id_l_P. econstructor. all: unfold t_sub_id_l_P, w_sub_id_l_P, s_sub_id_l_P; intros; cbn. 4,5: destruct A as [ [] | [] ]; cbn. all: match goal with | |- Whn _ = Whn _ => do 2 f_equal | _ => f_equal end; eauto. all: first [ rewrite a_shift1_id | rewrite a_shift2_id ]; auto. Qed. Lemma t_sub_id_l {Ξ} A (t : term Ξ A) : t `ββ var = t. now apply (term_ind_mut _ _ _ sub_id_l_prf). Qed. Lemma w_sub_id_l {Ξ} A (v : whn Ξ A) : v `α΅₯β var = v. now apply (whn_ind_mut _ _ _ sub_id_l_prf). Qed. Lemma s_sub_id_l {Ξ} (s : state Ξ) : s ββ var = s. now apply (state_ind_mut _ _ _ sub_id_l_prf). Qed. Lemma v_sub_id_l {Ξ} A (v : val Ξ A) : v α΅₯β var = v. destruct A as [ [] | [] ]. - now apply w_sub_id_l. - now apply t_sub_id_l. - now apply t_sub_id_l. - now apply w_sub_id_l. Qed. Lemma sub1_sub {Ξ Ξ A} (f : Ξ =[val]> Ξ) (v : val Ξ A) : a_shift1 f β asgn1 (v α΅₯β f) β‘β asgn1 v β f. intros ? h; dependent elimination h; cbn. - now rewrite v_sub_id_r. - unfold v_shift1; rewrite v_sub_ren, v_sub_id_r. now apply v_sub_id_l. Qed. Lemma sub1_ren {Ξ Ξ A} (f : Ξ β Ξ) (v : val Ξ A) : r_shift1 f α΅£β asgn1 (v α΅₯βα΅£ f) β‘β asgn1 v βα΅£ f. intros ? h; dependent elimination h; auto. cbn; now rewrite v_ren_id_r. Qed. Lemma v_sub1_sub {Ξ Ξ A B} (f : Ξ =[val]> Ξ) (v : val Ξ A) (w : val (Ξ βΆβ A) B) : (w α΅₯β a_shift1 f) α΅₯β β[ v α΅₯β f ] = (w α΅₯β β[ v ]) α΅₯β f . cbn; rewrite 2 v_sub_sub. apply v_sub_eq; now rewrite sub1_sub. Qed. Lemma v_sub1_ren {Ξ Ξ A B} (f : Ξ β Ξ) (v : val Ξ A) (w : val (Ξ βΆβ A) B) : (w α΅₯βα΅£ r_shift1 f) α΅₯β β[ v α΅₯βα΅£ f ] = (w α΅₯β β[ v ]) α΅₯βα΅£ f . cbn; rewrite v_sub_ren, v_ren_sub. apply v_sub_eq; now rewrite sub1_ren. Qed. Lemma s_sub1_sub {Ξ Ξ A} (f : Ξ =[val]> Ξ) (v : val Ξ A) (s : state (Ξ βΆβ A)) : (s ββ a_shift1 f) ββ β[ v α΅₯β f ] = (s ββ β[ v ]) ββ f . cbn; now rewrite 2 s_sub_sub, sub1_sub. Qed. Lemma s_sub2_sub {Ξ Ξ A B} (f : Ξ =[val]> Ξ) (s : state (Ξ βΆβ A βΆβ B)) u v : (s ββ a_shift2 f) ββ β[ u α΅₯β f , v α΅₯β f ] = (s ββ β[ u, v ]) ββ f . cbn; rewrite 2 s_sub_sub; apply s_sub_eq. intros ? v0; cbn. do 2 (dependent elimination v0; cbn; [ now rewrite v_sub_id_r | ]). unfold v_shift2; rewrite v_sub_ren, v_sub_id_r, <- v_sub_id_l. now apply v_sub_eq. Qed. Lemma s_sub1_ren {Ξ Ξ A} (f : Ξ β Ξ) (v : val Ξ A) (s : state (Ξ βΆβ A)) : (s ββα΅£ r_shift1 f) ββ β[ v α΅₯βα΅£ f ] = (s ββ β[ v ]) ββα΅£ f . cbn; now rewrite s_sub_ren, s_ren_sub, sub1_ren. Qed. Lemma t_sub1_sub {Ξ Ξ A B} (f : Ξ =[val]> Ξ) (v : val Ξ A) (t : term (Ξ βΆβ A) B) : (t `ββ a_shift1 f) `ββ β[ v α΅₯β f ] = (t `ββ β[ v ]) `ββ f . cbn; rewrite 2 t_sub_sub. apply t_sub_eq; now rewrite sub1_sub. Qed. Lemma t_sub1_ren {Ξ Ξ A B} (f : Ξ β Ξ) (v : val Ξ A) (t : term (Ξ βΆβ A) B) : (t ββα΅£ r_shift1 f) `ββ β[ v α΅₯βα΅£ f ] = (t `ββ β[ v ]) ββα΅£ f . cbn; rewrite t_sub_ren, t_ren_sub. apply t_sub_eq; now rewrite sub1_ren. Qed. #[global] Instance p_app_eq {Ξ A} (v : val Ξ A) (m : pat (t_neg A)) : Proper (asgn_eq _ _ ==> eq) (p_app v m) . intros u1 u2 H; destruct A as [ [] | []]; cbn; now rewrite (w_sub_eq u1 u2 H). Qed. Definition refold_id_aux_P (Ξ : neg_ctx) p : pre_ty p -> Prop := match p with | pos => fun A => forall (v : whn Ξ `+A), p_of_w_0p _ v `α΅₯β p_dom_of_w_0p _ v = v | neg => fun A => forall (v : whn Ξ `-A), p_of_w_0n _ v `α΅₯β p_dom_of_w_0n _ v = v end . Lemma refold_id_aux {Ξ p} A : refold_id_aux_P Ξ p A . induction A; intros v. - dependent elimination v; destruct (s_prf c). - dependent elimination v; destruct (s_prf c). - dependent elimination v; [ destruct (s_prf c) | ]; auto. - dependent elimination v; [ destruct (s_prf c) | ]; auto. - dependent elimination v; [ destruct (s_prf c) | ]. cbn; f_equal; rewrite w_sub_ren. rewrite <- IHA1; apply w_sub_eq; exact (a_cat_proj_l _ _). rewrite <- IHA2; apply w_sub_eq; exact (a_cat_proj_r _ _). - dependent elimination v; [ destruct (s_prf c) | ]. cbn; f_equal; rewrite w_sub_ren. rewrite <- IHA1; apply w_sub_eq; exact (a_cat_proj_l _ _). rewrite <- IHA2; apply w_sub_eq; exact (a_cat_proj_r _ _). - dependent elimination v; [ destruct (s_prf c) | | ]; cbn; f_equal; [ apply IHA1 | apply IHA2 ]. - dependent elimination v; [ destruct (s_prf c) | | ]; cbn; f_equal; [ apply IHA1 | apply IHA2 ]. - dependent elimination v; [ destruct (s_prf c) | ]; cbn; f_equal. - dependent elimination v; [ destruct (s_prf c) | ]; cbn; f_equal. - dependent elimination v; [ destruct (s_prf c) | ]. cbn; f_equal; apply IHA. - dependent elimination v; [ destruct (s_prf c) | ]. cbn; f_equal; apply IHA. Qed. Lemma refold_id {Ξ : neg_ctx} A (v : val Ξ A) : p_of_v A v `α΅₯β p_dom_of_v A v = v. destruct A as [ [] A | [] A ]; auto; exact (refold_id_aux A v). Qed. Equations p_of_w_eq_aux_p {Ξ : neg_ctx} (A : pre_ty pos) (p : pat `+A) (e : p_dom p =[val]> Ξ) : p_of_w_0p A (p `α΅₯β e) = p by struct p := p_of_w_eq_aux_p (1) (POne) e := eq_refl ; p_of_w_eq_aux_p (A β B) (PTen p1 p2) e := f_equal2 PTen (eq_trans (f_equal _ (w_sub_ren _ _ _ _)) (p_of_w_eq_aux_p A p1 _)) (eq_trans (f_equal _ (w_sub_ren _ _ _ _)) (p_of_w_eq_aux_p B p2 _)) ; p_of_w_eq_aux_p (A β B) (POr1 p) e := f_equal POr1 (p_of_w_eq_aux_p A p e) ; p_of_w_eq_aux_p (A β B) (POr2 p) e := f_equal POr2 (p_of_w_eq_aux_p B p e) ; p_of_w_eq_aux_p (β A) (PShiftP _) e := eq_refl ; p_of_w_eq_aux_p (β A) (PNegP p) e := f_equal PNegP (p_of_w_eq_aux_n A p e) ; with p_of_w_eq_aux_n {Ξ : neg_ctx} (A : pre_ty neg) (p : pat `-A) (e : p_dom p =[val]> Ξ) : p_of_w_0n A (p `α΅₯β e) = p by struct p := p_of_w_eq_aux_n (β₯) (PBot) e := eq_refl ; p_of_w_eq_aux_n (A β B) (PPar p1 p2) e := f_equal2 PPar (eq_trans (f_equal _ (w_sub_ren _ _ _ _)) (p_of_w_eq_aux_n A p1 _)) (eq_trans (f_equal _ (w_sub_ren _ _ _ _)) (p_of_w_eq_aux_n B p2 _)) ; p_of_w_eq_aux_n (A & B) (PAnd1 p) e := f_equal PAnd1 (p_of_w_eq_aux_n A p e) ; p_of_w_eq_aux_n (A & B) (PAnd2 p) e := f_equal PAnd2 (p_of_w_eq_aux_n B p e) ; p_of_w_eq_aux_n (β A) (PShiftN _) e := eq_refl ; p_of_w_eq_aux_n (Β¬ A) (PNegN p) e := f_equal PNegN (p_of_w_eq_aux_p A p e) . Definition p_dom_of_w_eq_P (Ξ : neg_ctx) p : pre_ty p -> Prop := match p with | pos => fun A => forall (p : pat `+A) (e : p_dom p =[val]> Ξ), rew [fun p => p_dom p =[ val ]> Ξ] p_of_w_eq_aux_p A p e in p_dom_of_w_0p A (p `α΅₯β e) β‘β e | neg => fun A => forall (p : pat `-A) (e : p_dom p =[val]> Ξ), rew [fun p => p_dom p =[ val ]> Ξ] p_of_w_eq_aux_n A p e in p_dom_of_w_0n A (p `α΅₯β e) β‘β e end . Lemma p_dom_of_v_eq {Ξ p} A : p_dom_of_w_eq_P Ξ p A . induction A; intros p e; dependent elimination p; cbn - [ r_cat_l r_cat_r ]. - intros ? h; repeat (dependent elimination h; auto). - intros ? h; repeat (dependent elimination h; auto). - pose (H1 := w_sub_ren r_cat_l e `+A3 (w_of_p p)) . pose (H2 := w_sub_ren r_cat_r e `+B (w_of_p p0)) . pose (x1 := w_of_p p `α΅₯βα΅£ r_cat_l `α΅₯β e). pose (x2 := w_of_p p0 `α΅₯βα΅£ r_cat_r `α΅₯β e). change (w_sub_ren r_cat_l e _ _) with H1. change (w_sub_ren r_cat_r e _ _) with H2. change (_ `α΅₯βα΅£ r_cat_l `α΅₯β e) with x1 in H1 |- *. change (_ `α΅₯βα΅£ r_cat_r `α΅₯β e) with x2 in H2 |- *. rewrite H1, H2; clear H1 H2 x1 x2; cbn - [ r_cat_l r_cat_r ]. pose (H1 := p_of_w_eq_aux_p A3 p (r_cat_l α΅£β e)); change (p_of_w_eq_aux_p A3 _ _) with H1 in IHA1 |- *. pose (H2 := p_of_w_eq_aux_p B p0 (r_cat_r α΅£β e)); change (p_of_w_eq_aux_p B _ _) with H2 in IHA2 |- *. transitivity ([ rew [fun p : pat `+A3 => p_dom p =[ val ]> Ξ] H1 in p_dom_of_w_0p A3 (w_of_p p `α΅₯β r_cat_l α΅£β e) , rew [fun p : pat `+B => p_dom p =[ val ]> Ξ] H2 in p_dom_of_w_0p B (w_of_p p0 `α΅₯β r_cat_r α΅£β e) ])%asgn. now rewrite <- H1, <- H2, eq_refl_map2_distr. refine (a_cat_uniq _ _ _ _ _); [ apply IHA1 | apply IHA2 ] . - pose (H1 := w_sub_ren r_cat_l e `-A4 (w_of_p p1)) . pose (H2 := w_sub_ren r_cat_r e `-B0 (w_of_p p2)) . pose (x1 := w_of_p p1 `α΅₯βα΅£ r_cat_l `α΅₯β e). pose (x2 := w_of_p p2 `α΅₯βα΅£ r_cat_r `α΅₯β e). change (w_sub_ren r_cat_l e _ _) with H1. change (w_sub_ren r_cat_r e _ _) with H2. change (_ `α΅₯βα΅£ r_cat_l `α΅₯β e) with x1 in H1 |- *. change (_ `α΅₯βα΅£ r_cat_r `α΅₯β e) with x2 in H2 |- *. rewrite H1, H2; clear H1 H2 x1 x2; cbn - [ r_cat_l r_cat_r ]. pose (H1 := p_of_w_eq_aux_n A4 p1 (r_cat_l α΅£β e)); change (p_of_w_eq_aux_n A4 _ _) with H1 in IHA1 |- *. pose (H2 := p_of_w_eq_aux_n B0 p2 (r_cat_r α΅£β e)); change (p_of_w_eq_aux_n B0 _ _) with H2 in IHA2 |- *. transitivity ([ rew [fun p : pat `-A4 => p_dom p =[ val ]> Ξ] H1 in p_dom_of_w_0n A4 (w_of_p p1 `α΅₯β r_cat_l α΅£β e) , rew [fun p : pat `-B0 => p_dom p =[ val ]> Ξ] H2 in p_dom_of_w_0n B0 (w_of_p p2 `α΅₯β r_cat_r α΅£β e) ])%asgn. now rewrite <- H1, <- H2, eq_refl_map2_distr. refine (a_cat_uniq _ _ _ _ _); [ apply IHA1 | apply IHA2 ] . - match goal with | |- ?s β‘β e => pose (xx := s); change (_ β‘β e) with (xx β‘β e) end . remember xx as xx'; unfold xx in Heqxx'; clear xx. rewrite (eq_trans Heqxx' (eq_sym (rew_map _ POr1 _ _))). apply IHA1. - match goal with | |- ?s β‘β e => pose (xx := s); change (_ β‘β e) with (xx β‘β e) end . remember xx as xx'; unfold xx in Heqxx'; clear xx. rewrite (eq_trans Heqxx' (eq_sym (rew_map _ POr2 _ _))). apply IHA2. - match goal with | |- ?s β‘β e => pose (xx := s); change (_ β‘β e) with (xx β‘β e) end . remember xx as xx'; unfold xx in Heqxx'; clear xx. rewrite (eq_trans Heqxx' (eq_sym (rew_map _ PAnd1 _ _))). apply IHA1. - match goal with | |- ?s β‘β e => pose (xx := s); change (_ β‘β e) with (xx β‘β e) end . remember xx as xx'; unfold xx in Heqxx'; clear xx. rewrite (eq_trans Heqxx' (eq_sym (rew_map _ PAnd2 _ _))). apply IHA2. - intros ? v; repeat (dependent elimination v; auto). - intros ? v; repeat (dependent elimination v; auto). - match goal with | |- ?s β‘β e => pose (xx := s); change (_ β‘β e) with (xx β‘β e) end . remember xx as xx'; unfold xx in Heqxx'; clear xx. rewrite (eq_trans Heqxx' (eq_sym (rew_map _ PNegP _ _))). apply IHA. - match goal with | |- ?s β‘β e => pose (xx := s); change (_ β‘β e) with (xx β‘β e) end . remember xx as xx'; unfold xx in Heqxx'; clear xx. rewrite (eq_trans Heqxx' (eq_sym (rew_map _ PNegN _ _))). apply IHA. Qed. (* coq unification drives me crazy!! *) Definition upg_vp {Ξ} {A : pre_ty pos} : whn Ξ `+A -> val Ξ `+A := fun v => v. Definition upg_kp {Ξ} {A : pre_ty pos} : term Ξ `-A -> val Ξ `-A := fun v => v. Definition upg_vn {Ξ} {A : pre_ty neg} : term Ξ `+A -> val Ξ `+A := fun v => v. Definition upg_kn {Ξ} {A : pre_ty neg} : whn Ξ `-A -> val Ξ `-A := fun v => v. Definition dwn_vp {Ξ} {A : pre_ty pos} : val Ξ `+A -> whn Ξ `+A := fun v => v. Definition dwn_kp {Ξ} {A : pre_ty pos} : val Ξ `-A -> term Ξ `-A := fun v => v. Definition dwn_vn {Ξ} {A : pre_ty neg} : val Ξ `+A -> term Ξ `+A := fun v => v. Definition dwn_kn {Ξ} {A : pre_ty neg} : val Ξ `-A -> whn Ξ `-A := fun v => v. Lemma nf_eq_split_p {Ξ : neg_ctx} {A : pre_ty pos} (i : Ξ β `-A) (p : pat `+A) Ξ³ : nf_eq (i β v_split_p (dwn_vp (p `α΅₯β Ξ³))) (i β (p : o_op obs_op `-A) β¦ Ξ³ β¦). unfold v_split_p, dwn_vp; cbn. pose proof (p_dom_of_v_eq A p Ξ³). pose (H' := p_of_w_eq_aux_p A p Ξ³); fold H' in H. pose (a := p_dom_of_w_0p A (w_of_p p `α΅₯β Ξ³)); fold a in H |- *. remember a as a'; clear a Heqa'. revert a' H; rewrite H'; intros; now econstructor. Qed. Lemma nf_eq_split_n {Ξ : neg_ctx} {A : pre_ty neg} (i : Ξ β `+A) (p : pat `-A) Ξ³ : nf_eq (i β v_split_n (dwn_kn (p `α΅₯β Ξ³))) (i β (p : o_op obs_op `+A) β¦ Ξ³ β¦). unfold v_split_n, dwn_kn; cbn. pose proof (p_dom_of_v_eq A p Ξ³). pose (H' := p_of_w_eq_aux_n A p Ξ³); fold H' in H. pose (a := p_dom_of_w_0n A (w_of_p p `α΅₯β Ξ³)); fold a in H |- *. remember a as a'; clear a Heqa'. revert a' H; rewrite H'; intros; now econstructor. Qed.
Finally we can return to saner pursuits.
The notion of values and configurations we will pass to the generic OGS construction
are our mu-mu-tilde values and states, but restricted to negative typing contexts. As
such, while we have proven all the metatheory for arbitrary typing contexts, we still
need a tiny bit of work to provide the laws in this special case. Once again, thanks to
our tricky notion of subset context (Ctx/Subset.v
), there is no need to cross a
complex isomorphism (between contexts of negative types and contexts of types where
all types are negative). We start by instanciating the substitution structures and
their laws.
Notation val_n := (val β neg_c_coe).
Notation state_n := (state β neg_c_coe).
#[global] Instance val_n_monoid : subst_monoid val_n .
esplit.
- intros Ξ x i; exact (var i).
- intros Ξ x v Ξ f; exact (v α΅₯β f).
Defined.
#[global] Instance state_n_module : subst_module val_n state_n .
esplit; intros Ξ s Ξ f; exact (s ββ (f : Ξ =[val]> Ξ)).
Defined.
#[global] Instance val_n_laws : subst_monoid_laws val_n .
esplit.
- intros ???? <- ????; now apply v_sub_eq.
- intros ?????; now apply v_sub_id_r.
- intros ???; now apply v_sub_id_l.
- intros ???????; symmetry; now apply v_sub_sub.
Qed.
#[global] Instance state_n_laws : subst_module_laws val_n state_n .
esplit.
- intros ??? <- ????; now apply s_sub_eq.
- intros ??; now apply s_sub_id_l.
- intros ??????; symmetry; now apply s_sub_sub.
Qed.
Variable assumptions, that is, lemmata related to decidability of a value being a variable are easily proven inline.
#[global] Instance var_laws : var_assumptions val_n. esplit. - intros ? [[]|[]] ?? H; now dependent destruction H. - intros ? [[]|[]] v; dependent elimination v. 10,13: dependent elimination w. all: try exact (Yes _ (Vvar _)). all: apply No; intro H; dependent destruction H. - intros ?? [[]|[]] ???; cbn in v; dependent induction v. all: try now dependent destruction X; exact (Vvar _). all: dependent induction w; dependent destruction X; exact (Vvar _). Qed.
And we conclude the easy part by instanciating the relevant part of the language machine.
#[global] Instance sysd_machine : machine val_n state_n obs_op :=
{| Machine.eval := @eval ; oapp := @p_app |} .
It now suffices to prove the remaining assumptions on the language machine: that evaluation respects substitution and that the 'bad-instanciation' relation has finite chains. For this we pull in some tooling for coinductive reasoning.
From Coinduction Require Import coinduction lattice rel tactics.
Ltac refold_eval :=
change (Structure.iter _ _ ?a) with (eval a);
change (Structure.subst (fun pat : T1 => let 'T1_0 := pat in ?f) T1_0 ?u)
with (bind_delay' u f).
Let's go.
#[global] Instance machine_law : machine_laws val_n state_n obs_op.
First we have easy lemmata on observation application.
esplit. - intros; apply p_app_eq. - intros ?? [[]|[]] ????; cbn. 1,4: change (?a `ββ ?b) with (a α΅₯β b); now rewrite (w_sub_sub _ _ _ _). all: change (?a `α΅₯β ?b) with (a α΅₯β b) at 1; now rewrite (w_sub_sub _ _ _ _).
Next we prove the core argument of OGS soundness: evaluating a substitution is like evaluating the configuration, substituting the result and evaluating again. While tedious the proof is basically direct, going by induction on the structure of one-step evaluation.
- cbn; intros Ξ Ξ; unfold comp_eq, it_eq; coinduction R CIH; intros c a. cbn; funelim (eval_aux c); try now destruct (s_prf i). + cbn; econstructor; refold_eval. change (?t `ββ ?a) with (upg_kp t α΅₯β a); rewrite s_sub1_sub. apply CIH. + cbn; econstructor; refold_eval. change (?t `α΅₯β ?a) with (upg_vp t α΅₯β a); rewrite s_sub1_sub. apply CIH. + cbn; econstructor; refold_eval. change (RecL (?t `ββ a_shift1 ?a)) with (upg_kp (RecL t) α΅₯β a); rewrite t_sub1_sub. apply CIH. + change (it_eqF _ ?RX ?RY _ _ _) with (it_eq_map β β RX RY T1_0 (eval (Cut _ (Whn (v `α΅₯β a)) (a `- A i))) (eval (Cut _ (Whn ((w_of_p (p_of_w_0p A v) `α΅₯β nf_args (s_var_upg i β v_split_p v)) `α΅₯β a)) (var (s_var_upg i) `ββ a)))). unfold nf_args, v_split_p, cut_r, fill_args. now rewrite (refold_id_aux A v). + cbn; econstructor; refold_eval; apply CIH. + cbn; econstructor; refold_eval. change (?v `α΅₯β ?a) with (upg_vp v α΅₯β a); rewrite s_sub2_sub. apply CIH. + cbn; econstructor; refold_eval. change (?v `α΅₯β ?a) with (upg_vp v α΅₯β a); rewrite s_sub1_sub. apply CIH. + cbn; econstructor; refold_eval. change (?v `α΅₯β ?a) with (upg_vp v α΅₯β a); rewrite s_sub1_sub. apply CIH. + cbn; econstructor; refold_eval. change (?v `ββ ?a) with (upg_vn v α΅₯β a); rewrite s_sub1_sub. apply CIH. + cbn; econstructor; refold_eval. change (?v `α΅₯β ?a) with (upg_kn v α΅₯β a); rewrite s_sub1_sub. apply CIH. + cbn; econstructor; refold_eval. change (?v `ββ ?a) with (upg_vn v α΅₯β a); rewrite s_sub1_sub. apply CIH. + cbn; econstructor; refold_eval. change (?v `α΅₯β ?a) with (upg_kn v α΅₯β a); rewrite s_sub1_sub. apply CIH. + cbn; econstructor; refold_eval. change (RecR (?t `ββ a_shift1 ?a)) with (upg_vn (RecR t) α΅₯β a); rewrite t_sub1_sub. apply CIH. + change (it_eqF _ ?RX ?RY _ _ _) with (it_eq_map β β RX RY T1_0 (eval (Cut _ (a `+ A i) (Whn (k `α΅₯β a)))) (eval (Cut _ (var (s_var_upg i) `ββ a) (Whn ((w_of_p (p_of_w_0n A k) `α΅₯β nf_args (s_var_upg i β v_split_n k)) `α΅₯β a))))). unfold nf_args, v_split_n, cut_r, fill_args. now rewrite (refold_id_aux A k). + cbn; econstructor; refold_eval; apply CIH. + cbn; econstructor; refold_eval. change (?v `α΅₯β ?a) with (upg_kn v α΅₯β a); rewrite s_sub2_sub. apply CIH. + cbn; econstructor; refold_eval. change (?v `α΅₯β ?a) with (upg_kn v α΅₯β a); rewrite s_sub1_sub. apply CIH. + cbn; econstructor; refold_eval. change (?v `α΅₯β ?a) with (upg_kn v α΅₯β a); rewrite s_sub1_sub. apply CIH. + cbn; econstructor; refold_eval. change (?v `ββ ?a) with (upg_kp v α΅₯β a); rewrite s_sub1_sub. apply CIH. + cbn; econstructor; refold_eval. change (?v `α΅₯β ?a) with (upg_vp v α΅₯β a); rewrite s_sub1_sub. apply CIH.
Next we prove that evaluating a normal form is just returning this normal form. This goes by approximately induction on observations.
- cbn; intros ? [ A i [ o Ξ³ ]]; cbn; unfold p_app, nf_args, cut_r, fill_args. cbn in o; funelim (w_of_p o); simpl_depind; inversion eqargs. all: match goal with | H : _ = ?Aβ |- _ => destruct A; dependent destruction H end. 1-2: unfold c_var in i; destruct (s_prf i). all: dependent destruction eqargs; cbn. all: apply it_eq_unstep; cbn -[w_of_p]; econstructor. 1-2: now econstructor. all: match goal with | Ξ³ : dom ?p =[val_n]> _ |- _ => first [ exact (nf_eq_split_p _ p Ξ³) | exact (nf_eq_split_n _ p Ξ³) ] end.
Finally we prove the finite chain property. The proof here is quite tedious again, with numerous cases, but it is still by brutally walking through the structure of one-step evaluation and finding the needed redex.
- intros A; econstructor; intros [ B m ] H; dependent elimination H; cbn [projT1 projT2] in i, i0. destruct y as [ [] | [] ]. all: dependent elimination v; try now destruct (t0 (Vvar _)). all: clear t0. all: dependent elimination o; cbn in i0. all: match goal with | u : dom _ =[val_n]> _ |- _ => cbn in i0; pose (vv := u _ Ctx.top); change (u _ Ctx.top) with vv in i0; remember vv as v'; clear u vv Heqv'; cbn in v' | _ => idtac end. 7-18,25-36: apply it_eq_step in i0; now inversion i0. 1-9,19-24: match goal with | t : term _ _ |- _ => dependent elimination t; [ apply it_eq_step in i0; now inversion i0 | apply it_eq_step in i0; now inversion i0 | ] | _ => idtac end. all: match goal with | t : evalβ (Cut _ (Whn ?w) _) β _ |- _ => dependent elimination w; [ | apply it_eq_step in i0; now inversion i0 ] | t : evalβ (Cut _ _ (Whn ?w)) β _ |- _ => dependent elimination w; [ | apply it_eq_step in i0; now inversion i0 ] | _ => idtac end. all: apply it_eq_step in i0; cbn in i0; dependent elimination i0; cbn in r_rel; apply noConfusion_inv in r_rel; unfold v_split_n,v_split_p in r_rel; cbn in r_rel; unfold NoConfusionHom_f_cut,s_var_upg in r_rel; cbn in r_rel; pose proof (H := f_equal pr1 r_rel); cbn in H; dependent destruction H; apply DepElim.pr2_uip in r_rel; pose proof (H := f_equal pr1 r_rel); cbn in H; dependent destruction H; apply DepElim.pr2_uip in r_rel; dependent destruction r_rel. all: econstructor; intros [ t o ] H; cbn in t,o; dependent elimination H; dependent elimination v; [ apply it_eq_step in i0; cbn in i0; now inversion i0 | apply it_eq_step in i0; cbn in i0; now inversion i0 | ]. all: match goal with | H : is_var (Whn ?w) -> _ |- _ => dependent elimination w; try now destruct (H (Vvar _)) end. all: apply it_eq_step in i0; cbn in i0; dependent elimination i0. Qed.
We have finished instanciating our generic OGS construction on the System D calculus. For good measure we give here the concrete instanciation of the soundness theorem, stating that bisimilarity of the OGS strategies substitution equivalence.
Definition subst_eq (Ξ : neg_ctx) {Ξ} : relation (state Ξ) :=
fun u v => forall (Ο : Ξ =[val]> Ξ), evalβ (u ββ Ο : state_n Ξ) β evalβ (v ββ Ο : state_n Ξ) .
Notation "x ββ¦sub Ξ β§β y" := (subst_eq Ξ x y) (at level 50).
Theorem subst_correct (Ξ : neg_ctx) {Ξ : neg_ctx} (x y : state Ξ)
: x ββ¦ogs Ξ β§β y -> x ββ¦sub Ξ β§β y.
exact (ogs_correction _ x y).
Qed.
Finally it does not cost much to recover the more standard CIU equivalence, which we derive here for the case of terms (not co-terms).
Definition c_of_t {Ξ : neg_ctx} {A : pre_ty pos} (t : term Ξ `+A)
: state_n (Ξ βΆβ {| sub_elt := `-A ; sub_prf := stt |}) :=
Cut _ (t_shift1 _ t) (Whn (Var Ctx.top)) .
Notation "'nameβΊ'" := c_of_t.
Definition a_of_sk {Ξ Ξ : neg_ctx} {A : pre_ty pos} (s : Ξ =[val]> Ξ) (k : term Ξ `-A)
: (Ξ βΆβ {| sub_elt := `-A ; sub_prf := stt |}) =[val_n]> Ξ :=
[ s ,β k : val Ξ `-A ].
Lemma sub_csk {Ξ Ξ : neg_ctx} {A : pre_ty pos} (t : term Ξ `+A) (s : Ξ =[val]> Ξ)
(k : term Ξ `-A)
: Cut _ (t `ββ s) k = c_of_t t ββ a_of_sk s k.
Proof.
cbn; f_equal; unfold t_shift1; rewrite t_sub_ren; now apply t_sub_eq.
Qed.
Definition ciu_eq (Ξ : neg_ctx) {Ξ} {A : pre_ty pos} : relation (term Ξ `+A) :=
fun u v =>
forall (Ο : Ξ =[val]> Ξ) (k : term Ξ `-A),
evalβ (Cut _ (u `ββ Ο) k : state_n Ξ) β evalβ (Cut _ (v `ββ Ο) k : state_n Ξ) .
Notation "x ββ¦ciu Ξ β§βΊβ y" := (ciu_eq Ξ x y) (at level 50).
Theorem ciu_correct (Ξ : neg_ctx) {Ξ : neg_ctx} {A} (x y : term Ξ `+A)
: (nameβΊ x) ββ¦ogs Ξ β§β (nameβΊ y) -> x ββ¦ciu Ξ β§βΊβ y.
intros H Ο k; rewrite 2 sub_csk.
now apply subst_correct.
Qed.