Library iris.program_logic.ectxi_language
An axiomatization of languages based on evaluation context items, including
a proof that these are instances of general ectx-based languages.
From iris.algebra Require Export base.
From iris.program_logic Require Import language ectx_language.
Class EctxiLanguage (expr val ectx_item state : Type) := {
of_val : val → expr;
to_val : expr → option val;
fill_item : ectx_item → expr → expr;
head_step : expr → state → expr → state → option expr → Prop;
to_of_val v : to_val (of_val v) = Some v;
of_to_val e v : to_val e = Some v → of_val v = e;
val_stuck e1 σ1 e2 σ2 ef : head_step e1 σ1 e2 σ2 ef → to_val e1 = None;
fill_item_inj Ki :> Inj (=) (=) (fill_item Ki);
fill_item_val Ki e : is_Some (to_val (fill_item Ki e)) → is_Some (to_val e);
fill_item_no_val_inj Ki1 Ki2 e1 e2 :
to_val e1 = None → to_val e2 = None →
fill_item Ki1 e1 = fill_item Ki2 e2 → Ki1 = Ki2;
head_ctx_step_val Ki e σ1 e2 σ2 ef :
head_step (fill_item Ki e) σ1 e2 σ2 ef → is_Some (to_val e);
}.
Arguments of_val {_ _ _ _ _} _.
Arguments to_val {_ _ _ _ _} _.
Arguments fill_item {_ _ _ _ _} _ _.
Arguments head_step {_ _ _ _ _} _ _ _ _ _.
Arguments to_of_val {_ _ _ _ _} _.
Arguments of_to_val {_ _ _ _ _} _ _ _.
Arguments val_stuck {_ _ _ _ _} _ _ _ _ _ _.
Arguments fill_item_val {_ _ _ _ _} _ _ _.
Arguments fill_item_no_val_inj {_ _ _ _ _} _ _ _ _ _ _ _.
Arguments head_ctx_step_val {_ _ _ _ _} _ _ _ _ _ _ _.
Arguments step_by_val {_ _ _ _ _} _ _ _ _ _ _ _ _ _ _ _.
Section ectxi_language.
Context {expr val ectx_item state}
{Λ : EctxiLanguage expr val ectx_item state}.
Implicit Types (e : expr) (Ki : ectx_item).
Notation ectx := (list ectx_item).
Definition fill (K : ectx) (e : expr) : expr := fold_right fill_item e K.
Instance fill_inj K : Inj (=) (=) (fill K).
Proof. red; induction K as [|Ki K IH]; naive_solver. Qed.
Lemma fill_val K e : is_Some (to_val (fill K e)) → is_Some (to_val e).
Proof.
induction K; simpl; first done. intros ?%fill_item_val. eauto.
Qed.
Lemma fill_val_2:
(∀ Ki e1 e2, is_Some (to_val e1) → is_Some (to_val e2) →
is_Some (to_val (fill_item Ki e1)) →
is_Some (to_val (fill_item Ki e2))) →
∀ K e1 e2, is_Some (to_val e1) → is_Some (to_val e2) →
is_Some (to_val (fill K e1)) →
is_Some (to_val (fill K e2)).
Proof.
intros HKi K. revert HKi.
induction K; intros HKi e1 e2; eauto.
rewrite //=. intros Hv1 Hv2 Hfill.
eapply HKi.
- eapply fill_item_val. eauto.
- eapply IHK.
× apply HKi.
× apply Hv1.
× apply Hv2.
× eapply fill_item_val. eauto.
- eauto.
Qed.
Lemma fill_not_val K e : to_val e = None → to_val (fill K e) = None.
Proof. rewrite !eq_None_not_Some. eauto using fill_val. Qed.
Lemma step_by_val K K' e1 e1' σ1 e2 σ2 ef :
fill K e1 = fill K' e1' → to_val e1 = None → head_step e1' σ1 e2 σ2 ef →
∃ K'', K' = K ++ K''. Proof.
intros Hfill Hred Hnval; revert K' Hfill.
induction K as [|Ki K IH]; simpl; intros K' Hfill; first by eauto.
destruct K' as [|Ki' K']; simplify_eq/=.
{ exfalso; apply (eq_None_not_Some (to_val (fill K e1)));
eauto using fill_not_val, head_ctx_step_val. }
cut (Ki = Ki'); [naive_solver eauto using prefix_of_cons|].
eauto using fill_item_no_val_inj, val_stuck, fill_not_val.
Qed.
Global Program Instance : EctxLanguage expr val ectx state :=
Build_EctxLanguage expr val ectx state of_val to_val [] (++) fill head_step _ _ _ _ _ _ _ _ _.
Solve Obligations with eauto using to_of_val, of_to_val, val_stuck,
fill_not_val, step_by_val, fold_right_app, app_eq_nil.
Global Instance ectxi_lang_ctx_item Ki :
LanguageCtx (ectx_lang expr) (fill_item Ki).
Proof. change (LanguageCtx _ (fill [Ki])). apply _. Qed.
Lemma head_step_det_prim_det:
(∀ e σ e1' σ1' ef1' e2' σ2' ef2',
head_step e σ e1' σ1' ef1' →
head_step e σ e2' σ2' ef2' →
e1' = e2' ∧ σ1' = σ2' ∧ ef1' = ef2') →
(∀ e σ e1' σ1' ef1' e2' σ2' ef2',
prim_step e σ e1' σ1' ef1' →
prim_step e σ e2' σ2' ef2' →
e1' = e2' ∧ σ1' = σ2' ∧ ef1' = ef2').
Proof.
intros Hdet e σ e1' σ1' ef1' e2' σ2' ef2' Hprim1 Hprim2.
inversion Hprim1 as [K1 efill1 e1'' ??]; subst.
inversion Hprim2 as [K2 efill2 e2'' ??]; subst.
assert (efill1 = efill2 ∧ K1 = K2) as (->&->).
{ edestruct (step_by_val K1 K2) as (K1'&Hpre1); eauto using val_stuck.
edestruct (step_by_val K2 K1) as (K2'&Hpre2); eauto using val_stuck.
rewrite Hpre1 in Hpre2.
rewrite -app_assoc -{1}(app_nil_r K1) in Hpre2.
apply app_inv_head in Hpre2.
symmetry in Hpre2. apply app_eq_nil in Hpre2 as (->&->).
rewrite ?app_nil_r in Hpre1. subst.
split; auto.
eapply fill_inj; eauto.
}
edestruct (Hdet efill2 σ e1'' σ1' ef1' e2'') as (->&->&->); eauto.
Qed.
End ectxi_language.
From iris.program_logic Require Import language ectx_language.
Class EctxiLanguage (expr val ectx_item state : Type) := {
of_val : val → expr;
to_val : expr → option val;
fill_item : ectx_item → expr → expr;
head_step : expr → state → expr → state → option expr → Prop;
to_of_val v : to_val (of_val v) = Some v;
of_to_val e v : to_val e = Some v → of_val v = e;
val_stuck e1 σ1 e2 σ2 ef : head_step e1 σ1 e2 σ2 ef → to_val e1 = None;
fill_item_inj Ki :> Inj (=) (=) (fill_item Ki);
fill_item_val Ki e : is_Some (to_val (fill_item Ki e)) → is_Some (to_val e);
fill_item_no_val_inj Ki1 Ki2 e1 e2 :
to_val e1 = None → to_val e2 = None →
fill_item Ki1 e1 = fill_item Ki2 e2 → Ki1 = Ki2;
head_ctx_step_val Ki e σ1 e2 σ2 ef :
head_step (fill_item Ki e) σ1 e2 σ2 ef → is_Some (to_val e);
}.
Arguments of_val {_ _ _ _ _} _.
Arguments to_val {_ _ _ _ _} _.
Arguments fill_item {_ _ _ _ _} _ _.
Arguments head_step {_ _ _ _ _} _ _ _ _ _.
Arguments to_of_val {_ _ _ _ _} _.
Arguments of_to_val {_ _ _ _ _} _ _ _.
Arguments val_stuck {_ _ _ _ _} _ _ _ _ _ _.
Arguments fill_item_val {_ _ _ _ _} _ _ _.
Arguments fill_item_no_val_inj {_ _ _ _ _} _ _ _ _ _ _ _.
Arguments head_ctx_step_val {_ _ _ _ _} _ _ _ _ _ _ _.
Arguments step_by_val {_ _ _ _ _} _ _ _ _ _ _ _ _ _ _ _.
Section ectxi_language.
Context {expr val ectx_item state}
{Λ : EctxiLanguage expr val ectx_item state}.
Implicit Types (e : expr) (Ki : ectx_item).
Notation ectx := (list ectx_item).
Definition fill (K : ectx) (e : expr) : expr := fold_right fill_item e K.
Instance fill_inj K : Inj (=) (=) (fill K).
Proof. red; induction K as [|Ki K IH]; naive_solver. Qed.
Lemma fill_val K e : is_Some (to_val (fill K e)) → is_Some (to_val e).
Proof.
induction K; simpl; first done. intros ?%fill_item_val. eauto.
Qed.
Lemma fill_val_2:
(∀ Ki e1 e2, is_Some (to_val e1) → is_Some (to_val e2) →
is_Some (to_val (fill_item Ki e1)) →
is_Some (to_val (fill_item Ki e2))) →
∀ K e1 e2, is_Some (to_val e1) → is_Some (to_val e2) →
is_Some (to_val (fill K e1)) →
is_Some (to_val (fill K e2)).
Proof.
intros HKi K. revert HKi.
induction K; intros HKi e1 e2; eauto.
rewrite //=. intros Hv1 Hv2 Hfill.
eapply HKi.
- eapply fill_item_val. eauto.
- eapply IHK.
× apply HKi.
× apply Hv1.
× apply Hv2.
× eapply fill_item_val. eauto.
- eauto.
Qed.
Lemma fill_not_val K e : to_val e = None → to_val (fill K e) = None.
Proof. rewrite !eq_None_not_Some. eauto using fill_val. Qed.
Lemma step_by_val K K' e1 e1' σ1 e2 σ2 ef :
fill K e1 = fill K' e1' → to_val e1 = None → head_step e1' σ1 e2 σ2 ef →
∃ K'', K' = K ++ K''. Proof.
intros Hfill Hred Hnval; revert K' Hfill.
induction K as [|Ki K IH]; simpl; intros K' Hfill; first by eauto.
destruct K' as [|Ki' K']; simplify_eq/=.
{ exfalso; apply (eq_None_not_Some (to_val (fill K e1)));
eauto using fill_not_val, head_ctx_step_val. }
cut (Ki = Ki'); [naive_solver eauto using prefix_of_cons|].
eauto using fill_item_no_val_inj, val_stuck, fill_not_val.
Qed.
Global Program Instance : EctxLanguage expr val ectx state :=
Build_EctxLanguage expr val ectx state of_val to_val [] (++) fill head_step _ _ _ _ _ _ _ _ _.
Solve Obligations with eauto using to_of_val, of_to_val, val_stuck,
fill_not_val, step_by_val, fold_right_app, app_eq_nil.
Global Instance ectxi_lang_ctx_item Ki :
LanguageCtx (ectx_lang expr) (fill_item Ki).
Proof. change (LanguageCtx _ (fill [Ki])). apply _. Qed.
Lemma head_step_det_prim_det:
(∀ e σ e1' σ1' ef1' e2' σ2' ef2',
head_step e σ e1' σ1' ef1' →
head_step e σ e2' σ2' ef2' →
e1' = e2' ∧ σ1' = σ2' ∧ ef1' = ef2') →
(∀ e σ e1' σ1' ef1' e2' σ2' ef2',
prim_step e σ e1' σ1' ef1' →
prim_step e σ e2' σ2' ef2' →
e1' = e2' ∧ σ1' = σ2' ∧ ef1' = ef2').
Proof.
intros Hdet e σ e1' σ1' ef1' e2' σ2' ef2' Hprim1 Hprim2.
inversion Hprim1 as [K1 efill1 e1'' ??]; subst.
inversion Hprim2 as [K2 efill2 e2'' ??]; subst.
assert (efill1 = efill2 ∧ K1 = K2) as (->&->).
{ edestruct (step_by_val K1 K2) as (K1'&Hpre1); eauto using val_stuck.
edestruct (step_by_val K2 K1) as (K2'&Hpre2); eauto using val_stuck.
rewrite Hpre1 in Hpre2.
rewrite -app_assoc -{1}(app_nil_r K1) in Hpre2.
apply app_inv_head in Hpre2.
symmetry in Hpre2. apply app_eq_nil in Hpre2 as (->&->).
rewrite ?app_nil_r in Hpre1. subst.
split; auto.
eapply fill_inj; eauto.
}
edestruct (Hdet efill2 σ e1'' σ1' ef1' e2'') as (->&->&->); eauto.
Qed.
End ectxi_language.