aboutsummaryrefslogtreecommitdiffstats
path: root/theories/dynlang
diff options
context:
space:
mode:
authorRutger Broekhoff2025-07-07 21:52:08 +0200
committerRutger Broekhoff2025-07-07 21:52:08 +0200
commitba61dfd69504ec6263a9dee9931d93adeb6f3142 (patch)
treed6c9b78e50eeab24e0c1c09ab45909a6ae3fd5db /theories/dynlang
downloadverified-dyn-lang-interp-ba61dfd69504ec6263a9dee9931d93adeb6f3142.tar.gz
verified-dyn-lang-interp-ba61dfd69504ec6263a9dee9931d93adeb6f3142.zip
Initialize repository
Diffstat (limited to 'theories/dynlang')
-rw-r--r--theories/dynlang/equiv.v154
-rw-r--r--theories/dynlang/interp.v49
-rw-r--r--theories/dynlang/interp_proofs.v426
-rw-r--r--theories/dynlang/operational.v41
-rw-r--r--theories/dynlang/operational_props.v33
5 files changed, 703 insertions, 0 deletions
diff --git a/theories/dynlang/equiv.v b/theories/dynlang/equiv.v
new file mode 100644
index 0000000..aa0b7f3
--- /dev/null
+++ b/theories/dynlang/equiv.v
@@ -0,0 +1,154 @@
1From mininix Require Export lambda.interp_proofs dynlang.interp_proofs.
2From stdpp Require Import options.
3
4Class Lift A B := lift : A → B.
5Global Hint Mode Lift ! - : typeclass_instances.
6Arguments lift {_ _ _} !_ /.
7Notation "⌜ x ⌝" := (lift x) (at level 0).
8Notation "⌜* x ⌝" := (fmap lift x) (at level 0).
9
10Module lambda.
11 Global Instance lambda_expr_lift : Lift lambda.expr dynlang.expr :=
12 fix go e := let _ : Lift _ _ := go in
13 match e with
14 | lambda.EString s => dynlang.EString s
15 | lambda.EId x => dynlang.EId ∅ (dynlang.EString x)
16 | lambda.EAbs x e => dynlang.EAbs (dynlang.EString x) ⌜e⌝
17 | lambda.EApp e1 e2 => dynlang.EApp ⌜e1⌝ ⌜e2⌝
18 end.
19
20 Global Instance lambda_thunk_lift : Lift lambda.thunk dynlang.thunk :=
21 fix go t := let _ : Lift _ _ := go in
22 dynlang.Thunk ⌜*lambda.thunk_env t⌝ ⌜lambda.thunk_expr t⌝.
23
24 Global Instance lambda_val_lift : Lift lambda.val dynlang.val := λ v,
25 match v with
26 | lambda.VString s => dynlang.VString s
27 | lambda.VClo x E e => dynlang.VClo x ⌜*E⌝ ⌜e⌝
28 end.
29End lambda.
30
31Lemma interp_open_lambda_dynlang E e mv n :
32 lambda.closed_env E → lambda.closed (dom E) e →
33 lambda.interp n E e = Res mv →
34 ∃ m, dynlang.interp m ⌜*E⌝ ⌜e⌝ = Res ⌜*mv⌝.
35Proof.
36 revert E e mv. induction n as [|n IH]; [done|]; intros E e mv HE He Hinterp.
37 rewrite lambda.interp_S in Hinterp. destruct e as [s|z|ex e|e1 e2]; simplify_res.
38 - (* EString *) by exists 1.
39 - (* EId *)
40 apply elem_of_dom in He as [[Et et] Hz]. rewrite Hz /= in Hinterp.
41 apply lambda.closed_env_lookup in Hz as He; last done.
42 rewrite lambda.closed_thunk_eq/= in He. destruct He as [HEtclosed Hetclosed].
43 apply IH in Hinterp as [m Hinterp]; [|done..].
44 exists (S (S m)). rewrite !dynlang.interp_S /= -dynlang.interp_S.
45 rewrite lookup_empty /= right_id_L lookup_fmap Hz /=.
46 eauto using dynlang.interp_le with lia.
47 - (* EAbs *) by exists 2.
48 - (* EApp *)
49 destruct He as [He1 He2].
50 destruct (lambda.interp _ _ e1) as [mw|] eqn:Hinterp1; simplify_res.
51 pose proof Hinterp1 as Hinterp1'.
52 apply lambda.interp_closed in Hinterp1' as Hmw; [|done..].
53 eapply IH in Hinterp1 as [m1 Hinterp1]; [|done..].
54 destruct mw as [w|]; simplify_res; last first.
55 { exists (S m1). by rewrite dynlang.interp_S /= Hinterp1. }
56 destruct (maybe3 lambda.VClo w) eqn:?; simplify_res; last first.
57 { exists (S m1). rewrite dynlang.interp_S /= Hinterp1 /=. by destruct w. }
58 destruct w; simplify_res.
59 apply IH in Hinterp as [m2 Hinterp2].
60 + exists (S (m1 + m2)). rewrite dynlang.interp_S /=.
61 rewrite (dynlang.interp_le Hinterp1) /=; last lia.
62 rewrite fmap_insert /= in Hinterp2.
63 rewrite (dynlang.interp_le Hinterp2) /=; last lia. done.
64 + apply lambda.closed_env_insert; [by split|naive_solver].
65 + rewrite dom_insert_L. set_solver.
66Qed.
67Lemma interp_lambda_dynlang e mv n :
68 lambda.closed ∅ e →
69 lambda.interp n ∅ e = Res mv →
70 ∃ m, dynlang.interp m ∅ ⌜e⌝ = Res ⌜*mv⌝.
71Proof. intro. by apply interp_open_lambda_dynlang. Qed.
72
73Lemma interp_open_dynlang_lambda E e mv n :
74 lambda.closed_env E → lambda.closed (dom E) e →
75 dynlang.interp n ⌜*E⌝ ⌜e⌝ = Res mv →
76 ∃ mw, lambda.interp n E e = Res mw ∧ mv = ⌜*mw⌝.
77Proof.
78 revert E e mv. induction n as [|n IH]; [done|]; intros E e mv HE He Hinterp.
79 rewrite dynlang.interp_S in Hinterp. destruct e as [s|z|ex e|e1 e2]; simplify_res.
80 - (* EString *) rewrite lambda.interp_S /=. by eexists.
81 - (* EId *)
82 destruct n as [|n]; [done|].
83 rewrite dynlang.interp_S /= -dynlang.interp_S in Hinterp.
84 apply elem_of_dom in He as [[Et et] Hz].
85 pose proof (f_equal (fmap lift) Hz) as Hz'.
86 rewrite -lookup_fmap /= in Hz'. rewrite Hz' lookup_empty /= {Hz'} in Hinterp.
87 pose proof Hz as Hz'.
88 apply lambda.closed_env_lookup in Hz' as [HEt Het]; simpl in *; last done.
89 apply IH in Hinterp as (mw & Hinterp & ->); [|done..].
90 exists mw. rewrite lambda.interp_S /= Hz /=. done.
91 - (* EAbs *)
92 destruct n as [|n]; [done|].
93 rewrite dynlang.interp_S /= in Hinterp; simplify_res.
94 rewrite lambda.interp_S /=. by eexists.
95 - (* EApp *)
96 destruct He as [He1 He2].
97 destruct (dynlang.interp _ _ _) as [mw1|] eqn:Hinterp1; simplify_res.
98 eapply IH in Hinterp1 as (mv1 & Hinterp1 & ->); [|done..].
99 destruct mv1 as [v1|]; simplify_res; last first.
100 { exists None. by rewrite lambda.interp_S /= Hinterp1. }
101 destruct (maybe3 dynlang.VClo _) eqn:?; simplify_res; last first.
102 { exists None. rewrite lambda.interp_S /= Hinterp1 /=. by destruct v1. }
103 destruct v1; simplify_res.
104 change (dynlang.Thunk ⌜*E⌝ ⌜e2⌝) with ⌜lambda.Thunk E e2⌝ in Hinterp.
105 rewrite -fmap_insert in Hinterp.
106 apply lambda.interp_closed in Hinterp1 as Hmw; [|done..].
107 apply IH in Hinterp as (mv2 & Hinterp2 & ->).
108 + exists mv2. rewrite lambda.interp_S /= Hinterp1 /=. done.
109 + apply lambda.closed_env_insert; [by split|]. naive_solver.
110 + rewrite dom_insert_L. set_solver.
111Qed.
112Lemma interp_dynlang_lambda e mv n :
113 lambda.closed ∅ e →
114 dynlang.interp n ∅ ⌜e⌝ = Res mv →
115 ∃ mw, lambda.interp n ∅ e = Res mw ∧ mv = ⌜*mw⌝.
116Proof. intros. by apply interp_open_dynlang_lambda. Qed.
117
118(* The following equivalences about the semantics trivially follow: *)
119
120Theorem interp_equiv_ret_string e s :
121 lambda.closed ∅ e →
122 rtc lambda.step e (lambda.EString s)
123 ↔ rtc dynlang.step ⌜e⌝ (dynlang.EString s).
124Proof.
125 intros. rewrite -lambda.interp_sound_complete_ret_string //.
126 rewrite -dynlang.interp_sound_complete_ret_string. split; intros [n Hinterp].
127 + by apply interp_lambda_dynlang in Hinterp.
128 + apply interp_dynlang_lambda in Hinterp as ([[]|] & ?); naive_solver.
129Qed.
130
131Theorem interp_equiv_fail e :
132 lambda.closed ∅ e →
133 (∃ e', rtc lambda.step e e' ∧ lambda.stuck e')
134 ↔ (∃ e', rtc dynlang.step ⌜e⌝ e' ∧ dynlang.stuck e').
135Proof.
136 intros. rewrite -lambda.interp_sound_complete_fail //.
137 rewrite -dynlang.interp_sound_complete_fail. split; intros [n Hinterp].
138 + by apply interp_lambda_dynlang in Hinterp.
139 + apply interp_dynlang_lambda in Hinterp as ([] & ?); naive_solver.
140Qed.
141
142Theorem interp_equiv_no_fuel e :
143 lambda.closed ∅ e →
144 all_loop lambda.step e ↔ all_loop dynlang.step ⌜e⌝.
145Proof.
146 intros He. rewrite -lambda.interp_sound_complete_no_fuel; last done.
147 rewrite -dynlang.interp_sound_complete_no_fuel. split; intros Hnofuel n.
148 - destruct (dynlang.interp n ∅ _) as [mv|] eqn:Hinterp; [|done].
149 apply interp_dynlang_lambda in Hinterp as (? & Hinterp & _); [|done].
150 by rewrite Hnofuel in Hinterp.
151 - destruct (lambda.interp n ∅ _) as [mv|] eqn:Hinterp; [|done].
152 apply interp_lambda_dynlang in Hinterp as [m Hinterp]; [|done..].
153 by rewrite Hnofuel in Hinterp.
154Qed.
diff --git a/theories/dynlang/interp.v b/theories/dynlang/interp.v
new file mode 100644
index 0000000..dcf6b95
--- /dev/null
+++ b/theories/dynlang/interp.v
@@ -0,0 +1,49 @@
1From mininix Require Export res dynlang.operational_props.
2From stdpp Require Import options.
3
4Module Import dynlang.
5Export dynlang.
6
7Inductive thunk := Thunk { thunk_env : gmap string thunk; thunk_expr : expr }.
8Add Printing Constructor thunk.
9Notation env := (gmap string thunk).
10
11Inductive val :=
12 | VString (s : string)
13 | VClo (x : string) (E : env) (e : expr).
14
15Global Instance maybe_VString : Maybe VString := λ v,
16 if v is VString s then Some s else None.
17Global Instance maybe_VClo : Maybe3 VClo := λ v,
18 if v is VClo x E e then Some (x, E, e) else None.
19
20Definition interp1 (interp : env → expr → res val) (E : env) (e : expr) : res val :=
21 match e with
22 | EString s =>
23 mret (VString s)
24 | EId ds e =>
25 v ← interp E e;
26 x ← Res $ maybe VString v;
27 t ← Res $ (E !! x) ∪ (Thunk ∅ <$> ds !! x);
28 interp (thunk_env t) (thunk_expr t)
29 | EAbs ex e =>
30 v ← interp E ex;
31 x ← Res $ maybe VString v;
32 mret (VClo x E e)
33 | EApp e1 e2 =>
34 v1 ← interp E e1;
35 '(x, E', e') ← Res (maybe3 VClo v1);
36 interp (<[x:=Thunk E e2]> E') e'
37 end.
38
39Fixpoint interp (n : nat) (E : env) (e : expr) : res val :=
40 match n with
41 | O => NoFuel
42 | S n => interp1 (interp n) E e
43 end.
44
45Global Opaque interp.
46
47End dynlang.
48
49Add Printing Constructor dynlang.thunk.
diff --git a/theories/dynlang/interp_proofs.v b/theories/dynlang/interp_proofs.v
new file mode 100644
index 0000000..f18a91c
--- /dev/null
+++ b/theories/dynlang/interp_proofs.v
@@ -0,0 +1,426 @@
1From mininix Require Export dynlang.interp.
2From stdpp Require Import options.
3
4Module Import dynlang.
5Export dynlang.
6
7Lemma interp_S n : interp (S n) = interp1 (interp n).
8Proof. done. Qed.
9
10Fixpoint thunk_size (t : thunk) : nat :=
11 S (map_sum_with thunk_size (thunk_env t)).
12Definition env_size (E : env) : nat :=
13 map_sum_with thunk_size E.
14
15Lemma env_ind (P : env → Prop) :
16 (∀ E, map_Forall (λ i, P ∘ thunk_env) E → P E) →
17 ∀ E : env, P E.
18Proof.
19 intros Pbs E.
20 induction (Nat.lt_wf_0_projected env_size E) as [E _ IH].
21 apply Pbs, map_Forall_lookup=> y [E' e'] Hy.
22 apply (map_sum_with_lookup_le thunk_size) in Hy.
23 apply IH. by rewrite -Nat.le_succ_l.
24Qed.
25
26(** Correspondence to operational semantics *)
27Definition subst_env' (thunk_to_expr : thunk → expr) (E : env) : expr → expr :=
28 subst (thunk_to_expr <$> E).
29Fixpoint thunk_to_expr (t : thunk) : expr :=
30 subst_env' thunk_to_expr (thunk_env t) (thunk_expr t).
31Notation subst_env := (subst_env' thunk_to_expr).
32
33Lemma subst_env_eq e E :
34 subst_env E e =
35 match e with
36 | EString s => EString s
37 | EId ds e => EId ((thunk_to_expr <$> E) ∪ ds) (subst_env E e)
38 | EAbs ex e => EAbs (subst_env E ex) (subst_env E e)
39 | EApp e1 e2 => EApp (subst_env E e1) (subst_env E e2)
40 end.
41Proof. by destruct e. Qed.
42
43Lemma subst_env_alt E e : subst_env E e = subst (thunk_to_expr <$> E) e.
44Proof. done. Qed.
45
46(* Use the unfolding lemmas, don't rely on conversion *)
47Opaque subst_env'.
48
49Definition val_to_expr (v : val) : expr :=
50 match v with
51 | VString s => EString s
52 | VClo x E e => EAbs (EString x) (subst_env E e)
53 end.
54
55Lemma val_final v : final (val_to_expr v).
56Proof. by destruct v. Qed.
57
58Lemma subst_empty e : subst ∅ e = e.
59Proof. induction e; f_equal/=; auto. by rewrite left_id_L. Qed.
60
61Lemma subst_env_empty e : subst_env ∅ e = e.
62Proof. rewrite subst_env_alt. apply subst_empty. Qed.
63
64Lemma interp_le {n1 n2 E e mv} :
65 interp n1 E e = Res mv → n1 ≤ n2 → interp n2 E e = Res mv.
66Proof.
67 revert n2 E e mv.
68 induction n1 as [|n1 IH]; intros [|n2] E e mv He ?; [by (done || lia)..|].
69 rewrite interp_S in He; rewrite interp_S; destruct e;
70 repeat match goal with
71 | _ => case_match
72 | H : context [(_ <$> ?mx)] |- _ => destruct mx eqn:?; simplify_res
73 | H : ?r ≫= _ = _ |- _ => destruct r as [[]|] eqn:?; simplify_res
74 | H : _ <$> ?r = _ |- _ => destruct r as [[]|] eqn:?; simplify_res
75 | |- interp ?n ?E ?e ≫= _ = _ => erewrite (IH n E e) by (done || lia)
76 | _ => progress simplify_res
77 | _ => progress simplify_option_eq
78 end; eauto with lia.
79Qed.
80
81Lemma interp_agree {n1 n2 E e mv1 mv2} :
82 interp n1 E e = Res mv1 → interp n2 E e = Res mv2 → mv1 = mv2.
83Proof.
84 intros He1 He2. apply (inj Res). destruct (total (≤) n1 n2).
85 - rewrite -He2. symmetry. eauto using interp_le.
86 - rewrite -He1. eauto using interp_le.
87Qed.
88
89Lemma subst_env_union E1 E2 e :
90 subst_env (E1 ∪ E2) e = subst_env E1 (subst_env E2 e).
91Proof.
92 revert E1 E2. induction e; intros E1 E2; rewrite subst_env_eq /=.
93 - done.
94 - rewrite !(subst_env_eq (EId _ _)) IHe. f_equal.
95 by rewrite assoc_L map_fmap_union.
96 - rewrite !(subst_env_eq (EAbs _ _)) /=. f_equal; auto.
97 - rewrite !(subst_env_eq (EApp _ _)) /=. f_equal; auto.
98Qed.
99
100Lemma subst_env_insert E x e t :
101 subst_env (<[x:=t]> E) e = subst {[x:=thunk_to_expr t]} (subst_env E e).
102Proof.
103 rewrite insert_union_singleton_l subst_env_union subst_env_alt.
104 by rewrite map_fmap_singleton.
105Qed.
106
107Lemma subst_env_insert_eq e1 e2 E1 E2 x E1' E2' e1' e2' :
108 subst_env E1 e1 = subst_env E2 e2 →
109 subst_env E1' e1' = subst_env E2' e2' →
110 subst_env (<[x:=Thunk E1' e1']> E1) e1 = subst_env (<[x:=Thunk E2' e2']> E2) e2.
111Proof. intros He He'. by rewrite !subst_env_insert //= He' He. Qed.
112
113Lemma interp_proper n E1 E2 e1 e2 mv :
114 subst_env E1 e1 = subst_env E2 e2 →
115 interp n E1 e1 = Res mv →
116 ∃ mw m, interp m E2 e2 = Res mw ∧
117 val_to_expr <$> mv = val_to_expr <$> mw.
118Proof.
119 revert n E1 E2 e1 e2 mv. induction n as [|n IHn]; [done|].
120 intros E1 E2 e1 e2 mv Hsubst Hinterp.
121 rewrite 2!subst_env_eq in Hsubst.
122 rewrite interp_S in Hinterp. destruct e1, e2; simplify_res; try done.
123 - eexists (Some (VString _)), 1. by rewrite interp_S.
124 - destruct (interp n _ e1) as [mv1|] eqn:Hinterp'; simplify_eq/=.
125 eapply IHn in Hinterp' as (mw1 & m1 & Hinterp1 & ?); last done.
126 destruct mv1 as [v1|], mw1 as [w1|]; simplify_res; last first.
127 { exists None, (S m1). by rewrite interp_S /= Hinterp1. }
128 destruct (maybe VString v1) as [x|] eqn:Hv1;
129 simplify_res; last first.
130 { exists None, (S m1). split; [|done]. rewrite interp_S /= Hinterp1 /=.
131 destruct v1, w1; repeat destruct select base_lit; by simplify_eq/=. }
132 destruct v1, w1; repeat destruct select base_lit; simplify_eq/=.
133 assert (∀ (ds : stringmap expr) (E : env) x,
134 thunk_to_expr <$> (E !! x) ∪ (Thunk ∅ <$> ds !! x)
135 = ((thunk_to_expr <$> E) ∪ ds) !! x) as HE.
136 { intros ds' E x. rewrite lookup_union lookup_fmap.
137 repeat destruct (_ !! _); f_equal/=; by rewrite subst_env_empty. }
138 pose proof (f_equal (.!! s0) Hsubst) as Hs. rewrite -!HE {HE} in Hs.
139 destruct (E1 !! s0 ∪ _) as [[E1' e1']|],
140 (E2 !! s0 ∪ _) as [[E2' e2']|] eqn:HE2; simplify_res; last first.
141 { exists None, (S m1). rewrite interp_S /= Hinterp1 /=. by rewrite HE2. }
142 eapply IHn in Hinterp as (mw & m2 & Hinterp2 & ?); [|by eauto..].
143 exists mw, (S (m1 `max` m2)). split; [|done]. rewrite interp_S /=.
144 rewrite (interp_le Hinterp1) /=; last lia. rewrite HE2 /=.
145 eauto using interp_le with lia.
146 - destruct (interp n _ _) as [mv1|] eqn:Hinterp'; simplify_eq/=.
147 eapply IHn in Hinterp' as (mw1 & m1 & Hinterp1 & ?); last done.
148 destruct mv1 as [v1|], mw1 as [w1|]; simplify_res; last first.
149 { exists None, (S m1). by rewrite interp_S /= Hinterp1. }
150 destruct (maybe VString _) eqn:Hstring; simplify_res; last first.
151 { exists None, (S m1). rewrite interp_S /= Hinterp1 /=.
152 by assert (maybe VString w1 = None) as -> by (by destruct v1, w1). }
153 destruct v1, w1; simplify_eq/=.
154 eexists (Some (VClo _ _ _)), (S m1).
155 rewrite interp_S /= Hinterp1 /=. split; [done|]. by do 2 f_equal/=.
156 - destruct (interp n _ _) as [mv'|] eqn:Hinterp'; simplify_res.
157 eapply IHn in Hinterp' as (mw' & m1 & Hinterp1 & ?); last done.
158 destruct mv' as [v'|], mw' as [w'|]; simplify_res; last first.
159 { exists None, (S m1). by rewrite interp_S /= Hinterp1. }
160 destruct (maybe3 VClo _) eqn:Hclo; simplify_res; last first.
161 { exists None, (S m1). rewrite interp_S /= Hinterp1 /=.
162 by assert (maybe3 VClo w' = None) as -> by (by destruct v', w'). }
163 destruct v', w'; simplify_eq/=.
164 eapply IHn with (E2 := <[x0:=Thunk E2 e2_2]> E0) in Hinterp
165 as (w & m2 & Hinterp2 & ?); last by apply subst_env_insert_eq.
166 exists w, (S (m1 `max` m2)). rewrite interp_S /=.
167 rewrite (interp_le Hinterp1) /=; last lia.
168 rewrite (interp_le Hinterp2) /=; last lia. done.
169Qed.
170
171Lemma subst_as_subst_env x e1 e2 :
172 subst {[x:=e2]} e1 = subst_env (<[x:=Thunk ∅ e2]> ∅) e1.
173Proof. rewrite subst_env_insert //= !subst_env_empty //. Qed.
174
175Lemma interp_subst n x e1 e2 mv :
176 interp n ∅ (subst {[x:=e2]} e1) = Res mv →
177 ∃ mw m, interp m (<[x:=Thunk ∅ e2]> ∅) e1 = Res mw ∧
178 val_to_expr <$> mv = val_to_expr <$> mw.
179Proof.
180 apply interp_proper.
181 by rewrite subst_env_empty subst_as_subst_env.
182Qed.
183
184Lemma interp_step e1 e2 n mv :
185 e1 --> e2 →
186 interp n ∅ e2 = Res mv →
187 ∃ mw m, interp m ∅ e1 = Res mw ∧ val_to_expr <$> mv = val_to_expr <$> mw.
188Proof.
189 intros Hstep. revert mv n.
190 induction Hstep; intros mv n Hinterp.
191 - apply interp_subst in Hinterp as (w & [|m] & Hinterp & Hv);
192 simplify_eq/=; [|done..].
193 exists w, (S (S (S m))). rewrite !interp_S /= -!interp_S.
194 eauto using interp_le with lia.
195 - exists mv, (S (S n)). rewrite !interp_S /= -interp_S.
196 rewrite lookup_empty left_id_L H /=. eauto using interp_le with lia.
197 - destruct n as [|n]; [done|rewrite interp_S /= in Hinterp].
198 destruct (interp n _ _) as [mv'|] eqn:Hinterp'; simplify_res.
199 apply IHHstep in Hinterp' as (mw' & m1 & Hinterp1 & ?); simplify_res.
200 destruct mv' as [v'|], mw' as [w'|]; simplify_res; last first.
201 { exists None, (S m1). by rewrite interp_S /= Hinterp1. }
202 destruct (maybe VString _) eqn:Hstring; simplify_res; last first.
203 { exists None, (S m1). rewrite interp_S /= Hinterp1 /=.
204 by assert (maybe VString w' = None) as -> by (by destruct v', w'). }
205 destruct v', w'; simplify_eq/=.
206 eexists (Some (VClo _ _ _)), (S m1). rewrite !interp_S /=.
207 rewrite (interp_le Hinterp1) /=; last lia. done.
208 - destruct n as [|n]; [done|rewrite interp_S /= in Hinterp].
209 destruct (interp n _ _) as [mv'|] eqn:Hinterp'; simplify_res.
210 apply IHHstep in Hinterp' as (mw' & m1 & Hinterp1 & ?); simplify_res.
211 destruct mv' as [v'|], mw' as [w'|]; simplify_res; last first.
212 { exists None, (S m1). by rewrite interp_S /= Hinterp1. }
213 destruct (maybe3 VClo _) eqn:Hclo; simplify_res; last first.
214 { exists None, (S m1). rewrite interp_S /= Hinterp1 /=.
215 by assert (maybe3 VClo w' = None) as -> by (by destruct v', w'). }
216 destruct v', w'; simplify_eq/=.
217 eapply interp_proper in Hinterp as (mw & m2 & Hinterp2 & Hv);
218 last apply subst_env_insert_eq; try done.
219 exists mw, (S (m1 `max` m2)). rewrite !interp_S /=.
220 rewrite (interp_le Hinterp1) /=; last lia.
221 by rewrite (interp_le Hinterp2) /=; last lia.
222 - destruct n as [|n]; [done|rewrite interp_S /= in Hinterp].
223 destruct (interp n _ e1') as [mv1|] eqn:Hinterp1; simplify_eq/=.
224 apply IHHstep in Hinterp1 as (mw1 & m & Hinterp1 & Hw1).
225 destruct mv1 as [v1|], mw1 as [w1|]; simplify_res; last first.
226 { exists None, (S m). by rewrite interp_S /= Hinterp1. }
227 exists mv, (S (n `max` m)). split; [|done].
228 rewrite interp_S /= (interp_le Hinterp1) /=; last lia.
229 assert (maybe VString w1 = maybe VString v1) as ->.
230 { destruct v1, w1; naive_solver. }
231 destruct (maybe VString v1); simplify_res; [|done].
232 destruct (_ ∪ _); simplify_res; eauto using interp_le with lia.
233Qed.
234
235Lemma final_interp e :
236 final e →
237 ∃ w m, interp m ∅ e = mret w ∧ e = val_to_expr w.
238Proof.
239 induction e as [| |[]|]; inv 1.
240 - eexists (VString _), 1. by rewrite interp_S /=.
241 - eexists (VClo _ _ _), 2. rewrite interp_S /=. split; [done|].
242 by rewrite subst_env_empty.
243Qed.
244
245Lemma red_final_interp e :
246 red step e ∨ final e ∨ ∃ m, interp m ∅ e = mfail.
247Proof.
248 induction e.
249 - (* ENat *) right; left. constructor.
250 - (* EId *) destruct IHe as [[??]|[Hfinal|[m Hinterp]]].
251 + left. by repeat econstructor.
252 + apply final_interp in Hfinal as (w & m & Hinterp & ->).
253 destruct (maybe VString w) as [x|] eqn:Hw; last first.
254 { do 2 right. eexists (S m). rewrite interp_S /= Hinterp /=.
255 by rewrite Hw. }
256 destruct w; simplify_eq/=.
257 destruct (ds !! x) as [e|] eqn:Hx; last first.
258 { do 2 right. eexists (S m). rewrite interp_S /= Hinterp /=.
259 by rewrite Hx. }
260 left. by repeat econstructor.
261 + do 2 right. exists (S m). rewrite interp_S /= Hinterp. done.
262 - (* EAbs *) destruct IHe1 as [[??]|[Hfinal|[m Hinterp]]].
263 + left. by repeat econstructor.
264 + apply final_interp in Hfinal as (w & m & Hinterp & ->).
265 destruct (maybe VString w) as [x|] eqn:Hw; last first.
266 { do 2 right. eexists (S m). rewrite interp_S /= Hinterp /=.
267 by rewrite Hw. }
268 destruct w; naive_solver.
269 + do 2 right. exists (S m). rewrite interp_S /= Hinterp. done.
270 - (* EApp *) destruct IHe1 as [[??]|[Hfinal|[m Hinterp]]].
271 + left. by repeat econstructor.
272 + apply final_interp in Hfinal as (w & m & Hinterp & ->).
273 destruct (maybe3 VClo w) eqn:Hw.
274 { destruct w; simplify_eq/=. left. by repeat econstructor. }
275 do 2 right. exists (S m). by rewrite interp_S /= Hinterp /= Hw.
276 + do 2 right. exists (S m). by rewrite interp_S /= Hinterp.
277Qed.
278
279Lemma interp_complete e1 e2 :
280 e1 -->* e2 →
281 nf step e2 →
282 ∃ mw m, interp m ∅ e1 = Res mw ∧
283 if mw is Some w then e2 = val_to_expr w else ¬final e2.
284Proof.
285 intros Hsteps Hnf. induction Hsteps as [e|e1 e2 e3 Hstep _ IH].
286 { destruct (red_final_interp e) as [?|[Hfinal|[m Hinterp]]]; [done|..].
287 - apply final_interp in Hfinal as (w & m & ? & ?).
288 by exists (Some w), m.
289 - exists None, m. split; [done|]. intros Hfinal.
290 apply final_interp in Hfinal as (w & m' & ? & _).
291 by assert (mfail = mret w) by eauto using interp_agree. }
292 destruct IH as (mw & m & Hinterp & ?); try done.
293 eapply interp_step in Hinterp as (mw' & m' & ? & ?); last done.
294 destruct mw, mw'; naive_solver.
295Qed.
296
297Lemma interp_complete_ret e1 e2 :
298 e1 -->* e2 → final e2 →
299 ∃ w m, interp m ∅ e1 = mret w ∧ e2 = val_to_expr w.
300Proof.
301 intros Hsteps Hfinal. apply interp_complete in Hsteps
302 as ([w|] & m & ? & ?); naive_solver eauto using final_nf.
303Qed.
304Lemma interp_complete_fail e1 e2 :
305 e1 -->* e2 → nf step e2 → ¬final e2 →
306 ∃ m, interp m ∅ e1 = mfail.
307Proof.
308 intros Hsteps Hnf Hforce.
309 apply interp_complete in Hsteps as ([w|] & m & ? & ?); simplify_eq/=; try by eauto.
310 destruct Hforce. apply val_final.
311Qed.
312
313Lemma interp_sound_open E e n mv :
314 interp n E e = Res mv →
315 ∃ e', subst_env E e -->* e' ∧
316 if mv is Some v then e' = val_to_expr v else stuck e'.
317Proof.
318 revert E e mv.
319 induction n as [|n IH]; intros E e mv Hinterp; first done.
320 rewrite subst_env_eq. rewrite interp_S in Hinterp.
321 destruct e; simplify_res.
322 - (* EString *) by eexists.
323 - (* EId *)
324 destruct (interp _ _ _) as [mv1|] eqn:Hinterp1; simplify_res.
325 apply IH in Hinterp1 as (e1' & Hsteps1 & He1').
326 destruct mv1 as [v1|]; simplify_res; last first.
327 { eexists; split; [by eapply SId_rtc|]. split; [|inv 1].
328 intros [??]. destruct He1' as [Hnf []].
329 inv_step; simpl; eauto. destruct Hnf; eauto. }
330 destruct (maybe VString _) as [x|] eqn:Hv1; simplify_res; last first.
331 { eexists; split; [by eapply SId_rtc|]. split; [|inv 1].
332 intros [??]. destruct v1; inv_step. }
333 destruct v1; simplify_eq/=.
334 assert (thunk_to_expr <$> (E !! x) ∪ (Thunk ∅ <$> ds !! x)
335 = ((thunk_to_expr <$> E) ∪ ds) !! x).
336 { rewrite lookup_union lookup_fmap.
337 repeat destruct (_ !! _); f_equal/=; by rewrite subst_env_empty. }
338 destruct (_ ∪ _) as [[E' e']|] eqn:Hx; simplify_res.
339 * apply IH in Hinterp as (e'' & Hsteps & He'').
340 exists e''; split; [|done]. etrans; [by eapply SId_rtc|].
341 eapply rtc_l; [|done]. by econstructor.
342 * eexists; split; [by eapply SId_rtc|]. split; [|inv 1].
343 intros [? Hstep]. inv_step; simplify_eq/=; congruence.
344 - (* EAbs *)
345 destruct (interp _ _ _) as [mv1|] eqn:Hinterp1; simplify_res.
346 apply IH in Hinterp1 as (e1' & Hsteps1 & He1').
347 destruct mv1 as [v1|]; simplify_res; last first.
348 { eexists; split; [by eapply SAbsL_rtc|]. split.
349 + intros [??]. destruct He1' as [Hnf []].
350 inv_step; simpl; eauto. destruct Hnf; eauto.
351 + intros ?. destruct He1' as [_ []]. by destruct e1'. }
352 eexists; split; [by eapply SAbsL_rtc|].
353 destruct (maybe VString _) as [x|] eqn:Hv1; simplify_res; last first.
354 { split; [|destruct v1; inv 1]. intros [??]. destruct v1; inv_step. }
355 by destruct v1; simplify_eq/=.
356 - (* EApp *) destruct (interp _ _ _) as [mv'|] eqn:Hinterp'; simplify_res.
357 apply IH in Hinterp' as (e' & Hsteps & He'); try done.
358 destruct mv' as [v'|]; simplify_res; last first.
359 { eexists; repeat split; [by apply SAppL_rtc| |inv 1].
360 intros [e'' Hstep]. destruct He' as [Hnf Hfinal].
361 inv Hstep; [by destruct Hfinal; constructor|]. destruct Hnf. eauto. }
362 destruct (maybe3 VClo v') eqn:?; simplify_res; last first.
363 { eexists; repeat split; [by apply SAppL_rtc| |inv 1].
364 intros [e'' Hstep]. inv Hstep; destruct v'; by repeat inv_step. }
365 destruct v'; simplify_res.
366 apply IH in Hinterp as (e'' & Hsteps' & He'').
367 eexists; split; [|done]. etrans; [by apply SAppL_rtc|].
368 eapply rtc_l; first by constructor.
369 rewrite subst_env_insert // in Hsteps'.
370Qed.
371
372Lemma interp_sound n e mv :
373 interp n ∅ e = Res mv →
374 ∃ e', e -->* e' ∧ if mv is Some v then e' = val_to_expr v else stuck e'.
375Proof.
376 intros Hsteps%interp_sound_open; try done.
377 by rewrite subst_env_empty in Hsteps.
378Qed.
379
380(** Final theorems *)
381Theorem interp_sound_complete_ret e v :
382 (∃ w n, interp n ∅ e = mret w ∧ val_to_expr v = val_to_expr w)
383 ↔ e -->* val_to_expr v.
384Proof.
385 split.
386 - by intros (n & w & (e' & ? & ->)%interp_sound & ->).
387 - intros Hsteps. apply interp_complete_ret in Hsteps as ([] & ? & ? & ?);
388 eauto using val_final.
389Qed.
390
391Theorem interp_sound_complete_ret_string e s :
392 (∃ n, interp n ∅ e = mret (VString s)) ↔ e -->* EString s.
393Proof.
394 split.
395 - by intros [n (e' & ? & ->)%interp_sound].
396 - intros Hsteps. apply interp_complete_ret in Hsteps as ([] & ? & ? & ?);
397 simplify_eq/=; eauto.
398Qed.
399
400Theorem interp_sound_complete_fail e :
401 (∃ n, interp n ∅ e = mfail) ↔ ∃ e', e -->* e' ∧ stuck e'.
402Proof.
403 split.
404 - by intros [n ?%interp_sound].
405 - intros (e' & Hsteps & Hnf & Hforced). by eapply interp_complete_fail.
406Qed.
407
408Theorem interp_sound_complete_no_fuel e :
409 (∀ n, interp n ∅ e = NoFuel) ↔ all_loop step e.
410Proof.
411 rewrite all_loop_alt. split.
412 - intros Hnofuel e' Hsteps.
413 destruct (red_final_interp e') as [|[|He']]; [done|..].
414 + apply interp_complete_ret in Hsteps as (w & m & Hinterp & _); last done.
415 by rewrite Hnofuel in Hinterp.
416 + apply interp_sound_complete_fail in He' as (e'' & ? & [Hnf _]).
417 destruct (interp_complete e e'') as (mv & n & Hinterp & _); [by etrans|done|].
418 by rewrite Hnofuel in Hinterp.
419 - intros Hred n. destruct (interp n ∅ e) as [mv|] eqn:Hinterp; [|done].
420 apply interp_sound in Hinterp as (e' & Hsteps%Hred & Hstuck).
421 destruct mv as [v|]; simplify_eq/=.
422 + apply final_nf in Hsteps as []. apply val_final.
423 + by destruct Hstuck as [[] ?].
424Qed.
425
426End dynlang.
diff --git a/theories/dynlang/operational.v b/theories/dynlang/operational.v
new file mode 100644
index 0000000..34cca7b
--- /dev/null
+++ b/theories/dynlang/operational.v
@@ -0,0 +1,41 @@
1From mininix Require Export utils.
2From stdpp Require Import options.
3
4Module Import dynlang.
5
6Inductive expr :=
7 | EString (s : string)
8 | EId (ds : gmap string expr) (ex : expr)
9 | EAbs (ex e : expr)
10 | EApp (e1 e2 : expr).
11
12Fixpoint subst (ds : gmap string expr) (e : expr) : expr :=
13 match e with
14 | EString s => EString s
15 | EId ds' e => EId (ds ∪ ds') (subst ds e)
16 | EAbs ex e => EAbs (subst ds ex) (subst ds e)
17 | EApp e1 e2 => EApp (subst ds e1) (subst ds e2)
18 end.
19
20Reserved Infix "-->" (right associativity, at level 55).
21Inductive step : expr → expr → Prop :=
22 | Sβ x e1 e2 : EApp (EAbs (EString x) e1) e2 --> subst {[x:=e2]} e1
23 | SIdString ds x e : ds !! x = Some e → EId ds (EString x) --> e
24 | SAbsL ex1 ex1' e : ex1 --> ex1' → EAbs ex1 e --> EAbs ex1' e
25 | SAppL e1 e1' e2 : e1 --> e1' → EApp e1 e2 --> EApp e1' e2
26 | SId ds e1 e1' : e1 --> e1' → EId ds e1 --> EId ds e1'
27where "e1 --> e2" := (step e1 e2).
28
29Infix "-->*" := (rtc step) (right associativity, at level 55).
30
31Definition final (e : expr) : Prop :=
32 match e with
33 | EString _ => True
34 | EAbs (EString _) _ => True
35 | _ => False
36 end.
37
38Definition stuck (e : expr) : Prop :=
39 nf step e ∧ ¬final e.
40
41End dynlang.
diff --git a/theories/dynlang/operational_props.v b/theories/dynlang/operational_props.v
new file mode 100644
index 0000000..9e8028c
--- /dev/null
+++ b/theories/dynlang/operational_props.v
@@ -0,0 +1,33 @@
1From mininix Require Export dynlang.operational.
2From stdpp Require Import options.
3
4Module Import dynlang.
5Export dynlang.
6
7(** Properties of operational semantics *)
8Lemma step_not_final e1 e2 : e1 --> e2 → ¬final e1.
9Proof. induction 1; simpl; repeat case_match; naive_solver. Qed.
10Lemma final_nf e : final e → nf step e.
11Proof. by intros ? [??%step_not_final]. Qed.
12
13Lemma SAbsL_rtc ex1 ex1' e : ex1 -->* ex1' → EAbs ex1 e -->* EAbs ex1' e.
14Proof. induction 1; econstructor; eauto using step. Qed.
15Lemma SAppL_rtc e1 e1' e2 : e1 -->* e1' → EApp e1 e2 -->* EApp e1' e2.
16Proof. induction 1; econstructor; eauto using step. Qed.
17Lemma SId_rtc ds e1 e1' : e1 -->* e1' → EId ds e1 -->* EId ds e1'.
18Proof. induction 1; econstructor; eauto using step. Qed.
19
20Ltac inv_step := repeat
21 match goal with H : ?e --> _ |- _ => assert_fails (is_var e); inv H end.
22
23Lemma step_det e d1 d2 :
24 e --> d1 →
25 e --> d2 →
26 d1 = d2.
27Proof.
28 intros Hred1. revert d2.
29 induction Hred1; intros d2 Hred2; inv Hred2; try by inv_step;
30 f_equal; by apply IHHred1.
31Qed.
32
33End dynlang.