diff options
author | Rutger Broekhoff | 2025-07-07 21:52:08 +0200 |
---|---|---|
committer | Rutger Broekhoff | 2025-07-07 21:52:08 +0200 |
commit | ba61dfd69504ec6263a9dee9931d93adeb6f3142 (patch) | |
tree | d6c9b78e50eeab24e0c1c09ab45909a6ae3fd5db /theories/dynlang/equiv.v | |
download | verified-dyn-lang-interp-ba61dfd69504ec6263a9dee9931d93adeb6f3142.tar.gz verified-dyn-lang-interp-ba61dfd69504ec6263a9dee9931d93adeb6f3142.zip |
Initialize repository
Diffstat (limited to 'theories/dynlang/equiv.v')
-rw-r--r-- | theories/dynlang/equiv.v | 154 |
1 files changed, 154 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 @@ | |||
1 | From mininix Require Export lambda.interp_proofs dynlang.interp_proofs. | ||
2 | From stdpp Require Import options. | ||
3 | |||
4 | Class Lift A B := lift : A → B. | ||
5 | Global Hint Mode Lift ! - : typeclass_instances. | ||
6 | Arguments lift {_ _ _} !_ /. | ||
7 | Notation "⌜ x ⌝" := (lift x) (at level 0). | ||
8 | Notation "⌜* x ⌝" := (fmap lift x) (at level 0). | ||
9 | |||
10 | Module 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. | ||
29 | End lambda. | ||
30 | |||
31 | Lemma 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⌝. | ||
35 | Proof. | ||
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. | ||
66 | Qed. | ||
67 | Lemma 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⌝. | ||
71 | Proof. intro. by apply interp_open_lambda_dynlang. Qed. | ||
72 | |||
73 | Lemma 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⌝. | ||
77 | Proof. | ||
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. | ||
111 | Qed. | ||
112 | Lemma 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⌝. | ||
116 | Proof. intros. by apply interp_open_dynlang_lambda. Qed. | ||
117 | |||
118 | (* The following equivalences about the semantics trivially follow: *) | ||
119 | |||
120 | Theorem 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). | ||
124 | Proof. | ||
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. | ||
129 | Qed. | ||
130 | |||
131 | Theorem 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'). | ||
135 | Proof. | ||
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. | ||
140 | Qed. | ||
141 | |||
142 | Theorem interp_equiv_no_fuel e : | ||
143 | lambda.closed ∅ e → | ||
144 | all_loop lambda.step e ↔ all_loop dynlang.step ⌜e⌝. | ||
145 | Proof. | ||
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. | ||
154 | Qed. | ||