In this file we axiomatize what it means for a family to support substitution.
The specification of an evaluator will be separated in several steps. First we will ask for a family of values, i.e. objects that can be substituted for variables. We formalize well-typed well-scoped substitutions in the monoidal style of Fiore et al and Allais et al. Here we are generic over a notion of context, treating lists and DeBruijn indices in the usual well-typed well-scoped style, but also other similar notions. See Ctx/Abstract.v for more background on notions of variables and contexts and for the categorical presentation of substitution.
Class subst_monoid `{CC : context T C} (val : Famā T C) := {
v_var : c_var āā val ;
v_sub : val āā ā¦ val , val ā§ā ;
}.
#[global] Notation "v įµ„ā a" := (v_sub v a%asgn) (at level 30). Notation a_id := v_var.
By pointwise lifting of substitution we can define composition of assignments.
Definition a_comp `{subst_monoid T C val} {Ī1 Ī2 Ī3} : Ī1 =[val]> Ī2 -> Ī2 =[val]> Ī3 -> Ī1 =[val]> Ī3 := fun u v _ i => u _ i įµ„ā v. #[global] Infix "ā" := a_comp (at level 14) : asgn_scope.
The laws for monoids and modules are pretty straightforward. A specificity is that assignments are represented by functions from variables to values, as such their well-behaved equality is pointwise equality and we require substitution to respect it.
Class subst_monoid_laws `{CC : context T C} (val : Famā T C) {VM : subst_monoid val} := {
v_sub_proper :: Proper (āā Ī, āā _, eq ==> āā Ī, asgn_eq Ī Ī ==> eq) v_sub ;
v_sub_var {Ī1 Ī2 x} (i : Ī1 ā x) (p : Ī1 =[val]> Ī2)
: v_var i įµ„ā p = p _ i ;
v_var_sub {Ī x} (v : val Ī x)
: v įµ„ā a_id = v ;
v_sub_sub {Ī1 Ī2 Ī3 x} (v : val Ī1 x) (a : Ī1 =[val]> Ī2) (b : Ī2 =[val]> Ī3)
: v įµ„ā (a ā b) = (v įµ„ā a) įµ„ā b ;
} .
T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
H: subst_monoid_laws val
Ī1, Ī2: C
x: T
v: val Ī1 xProper (asgn_eq Ī1 Ī2 ==> eq) (v_sub v)now apply v_sub_proper. Qed.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
H: subst_monoid_laws val
Ī1, Ī2: C
x: T
v: val Ī1 xProper (asgn_eq Ī1 Ī2 ==> eq) (v_sub v)
Next, we ask for a module over the monoid of values, to represent the configurations of the machine.
Class subst_module `{CC : context T C} (val : Famā T C) (conf : Famā T C) := {
c_sub : conf āā ā¦ val , conf ā§ā ;
}.
#[global] Notation "c āā a" := (c_sub c a%asgn) (at level 30).
Again the laws should not be surprising.
Class subst_module_laws `{CC : context T C} (val : Famā T C) (conf : Famā T C) {VM : subst_monoid val} {CM : subst_module val conf} := { c_sub_proper :: Proper (āā Ī, eq ==> āā Ī, asgn_eq Ī Ī ==> eq) c_sub ; c_var_sub {Ī} (c : conf Ī) : c āā a_id = c ; c_sub_sub {Ī1 Ī2 Ī3} (c : conf Ī1) (a : Ī1 =[val]> Ī2) (b : Ī2 =[val]> Ī3) : c āā (a ā b) = (c āā a) āā b ; } .T, C: Type
CC: context T C
val: Famā T C
conf: Famā T C
VM: subst_monoid val
CM: subst_module val conf
H: subst_module_laws val conf
Ī1, Ī2: C
c: conf Ī1Proper (asgn_eq Ī1 Ī2 ==> eq) (c_sub c)now apply c_sub_proper. Qed.T, C: Type
CC: context T C
val: Famā T C
conf: Famā T C
VM: subst_monoid val
CM: subst_module val conf
H: subst_module_laws val conf
Ī1, Ī2: C
c: conf Ī1Proper (asgn_eq Ī1 Ī2 ==> eq) (c_sub c)
Now that we know that our families have a substitution operation and variables, we can readily derive a renaming operation. While we could have axiomatized it, together with its compatibility with substitution, allowing for possibly more efficient implementations, we prefer simplicity and work with this generic implementation in terms of substitution.
Section renaming. Context `{CC : context T C} {val : Famā T C} {conf : Famā T C}. Context {VM : subst_monoid val} {VML : subst_monoid_laws val}. Context {CM : subst_module val conf} {CML : subst_module_laws val conf}.
By post-composing with the substitution identity, we can embed renamings into assignments.
Definition r_emb {Ī Ī} (r : Ī ā Ī) : Ī =[val]> Ī := fun _ i => v_var (r _ i). #[global] Arguments r_emb {_ _} _ _ /.
Renaming is now simply a matter of substituting by the embedded renaming.
Definition v_ren : val āā ā¦ c_var , val ā§ā := fun _ _ v _ r => v įµ„ā r_emb r. Definition c_ren : conf āā ā¦ c_var , conf ā§ā := fun _ c _ r => c āā r_emb r. #[global] Arguments v_ren [Ī x] v [Ī] r /. #[global] Arguments c_ren [Ī] v [Ī] r /.
Finally we can rename assignments on the right.
Definition a_ren_r {Ī1 Ī2 Ī3} : Ī1 =[val]> Ī2 -> Ī2 ā Ī3 -> Ī1 =[val]> Ī3 := fun a r => (a ā (r_emb r))%asgn. #[global] Arguments a_ren_r _ _ _ _ _ _ /. End renaming. #[global] Notation "v įµ„āįµ£ r" := (v_ren v r%asgn) (at level 14). #[global] Notation "c āāįµ£ r" := (c_ren c r%asgn) (at level 14). #[global] Notation "a āįµ£ r" := (a_ren_r a r) (at level 14) : asgn_scope.
Something which we have absolutely pushed under the rug in the paper is a couple more mild technical hypotheses on the substitution monoid of values: since in the eventual guardedness proof we need to case split on whether or not a value is a variable, we need to ask for that to be possible! As such, we need the following additional assumptions:
These assumptions are named "clear-cut" in the paper (Def. 27).
We first define the fibers of v_var.
Variant is_var `{VM : subst_monoid T C val} {Ī x} : val Ī x -> Type := | Vvar (i : Ī ā x) : is_var (v_var i) . Equations is_var_get `{VM : subst_monoid T C val} {Ī x} {v : val Ī x} : is_var v -> Ī ā x := is_var_get (Vvar i) := i .
Which are obviously stable under renamings.
T, C: Type
CC: context T C
val: Famā T C
VM0: subst_monoid val
VM: subst_monoid_laws val
Ī1, Ī2: C
r: Ī1 ā Ī2
x: T
v: val Ī1 xis_var v -> is_var (v įµ„āįµ£ r)T, C: Type
CC: context T C
val: Famā T C
VM0: subst_monoid val
VM: subst_monoid_laws val
Ī1, Ī2: C
r: Ī1 ā Ī2
x: T
v: val Ī1 xis_var v -> is_var (v įµ„āįµ£ r)T, C: Type
CC: context T C
val: Famā T C
VM0: subst_monoid val
VM: subst_monoid_laws val
Ī1, Ī2: C
r: Ī1 ā Ī2
x: T
i: Ī1 ā xis_var (a_id i įµ„āįµ£ r)econstructor. Qed.T, C: Type
CC: context T C
val: Famā T C
VM0: subst_monoid val
VM: subst_monoid_laws val
Ī1, Ī2: C
r: Ī1 ā Ī2
x: T
i: Ī1 ā xis_var (r_emb r x i)
At last we define our last assumptions on variables (Def. 28).
Class var_assumptions `{CC : context T C} (val : Famā T C) {VM : subst_monoid val} := {
v_var_inj {Ī x} : injective (@v_var _ _ _ _ _ Ī x) ;
is_var_dec {Ī x} (v : val Ī x) : decidable (is_var v) ;
is_var_ren {Ī1 Ī2 x} (v : val Ī1 x) (r : Ī1 ā Ī2) : is_var (v įµ„āįµ£ r) -> is_var v ;
}.
Here we derive a couple helpers around these new assumptions.
Section variables. Context `{CC : context T C} {val : Famā T C}. Context {VM : subst_monoid val} {VML : subst_monoid_laws val}. Context {VA : var_assumptions val}.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
VA: var_assumptions val
Ī: C
x: T
v: val Ī x
p, q: is_var vp = qT, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
VA: var_assumptions val
Ī: C
x: T
v: val Ī x
p, q: is_var vp = qT, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
VA: var_assumptions val
Ī: C
x: T
v: val Ī x
p, q0: is_var v
i: Ī ā x
w: val Ī x
H: w = a_id i
q: is_var wVvar i = rew [is_var] H in qT, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
VA: var_assumptions val
Ī: C
x: T
v: val Ī x
p, q0: is_var v
i, i0: Ī ā x
H: a_id i0 = a_id iVvar i = rew [is_var] H in Vvar i0now dependent elimination H'; dependent elimination H. Qed.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
VA: var_assumptions val
Ī: C
x: T
v: val Ī x
p, q0: is_var v
i, i0: Ī ā x
H: a_id i0 = a_id i
H': i0 = iVvar i = rew [is_var] H in Vvar i0T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
VA: var_assumptions val
Ī: C
x: T
i: Ī ā x
p: is_var (a_id i)p = Vvar iapply is_var_irr. Qed. Variant is_var_ren_view {Ī1 Ī2 x} (v : val Ī1 x) (r : Ī1 ā Ī2) : is_var (v įµ„āįµ£ r) -> Type := | Vvren (H : is_var v) : is_var_ren_view v r (ren_is_var r H) .T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
VA: var_assumptions val
Ī: C
x: T
i: Ī ā x
p: is_var (a_id i)p = Vvar iT, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
VA: var_assumptions val
Ī1, Ī2: C
x: T
v: val Ī1 x
r: Ī1 ā Ī2
H: is_var (v įµ„āįµ£ r)is_var_ren_view v r Hrewrite (is_var_irr H (ren_is_var r (is_var_ren v r H))); econstructor. Qed.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
VA: var_assumptions val
Ī1, Ī2: C
x: T
v: val Ī1 x
r: Ī1 ā Ī2
H: is_var (v įµ„āįµ£ r)is_var_ren_view v r HT, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
VA: var_assumptions val
Ī1, Ī2: C
r: Ī1 ā Ī2
x: T
v: val Ī1 x
H: is_var vis_var_get (ren_is_var r H) = r x (is_var_get H)T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
VA: var_assumptions val
Ī1, Ī2: C
r: Ī1 ā Ī2
x: T
v: val Ī1 x
H: is_var vis_var_get (ren_is_var r H) = r x (is_var_get H)T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
VA: var_assumptions val
Ī1, Ī2: C
r: Ī1 ā Ī2
x: T
i: Ī1 ā xis_var_get (ren_is_var r (Vvar i)) = r x iT, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
VA: var_assumptions val
Ī1, Ī2: C
r: Ī1 ā Ī2
x: T
i: Ī1 ā xforall i0 : is_var (a_id i įµ„āįµ£ r), is_var_get i0 = r x inow rewrite (is_var_irr H (Vvar (r _ i))). Qed.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
VA: var_assumptions val
Ī1, Ī2: C
r: Ī1 ā Ī2
x: T
i: Ī1 ā x
H: is_var (a_id (r x i))is_var_get H = r x iT, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
VA: var_assumptions val
Ī: C
x: T
v: val Ī x
H: is_var vv = a_id (is_var_get H)now destruct H. Qed. End variables.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
VA: var_assumptions val
Ī: C
x: T
v: val Ī x
H: is_var vv = a_id (is_var_get H)
Finally we end with a couple derived property on assignments.
Section properties. Context {T C} {CC : context T C} (val : Famā T C). Context {VM : subst_monoid val} {VML : subst_monoid_laws val}.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2, Ī3: CProper (asgn_eq Ī1 Ī2 ==> asgn_eq Ī2 Ī3 ==> asgn_eq Ī1 Ī3) a_compintros ?? H1 ?? H2 ??; cbn; now rewrite H1, H2. Qed.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2, Ī3: CProper (asgn_eq Ī1 Ī2 ==> asgn_eq Ī2 Ī3 ==> asgn_eq Ī1 Ī3) a_compT, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2: CProper (asgn_eq Ī1 Ī2 ==> asgn_eq Ī1 Ī2) r_embintros ?? H ??; cbn; now rewrite H. Qed.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2: CProper (asgn_eq Ī1 Ī2 ==> asgn_eq Ī1 Ī2) r_embT, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2, Ī3: CProper (asgn_eq Ī1 Ī2 ==> asgn_eq Ī2 Ī3 ==> asgn_eq Ī1 Ī3) a_ren_rintros ?? H1 ?? H2 ??; cbn; now rewrite H1, H2. Qed.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2, Ī3: CProper (asgn_eq Ī1 Ī2 ==> asgn_eq Ī2 Ī3 ==> asgn_eq Ī1 Ī3) a_ren_rT, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2, Ī3: C
r: Ī1 ā Ī2
a: Ī2 =[ val ]> Ī3r_emb r ā a ā”ā r įµ£ā aintros ??; cbn; now rewrite v_sub_var. Qed.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2, Ī3: C
r: Ī1 ā Ī2
a: Ī2 =[ val ]> Ī3r_emb r ā a ā”ā r įµ£ā aT, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī: Cr_emb r_id ā”ā a_idreflexivity. Qed.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī: Cr_emb r_id ā”ā a_idT, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2, Ī3, Ī4: C
a: Ī1 =[ val ]> Ī2
b: Ī2 =[ val ]> Ī3
r: Ī3 ā Ī4(a ā b) āįµ£ r ā”ā a ā (b āįµ£ r)intros ??; cbn; now rewrite <-v_sub_sub. Qed.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2, Ī3, Ī4: C
a: Ī1 =[ val ]> Ī2
b: Ī2 =[ val ]> Ī3
r: Ī3 ā Ī4(a ā b) āįµ£ r ā”ā a ā (b āįµ£ r)T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2, Ī3, Ī4: C
a: Ī1 =[ val ]> Ī2
r: Ī2 ā Ī3
b: Ī3 =[ val ]> Ī4(a āįµ£ r) ā b ā”ā a ā (r įµ£ā b)intros ??; cbn; now rewrite <-v_sub_sub, a_ren_r_simpl. Qed.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2, Ī3, Ī4: C
a: Ī1 =[ val ]> Ī2
r: Ī2 ā Ī3
b: Ī3 =[ val ]> Ī4(a āįµ£ r) ā b ā”ā a ā (r įµ£ā b)T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2, Ī3, Ī4: C
a: Ī1 =[ val ]> Ī2
b: Ī2 =[ val ]> Ī3
c: Ī3 =[ val ]> Ī4(a ā b) ā c ā”ā a ā (b ā c)intros ??; cbn; now rewrite v_sub_sub. Qed.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2, Ī3, Ī4: C
a: Ī1 =[ val ]> Ī2
b: Ī2 =[ val ]> Ī3
c: Ī3 =[ val ]> Ī4(a ā b) ā c ā”ā a ā (b ā c)T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2: C
a: Ī1 =[ val ]> Ī2a ā a_id ā”ā aintros ??; cbn; now rewrite v_var_sub. Qed.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2: C
a: Ī1 =[ val ]> Ī2a ā a_id ā”ā aT, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2: C
a: Ī1 =[ val ]> Ī2a_id ā a ā”ā aT, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2: C
a: Ī1 =[ val ]> Ī2a_id ā a ā”ā anow rewrite v_sub_var. Qed. End properties.T, C: Type
CC: context T C
val: Famā T C
VM: subst_monoid val
VML: subst_monoid_laws val
Ī1, Ī2: C
a: Ī1 =[ val ]> Ī2
a0: T
a1: Ī1 ā a0a_id a1 įµ„ā a = a a0 a1