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/lambda | |
| download | verified-dyn-lang-interp-ba61dfd69504ec6263a9dee9931d93adeb6f3142.tar.gz verified-dyn-lang-interp-ba61dfd69504ec6263a9dee9931d93adeb6f3142.zip | |
Initialize repository
Diffstat (limited to 'theories/lambda')
| -rw-r--r-- | theories/lambda/interp.v | 44 | ||||
| -rw-r--r-- | theories/lambda/interp_proofs.v | 614 | ||||
| -rw-r--r-- | theories/lambda/operational.v | 38 | ||||
| -rw-r--r-- | theories/lambda/operational_props.v | 29 |
4 files changed, 725 insertions, 0 deletions
diff --git a/theories/lambda/interp.v b/theories/lambda/interp.v new file mode 100644 index 0000000..5bc60d1 --- /dev/null +++ b/theories/lambda/interp.v | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | From mininix Require Export res lambda.operational_props. | ||
| 2 | From stdpp Require Import options. | ||
| 3 | |||
| 4 | Module Import lambda. | ||
| 5 | Export lambda. | ||
| 6 | |||
| 7 | Inductive thunk := | ||
| 8 | Thunk { thunk_env : gmap string thunk; thunk_expr : expr }. | ||
| 9 | Add Printing Constructor thunk. | ||
| 10 | Notation env := (gmap string thunk). | ||
| 11 | |||
| 12 | Inductive val := | ||
| 13 | | VString (s : string) | ||
| 14 | | VClo (x : string) (E : env) (e : expr). | ||
| 15 | |||
| 16 | Global Instance maybe_VClo : Maybe3 VClo := λ v, | ||
| 17 | if v is VClo x E e then Some (x, E, e) else None. | ||
| 18 | |||
| 19 | Definition interp1 (interp : env → expr → res val) (E : env) (e : expr) : res val := | ||
| 20 | match e with | ||
| 21 | | EString s => | ||
| 22 | mret (VString s) | ||
| 23 | | EId x => | ||
| 24 | t ← Res (E !! x); | ||
| 25 | interp (thunk_env t) (thunk_expr t) | ||
| 26 | | EAbs x e => | ||
| 27 | mret (VClo x E e) | ||
| 28 | | EApp e1 e2 => | ||
| 29 | v1 ← interp E e1; | ||
| 30 | '(x, E', e') ← Res (maybe3 VClo v1); | ||
| 31 | interp (<[x:=Thunk E e2]> E') e' | ||
| 32 | end. | ||
| 33 | |||
| 34 | Fixpoint interp (n : nat) (E : env) (e : expr) : res val := | ||
| 35 | match n with | ||
| 36 | | O => NoFuel | ||
| 37 | | S n => interp1 (interp n) E e | ||
| 38 | end. | ||
| 39 | |||
| 40 | Global Opaque interp. | ||
| 41 | |||
| 42 | End lambda. | ||
| 43 | |||
| 44 | Add Printing Constructor lambda.thunk. | ||
diff --git a/theories/lambda/interp_proofs.v b/theories/lambda/interp_proofs.v new file mode 100644 index 0000000..efd0982 --- /dev/null +++ b/theories/lambda/interp_proofs.v | |||
| @@ -0,0 +1,614 @@ | |||
| 1 | From mininix Require Export lambda.interp. | ||
| 2 | From stdpp Require Import options. | ||
| 3 | |||
| 4 | Module Import lambda. | ||
| 5 | Export lambda. | ||
| 6 | |||
| 7 | Lemma interp_S n : interp (S n) = interp1 (interp n). | ||
| 8 | Proof. done. Qed. | ||
| 9 | |||
| 10 | Fixpoint thunk_size (t : thunk) : nat := | ||
| 11 | S (map_sum_with thunk_size (thunk_env t)). | ||
| 12 | Definition env_size (E : env) : nat := | ||
| 13 | map_sum_with thunk_size E. | ||
| 14 | |||
| 15 | Lemma env_ind (P : env → Prop) : | ||
| 16 | (∀ E, map_Forall (λ i, P ∘ thunk_env) E → P E) → | ||
| 17 | ∀ E : env, P E. | ||
| 18 | Proof. | ||
| 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. | ||
| 24 | Qed. | ||
| 25 | |||
| 26 | (** Correspondence to operational semantics *) | ||
| 27 | Definition subst_env' (thunk_to_expr : thunk → expr) (E : env) : expr → expr := | ||
| 28 | subst (thunk_to_expr <$> E). | ||
| 29 | Fixpoint thunk_to_expr (t : thunk) : expr := | ||
| 30 | subst_env' thunk_to_expr (thunk_env t) (thunk_expr t). | ||
| 31 | Notation subst_env := (subst_env' thunk_to_expr). | ||
| 32 | |||
| 33 | Lemma subst_env_eq e E : | ||
| 34 | subst_env E e = | ||
| 35 | match e with | ||
| 36 | | EString s => EString s | ||
| 37 | | EId x => if E !! x is Some t then thunk_to_expr t else EId x | ||
| 38 | | EAbs x e => EAbs x (subst_env (delete x E) e) | ||
| 39 | | EApp e1 e2 => EApp (subst_env E e1) (subst_env E e2) | ||
| 40 | end. | ||
| 41 | Proof. | ||
| 42 | rewrite /subst_env. destruct e; simpl; try done. | ||
| 43 | - rewrite lookup_fmap. by destruct (E !! x) as [[]|]. | ||
| 44 | - by rewrite fmap_delete. | ||
| 45 | Qed. | ||
| 46 | Lemma subst_env_id x E : | ||
| 47 | subst_env E (EId x) = if E !! x is Some t then thunk_to_expr t else EId x. | ||
| 48 | Proof. by rewrite subst_env_eq. Qed. | ||
| 49 | |||
| 50 | Lemma subst_env_alt E e : subst_env E e = subst (thunk_to_expr <$> E) e. | ||
| 51 | Proof. done. Qed. | ||
| 52 | |||
| 53 | (* Use the unfolding lemmas, don't rely on conversion *) | ||
| 54 | Opaque subst_env'. | ||
| 55 | |||
| 56 | Definition val_to_expr (v : val) : expr := | ||
| 57 | match v with | ||
| 58 | | VString s => EString s | ||
| 59 | | VClo x E e => EAbs x (subst_env (delete x E) e) | ||
| 60 | end. | ||
| 61 | |||
| 62 | Lemma final_val_to_expr v : final (val_to_expr v). | ||
| 63 | Proof. by destruct v. Qed. | ||
| 64 | Lemma step_not_val_to_expr v e : val_to_expr v --> e → False. | ||
| 65 | Proof. intros []%step_not_final. apply final_val_to_expr. Qed. | ||
| 66 | |||
| 67 | Lemma subst_empty e : subst ∅ e = e. | ||
| 68 | Proof. induction e; f_equal/=; auto. Qed. | ||
| 69 | |||
| 70 | Lemma subst_env_empty e : subst_env ∅ e = e. | ||
| 71 | Proof. rewrite subst_env_alt. apply subst_empty. Qed. | ||
| 72 | |||
| 73 | Lemma interp_le {n1 n2 E e mv} : | ||
| 74 | interp n1 E e = Res mv → n1 ≤ n2 → interp n2 E e = Res mv. | ||
| 75 | Proof. | ||
| 76 | revert n2 E e mv. | ||
| 77 | induction n1 as [|n1 IH]; intros [|n2] E e mv He ?; [by (done || lia)..|]. | ||
| 78 | rewrite interp_S in He; rewrite interp_S; destruct e; | ||
| 79 | repeat match goal with | ||
| 80 | | _ => case_match | ||
| 81 | | H : context [(_ <$> ?mx)] |- _ => destruct mx eqn:?; simplify_res | ||
| 82 | | H : ?r ≫= _ = _ |- _ => destruct r as [[]|] eqn:?; simplify_res | ||
| 83 | | H : _ <$> ?r = _ |- _ => destruct r as [[]|] eqn:?; simplify_res | ||
| 84 | | |- interp ?n ?E ?e ≫= _ = _ => erewrite (IH n E e) by (done || lia) | ||
| 85 | | _ => progress simplify_res | ||
| 86 | | _ => progress simplify_option_eq | ||
| 87 | end; eauto with lia. | ||
| 88 | Qed. | ||
| 89 | |||
| 90 | Lemma interp_agree {n1 n2 E e mv1 mv2} : | ||
| 91 | interp n1 E e = Res mv1 → interp n2 E e = Res mv2 → mv1 = mv2. | ||
| 92 | Proof. | ||
| 93 | intros He1 He2. apply (inj Res). destruct (total (≤) n1 n2). | ||
| 94 | - rewrite -He2. symmetry. eauto using interp_le. | ||
| 95 | - rewrite -He1. eauto using interp_le. | ||
| 96 | Qed. | ||
| 97 | |||
| 98 | Definition is_not_id (e : expr) : Prop := | ||
| 99 | match e with EId _ => False | _ => True end. | ||
| 100 | |||
| 101 | Lemma id_or_not e : (∃ x, e = EId x) ∨ is_not_id e. | ||
| 102 | Proof. destruct e; naive_solver. Qed. | ||
| 103 | |||
| 104 | Lemma interp_not_id n E e v : | ||
| 105 | interp n E e = mret v → is_not_id (subst_env E e). | ||
| 106 | Proof. | ||
| 107 | revert E e v. induction n as [|n IH]; intros E e v; [done|]. | ||
| 108 | rewrite interp_S. destruct e; simpl; try done. | ||
| 109 | rewrite subst_env_id. destruct (_ !! _) as [[[]]|]; naive_solver. | ||
| 110 | Qed. | ||
| 111 | |||
| 112 | Fixpoint closed (X : stringset) (e : expr) : Prop := | ||
| 113 | match e with | ||
| 114 | | EString _ => True | ||
| 115 | | EId x => x ∈ X | ||
| 116 | | EAbs x e => closed ({[ x ]} ∪ X) e | ||
| 117 | | EApp e1 e2 => closed X e1 ∧ closed X e2 | ||
| 118 | end. | ||
| 119 | |||
| 120 | Inductive closed_thunk (t : thunk) : Prop := { | ||
| 121 | closed_thunk_env : map_Forall (λ _, closed_thunk) (thunk_env t); | ||
| 122 | closed_thunk_expr : closed (dom (thunk_env t)) (thunk_expr t); | ||
| 123 | }. | ||
| 124 | Notation closed_env := (map_Forall (M:=env) (λ _, closed_thunk)). | ||
| 125 | |||
| 126 | Definition closed_val (v : val) : Prop := | ||
| 127 | match v with | ||
| 128 | | VString _ => True | ||
| 129 | | VClo x E e => closed_env E ∧ closed ({[x]} ∪ dom E) e | ||
| 130 | end. | ||
| 131 | |||
| 132 | Lemma closed_thunk_eq E e : | ||
| 133 | closed_thunk (Thunk E e) ↔ closed_env E ∧ closed (dom E) e. | ||
| 134 | Proof. split; inv 1; constructor; done. Qed. | ||
| 135 | |||
| 136 | Lemma closed_env_delete x E : closed_env E → closed_env (delete x E). | ||
| 137 | Proof. apply map_Forall_delete. Qed. | ||
| 138 | |||
| 139 | Lemma closed_env_insert x t E : | ||
| 140 | closed_thunk t → closed_env E → closed_env (<[x:=t]> E). | ||
| 141 | Proof. apply: map_Forall_insert_2. Qed. | ||
| 142 | |||
| 143 | Lemma closed_env_lookup E x t : | ||
| 144 | closed_env E → E !! x = Some t → closed_thunk t. | ||
| 145 | Proof. apply map_Forall_lookup_1. Qed. | ||
| 146 | |||
| 147 | Lemma closed_subst E ds e : | ||
| 148 | dom ds ## E → closed E e → subst ds e = e. | ||
| 149 | Proof. | ||
| 150 | revert E ds. | ||
| 151 | induction e; intros E ds Hdisj Heclosed; simplify_eq/=; first done. | ||
| 152 | - assert (Hxds : x ∉ dom ds) by set_solver. | ||
| 153 | by rewrite (not_elem_of_dom_1 _ _ Hxds). | ||
| 154 | - f_equal. by apply IHe with (E := {[x]} ∪ E); first set_solver. | ||
| 155 | - f_equal; naive_solver. | ||
| 156 | Qed. | ||
| 157 | |||
| 158 | Lemma closed_weaken X Y e : closed X e → X ⊆ Y → closed Y e. | ||
| 159 | Proof. revert X Y; induction e; naive_solver eauto with set_solver. Qed. | ||
| 160 | |||
| 161 | Lemma subst_closed ds X e : | ||
| 162 | map_Forall (λ _, closed ∅) ds → | ||
| 163 | closed (dom ds ∪ X) e → | ||
| 164 | closed X (subst ds e). | ||
| 165 | Proof. | ||
| 166 | revert X ds. induction e; intros X ds; repeat (case_decide || simplify_eq/=). | ||
| 167 | - done. | ||
| 168 | - intros. case_match. | ||
| 169 | + apply H in H1. by eapply closed_weaken. | ||
| 170 | + apply not_elem_of_dom in H1. set_solver. | ||
| 171 | - intros. apply IHe. | ||
| 172 | + by apply map_Forall_delete. | ||
| 173 | + by rewrite dom_delete_L assoc_L difference_union_L | ||
| 174 | [dom _ ∪ _]comm_L -assoc_L. | ||
| 175 | - naive_solver. | ||
| 176 | Qed. | ||
| 177 | |||
| 178 | Lemma subst_env_delete_closed E X e x : | ||
| 179 | closed_env E → | ||
| 180 | closed ({[x]} ∪ X) (subst_env E e) → | ||
| 181 | closed ({[x]} ∪ X) (subst_env (delete x E) e). | ||
| 182 | Proof. | ||
| 183 | revert E X x. | ||
| 184 | induction e as [s | z | z e IHe | e1 IHe1 e2 IHe2]; intros E X x. | ||
| 185 | - rewrite !subst_env_eq //. | ||
| 186 | - rewrite !subst_env_eq /=. case_match. | ||
| 187 | + destruct (decide (x = z)) as [->|?]. | ||
| 188 | * rewrite lookup_delete. set_solver. | ||
| 189 | * rewrite lookup_delete_ne // H //. | ||
| 190 | + destruct (decide (x = z)) as [->|?]. | ||
| 191 | * rewrite delete_notin // H //. | ||
| 192 | * rewrite lookup_delete_ne // H //. | ||
| 193 | - intros HE. | ||
| 194 | rewrite [subst_env (delete _ _) _]subst_env_eq subst_env_eq /= | ||
| 195 | delete_commute comm_L -assoc_L. | ||
| 196 | by apply IHe, map_Forall_delete. | ||
| 197 | - rewrite [subst_env (delete _ _) _]subst_env_eq subst_env_eq /=. | ||
| 198 | naive_solver. | ||
| 199 | Qed. | ||
| 200 | |||
| 201 | Lemma subst_env_closed E X e : | ||
| 202 | closed_env E → closed (dom E ∪ X) e → closed X (subst_env E e). | ||
| 203 | Proof. | ||
| 204 | revert e X. induction E using env_ind. | ||
| 205 | induction e; intros X Hcenv Hclosed; simplify_eq/=. | ||
| 206 | - done. | ||
| 207 | - rewrite subst_env_eq. case_match. | ||
| 208 | + destruct t as [Et et]; simpl. | ||
| 209 | apply closed_env_lookup in H0 as Htclosed; last done. | ||
| 210 | apply closed_thunk_eq in Htclosed as [HEtclosed Hetclosed]. | ||
| 211 | apply (H _ _ H0); simpl. | ||
| 212 | * exact HEtclosed. | ||
| 213 | * eapply closed_weaken; set_solver. | ||
| 214 | + simpl in *. apply not_elem_of_dom in H0. set_solver. | ||
| 215 | - rewrite subst_env_eq. simpl in *. | ||
| 216 | rewrite comm_L -assoc_L in Hclosed. | ||
| 217 | apply IHe in Hclosed; last exact Hcenv. | ||
| 218 | apply subst_env_delete_closed; first done. | ||
| 219 | by rewrite comm_L. | ||
| 220 | - rewrite subst_env_eq. naive_solver. | ||
| 221 | Qed. | ||
| 222 | |||
| 223 | Lemma thunk_to_expr_closed t : closed_thunk t → closed ∅ (thunk_to_expr t). | ||
| 224 | Proof. | ||
| 225 | destruct t as [E e]. intros [HEclosed Heclosed]%closed_thunk_eq. | ||
| 226 | by apply subst_env_closed; last rewrite union_empty_r_L. | ||
| 227 | Qed. | ||
| 228 | |||
| 229 | Lemma subst_env_insert E x e t : | ||
| 230 | closed_env E → | ||
| 231 | subst_env (<[x:=t]> E) e | ||
| 232 | = subst {[x:=thunk_to_expr t]} (subst_env (delete x E) e). | ||
| 233 | Proof. | ||
| 234 | revert E. induction e; intros E HEclosed; simpl. | ||
| 235 | - done. | ||
| 236 | - destruct (decide (x = x0)) as [->|?]. | ||
| 237 | + rewrite subst_env_eq lookup_insert subst_env_id | ||
| 238 | lookup_delete /= lookup_singleton. done. | ||
| 239 | + rewrite subst_env_eq lookup_insert_ne // subst_env_id. | ||
| 240 | destruct (E !! x0) eqn:Elookup. | ||
| 241 | * apply closed_env_lookup in Elookup as Hc0closed; last done. | ||
| 242 | apply thunk_to_expr_closed in Hc0closed. | ||
| 243 | rewrite lookup_delete_ne // Elookup. | ||
| 244 | by erewrite closed_subst with (E := ∅). | ||
| 245 | * by rewrite lookup_delete_ne // Elookup /= lookup_singleton_ne. | ||
| 246 | - rewrite (subst_env_eq (EAbs x0 e)) (subst_env_eq (EAbs _ _)) /=. f_equal. | ||
| 247 | destruct (decide (x0 = x)) as [->|?]. | ||
| 248 | + by rewrite delete_insert_delete delete_idemp | ||
| 249 | delete_singleton subst_empty. | ||
| 250 | + rewrite delete_insert_ne // delete_singleton_ne // delete_commute. | ||
| 251 | apply IHe. by apply closed_env_delete. | ||
| 252 | - rewrite (subst_env_eq (EApp _ _)) [subst_env (delete x E) _]subst_env_eq /=. | ||
| 253 | f_equal; auto. | ||
| 254 | Qed. | ||
| 255 | |||
| 256 | Lemma subst_env_insert_eq e1 e2 E1 E2 x E1' E2' e1' e2' : | ||
| 257 | closed_env E1 → closed_env E2 → | ||
| 258 | subst_env (delete x E1) e1 = subst_env (delete x E2) e2 → | ||
| 259 | subst_env E1' e1' = subst_env E2' e2' → | ||
| 260 | subst_env (<[x:=Thunk E1' e1']> E1) e1 | ||
| 261 | = subst_env (<[x:=Thunk E2' e2']> E2) e2. | ||
| 262 | Proof. | ||
| 263 | intros HE1closed HE2closed He' He. | ||
| 264 | rewrite !subst_env_insert //=. by rewrite He' He. | ||
| 265 | Qed. | ||
| 266 | |||
| 267 | Lemma interp_closed n E e mv : | ||
| 268 | closed_env E → closed (dom E) e → interp n E e = Res mv → | ||
| 269 | if mv is Some v then closed_val v else True. | ||
| 270 | Proof. | ||
| 271 | revert E e mv. | ||
| 272 | induction n; first done; intros E e mv HEclosed Heclosed Hinterp. | ||
| 273 | destruct e. | ||
| 274 | - rewrite interp_S /= in Hinterp. by destruct mv; simplify_res. | ||
| 275 | - rewrite interp_S /= in Hinterp. simplify_option_eq. | ||
| 276 | destruct (E !! x) eqn:Hlookup; simplify_res; try done. | ||
| 277 | apply closed_env_lookup in Hlookup; last assumption. | ||
| 278 | destruct t as [E' e']. apply closed_thunk_eq in Hlookup as [Henv Hexpr]. | ||
| 279 | by apply IHn with (E := E') (e := e'). | ||
| 280 | - rewrite interp_S /= in Hinterp. simplify_option_eq. | ||
| 281 | destruct mv as [v|]; simplify_res. split_and!. | ||
| 282 | + set_solver. | ||
| 283 | + done. | ||
| 284 | - rewrite interp_S /= in Hinterp. simplify_option_eq. | ||
| 285 | destruct Heclosed as [He1closed He2closed]. | ||
| 286 | destruct (interp n E e1) as [[[]|]|] eqn:Einterp; simplify_res; try done. | ||
| 287 | apply IHn in Einterp; try done. | ||
| 288 | simpl in Einterp. destruct Einterp as [Hinterp1 Hinterp2]. | ||
| 289 | apply IHn in Hinterp; first done. | ||
| 290 | + rewrite <-insert_delete_insert. | ||
| 291 | apply map_Forall_insert; first apply lookup_delete. split. | ||
| 292 | * by split. | ||
| 293 | * by apply closed_env_delete. | ||
| 294 | + by rewrite dom_insert_L. | ||
| 295 | Qed. | ||
| 296 | |||
| 297 | Lemma interp_proper n E1 E2 e1 e2 mv : | ||
| 298 | closed_env E1 → closed_env E2 → | ||
| 299 | closed (dom E1) e1 → closed (dom E2) e2 → | ||
| 300 | subst_env E1 e1 = subst_env E2 e2 → | ||
| 301 | interp n E1 e1 = Res mv → | ||
| 302 | ∃ mw m, interp m E2 e2 = Res mw ∧ | ||
| 303 | val_to_expr <$> mv = val_to_expr <$> mw. | ||
| 304 | Proof. | ||
| 305 | revert n E2 E1 e1 e2 mv. induction n as [|n IHn]; [done|]. | ||
| 306 | intros E2. induction E2 as [E2 IH] using env_ind. | ||
| 307 | intros E1 e1 e2 mv HE1closed HE2closed He1closed He2closed Hsubst Hinterp. | ||
| 308 | destruct (id_or_not e1) as [[x ->]|?]. | ||
| 309 | { rewrite interp_S /= in Hinterp. | ||
| 310 | destruct (E1 !! x) as [[E' e']|] eqn:Hx; simplify_eq/=; | ||
| 311 | last by apply not_elem_of_dom in Hx. | ||
| 312 | rewrite subst_env_id Hx in Hsubst. | ||
| 313 | apply closed_env_lookup in Hx; last done. | ||
| 314 | rewrite closed_thunk_eq in Hx. | ||
| 315 | destruct Hx as [HE'close He'closed]. | ||
| 316 | eauto. } | ||
| 317 | destruct (id_or_not e2) as [[x ->]|?]. | ||
| 318 | { rewrite subst_env_id in Hsubst. | ||
| 319 | destruct (E2 !! x) as [[E' e']|] eqn:Hx; simplify_eq/=. | ||
| 320 | - apply closed_env_lookup in Hx as Hclosed; last done. | ||
| 321 | rewrite closed_thunk_eq in Hclosed. | ||
| 322 | destruct Hclosed as [HE'closed He'closed]. | ||
| 323 | rewrite map_Forall_lookup in IH. | ||
| 324 | odestruct (IH _ _ Hx) as (w & m & Hinterp' & Hw); | ||
| 325 | first apply HE1closed; try done. | ||
| 326 | exists w, (S m). by rewrite interp_S /= Hx /=. | ||
| 327 | - destruct mv as [v|]. | ||
| 328 | + apply interp_not_id in Hinterp. by rewrite Hsubst in Hinterp. | ||
| 329 | + exists None, 1. by rewrite interp_S /= Hx. } | ||
| 330 | rewrite (subst_env_eq e1) (subst_env_eq e2) in Hsubst. | ||
| 331 | rewrite interp_S in Hinterp. destruct e1, e2; simplify_res; try done. | ||
| 332 | - eexists (Some (VString _)), 1. by rewrite interp_S. | ||
| 333 | - eexists (Some (VClo _ _ _)), 1. split; first by rewrite interp_S. | ||
| 334 | by do 2 f_equal/=. | ||
| 335 | - destruct (interp n _ _) as [mv'|] eqn:Hinterp'; simplify_res. | ||
| 336 | destruct He1closed as [He1_1closed He1_2closed], | ||
| 337 | He2closed as [He2_1closed He2_2closed]. | ||
| 338 | apply interp_closed in Hinterp' as Hclosed; [|done..]. | ||
| 339 | eapply IHn with (e2 := e2_1) in Hinterp' as (mw' & m1 & Hinterp1 & ?); | ||
| 340 | try done. | ||
| 341 | destruct mv' as [v'|], mw' as [w'|]; simplify_res; last first. | ||
| 342 | { exists None, (S m1). by rewrite interp_S /= Hinterp1. } | ||
| 343 | destruct (maybe3 VClo _) eqn:Hclo; simplify_res; last first. | ||
| 344 | { exists None, (S m1). rewrite interp_S /= Hinterp1 /=. | ||
| 345 | by assert (maybe3 VClo w' = None) as -> by (by destruct v', w'). } | ||
| 346 | destruct v', w'; simplify_eq/=. | ||
| 347 | eapply IHn with (E2 := <[x0:=Thunk E2 e2_2]> E0) in Hinterp | ||
| 348 | as (w & m2 & Hinterp2 & ?). | ||
| 349 | + exists w, (S (m1 `max` m2)). rewrite interp_S /=. | ||
| 350 | rewrite (interp_le Hinterp1) /=; last lia. | ||
| 351 | rewrite (interp_le Hinterp2) /=; last lia. done. | ||
| 352 | + rewrite -insert_delete_insert. | ||
| 353 | apply map_Forall_insert; first apply lookup_delete. | ||
| 354 | split; first done. apply closed_env_delete. naive_solver. | ||
| 355 | + apply interp_closed in Hinterp1; [|done..]. | ||
| 356 | rewrite /closed_val in Hinterp1. destruct Hinterp1 as [??]. | ||
| 357 | by apply map_Forall_insert_2. | ||
| 358 | + rewrite dom_insert_L. naive_solver. | ||
| 359 | + rewrite dom_insert_L. | ||
| 360 | apply interp_closed in Hinterp1; [|done..]. | ||
| 361 | rewrite /closed_val in Hinterp1. by destruct Hinterp1 as [_ ?]. | ||
| 362 | + apply interp_closed in Hinterp1; [|done..]. | ||
| 363 | rewrite /closed_val in Hinterp1. destruct Hinterp1 as [? _]. | ||
| 364 | apply subst_env_insert_eq; try naive_solver. | ||
| 365 | Qed. | ||
| 366 | |||
| 367 | Lemma subst_as_subst_env x e1 e2 : | ||
| 368 | subst {[x:=e2]} e1 = subst_env (<[x:=Thunk ∅ e2]> ∅) e1. | ||
| 369 | Proof. rewrite subst_env_insert //= !subst_env_empty //. Qed. | ||
| 370 | |||
| 371 | Lemma interp_subst n x e1 e2 mv : | ||
| 372 | closed {[x]} e1 → closed ∅ e2 → | ||
| 373 | interp n ∅ (subst {[x:=e2]} e1) = Res mv → | ||
| 374 | ∃ mw m, interp m (<[x:=Thunk ∅ e2]> ∅) e1 = Res mw ∧ | ||
| 375 | val_to_expr <$> mv = val_to_expr <$> mw. | ||
| 376 | Proof. | ||
| 377 | intros He1 He2. | ||
| 378 | apply interp_proper. | ||
| 379 | - done. | ||
| 380 | - by apply closed_env_insert. | ||
| 381 | - apply subst_closed. | ||
| 382 | + by apply map_Forall_singleton. | ||
| 383 | + by rewrite dom_singleton_L dom_empty_L union_empty_r_L. | ||
| 384 | - by rewrite insert_empty dom_singleton_L. | ||
| 385 | - by rewrite subst_env_empty subst_as_subst_env. | ||
| 386 | Qed. | ||
| 387 | |||
| 388 | Lemma closed_step e1 e2 : closed ∅ e1 → e1 --> e2 → closed ∅ e2. | ||
| 389 | Proof. | ||
| 390 | intros Hclosed Hstep. revert Hclosed. | ||
| 391 | induction Hstep; intros He1closed. | ||
| 392 | - simplify_eq/=. destruct He1closed. | ||
| 393 | apply subst_closed. | ||
| 394 | + by eapply map_Forall_singleton. | ||
| 395 | + by rewrite dom_singleton_L. | ||
| 396 | - simplify_eq/=. destruct He1closed. auto. | ||
| 397 | Qed. | ||
| 398 | |||
| 399 | Lemma closed_steps e1 e2 : closed ∅ e1 → e1 -->* e2 → closed ∅ e2. | ||
| 400 | Proof. induction 2; eauto using closed_step. Qed. | ||
| 401 | |||
| 402 | Lemma interp_step e1 e2 n v : | ||
| 403 | closed ∅ e1 → | ||
| 404 | e1 --> e2 → | ||
| 405 | interp n ∅ e2 = Res v → | ||
| 406 | ∃ w m, interp m ∅ e1 = Res w ∧ val_to_expr <$> v = val_to_expr <$> w. | ||
| 407 | Proof. | ||
| 408 | intros He1closed Hstep. revert v n He1closed. | ||
| 409 | induction Hstep as [|???? IH]; intros v n He1closed Hinterp. | ||
| 410 | { rewrite /= union_empty_r_L in He1closed. | ||
| 411 | destruct He1closed as [He1closed He2closed]. | ||
| 412 | apply interp_subst in Hinterp as (w & [|m] & Hinterp & Hv); | ||
| 413 | simplify_eq/=; [|done..]. | ||
| 414 | exists w, (S (S m)). by rewrite !interp_S /= -interp_S. } | ||
| 415 | simpl in He1closed. destruct He1closed as [He1closed He2closed]. | ||
| 416 | destruct n as [|n]; [done|rewrite interp_S /= in Hinterp]. | ||
| 417 | destruct (interp n _ _) eqn:Hinterp'; simplify_res. | ||
| 418 | destruct x; simplify_res; last first. | ||
| 419 | { apply IH in Hinterp' as (mw' & m1 & Hinterp1 & ?); simplify_res; last done. | ||
| 420 | destruct mw'; try done. exists None, (S m1). | ||
| 421 | by rewrite interp_S /= Hinterp1. } | ||
| 422 | apply closed_step in Hstep as He1'closed; last done. | ||
| 423 | apply interp_closed in Hinterp' as Hcloclosed; | ||
| 424 | [|done|by rewrite dom_empty_L]. | ||
| 425 | apply IH in Hinterp' as ([] & m1 & Hinterp1 & ?); simplify_eq/=; last done. | ||
| 426 | destruct (maybe3 VClo _) eqn:Hclo; simplify_res; last first. | ||
| 427 | { exists None, (S m1). rewrite interp_S /= Hinterp1 /=. | ||
| 428 | by assert (maybe3 VClo v1 = None) as -> by (by destruct v1, v0). } | ||
| 429 | simplify_option_eq. | ||
| 430 | simpl in Hcloclosed. destruct Hcloclosed as [HEclosed Heclosed]. | ||
| 431 | apply interp_closed in Hinterp1 as Hcloclosed; | ||
| 432 | [|done|by rewrite dom_empty_L]. simpl in Hcloclosed. | ||
| 433 | destruct v1; simplify_option_eq. | ||
| 434 | destruct Hcloclosed as [HE0closed He0closed]. | ||
| 435 | eapply interp_proper with (E2 := <[x0:=Thunk ∅ e2]> E0) (e2 := e0) | ||
| 436 | in Hinterp as (w & m2 & Hinterp2 & Hv); last apply subst_env_insert_eq. | ||
| 437 | { exists w, (S (m1 `max` m2)). rewrite !interp_S /=. | ||
| 438 | rewrite (interp_le Hinterp1) /=; last lia. | ||
| 439 | by rewrite (interp_le Hinterp2) /=; last lia. } | ||
| 440 | - by apply closed_env_insert. | ||
| 441 | - by apply closed_env_insert. | ||
| 442 | - by rewrite dom_insert_L. | ||
| 443 | - by rewrite dom_insert_L. | ||
| 444 | - done. | ||
| 445 | - done. | ||
| 446 | - done. | ||
| 447 | - done. | ||
| 448 | Qed. | ||
| 449 | |||
| 450 | Lemma final_interp e : | ||
| 451 | final e → | ||
| 452 | ∃ w m, interp m ∅ e = mret w ∧ e = val_to_expr w. | ||
| 453 | Proof. | ||
| 454 | induction e; inv 1. | ||
| 455 | - eexists (VString _), 1. by rewrite interp_S /=. | ||
| 456 | - eexists (VClo _ _ _), 1. rewrite interp_S /=. split; [done|]. | ||
| 457 | by rewrite delete_empty subst_env_empty. | ||
| 458 | Qed. | ||
| 459 | |||
| 460 | Lemma red_final_interp e : | ||
| 461 | red step e ∨ final e ∨ ∃ m, interp m ∅ e = mfail. | ||
| 462 | Proof. | ||
| 463 | induction e. | ||
| 464 | - (* ENat *) right; left. constructor. | ||
| 465 | - (* EId *) do 2 right. by exists 1. | ||
| 466 | - (* EAbs *) right; left. constructor. | ||
| 467 | - (* EApp *) destruct IHe1 as [[??]|[Hfinal|[m Hinterp]]]. | ||
| 468 | + left. by repeat econstructor. | ||
| 469 | + apply final_interp in Hfinal as (w & m & Hinterp & ->). | ||
| 470 | destruct (maybe3 VClo w) eqn:Hw. | ||
| 471 | { destruct w; simplify_eq/=. left. by repeat econstructor. } | ||
| 472 | do 2 right. exists (S m). by rewrite interp_S /= Hinterp /= Hw. | ||
| 473 | + do 2 right. exists (S m). by rewrite interp_S /= Hinterp. | ||
| 474 | Qed. | ||
| 475 | |||
| 476 | Lemma interp_complete e1 e2 : | ||
| 477 | closed ∅ e1 → | ||
| 478 | e1 -->* e2 → | ||
| 479 | nf step e2 → | ||
| 480 | ∃ mw m, interp m ∅ e1 = Res mw ∧ | ||
| 481 | if mw is Some w then e2 = val_to_expr w else ¬final e2. | ||
| 482 | Proof. | ||
| 483 | intros He1 Hsteps Hnf. induction Hsteps as [e|e1 e2 e3 Hstep _ IH]. | ||
| 484 | { destruct (red_final_interp e) as [?|[Hfinal|[m Hinterp]]]; [done|..]. | ||
| 485 | - apply final_interp in Hfinal as (w & m & ? & ?). | ||
| 486 | by exists (Some w), m. | ||
| 487 | - exists None, m. split; [done|]. intros Hfinal. | ||
| 488 | apply final_interp in Hfinal as (w & m' & ? & _). | ||
| 489 | by assert (mfail = mret w) by eauto using interp_agree. } | ||
| 490 | apply closed_step in Hstep as He2; last assumption. | ||
| 491 | destruct IH as (mw & m & Hinterp & ?); try done. | ||
| 492 | eapply interp_step in Hinterp as (mw' & m' & ? & ?). | ||
| 493 | - destruct mw, mw'; naive_solver. | ||
| 494 | - done. | ||
| 495 | - done. | ||
| 496 | Qed. | ||
| 497 | |||
| 498 | Lemma interp_complete_ret e1 e2 : | ||
| 499 | closed ∅ e1 → | ||
| 500 | e1 -->* e2 → final e2 → | ||
| 501 | ∃ w m, interp m ∅ e1 = mret w ∧ e2 = val_to_expr w. | ||
| 502 | Proof. | ||
| 503 | intros Hclosed Hsteps Hfinal. apply interp_complete in Hsteps | ||
| 504 | as ([w|] & m & ? & ?); naive_solver eauto using final_nf. | ||
| 505 | Qed. | ||
| 506 | Lemma interp_complete_fail e1 e2 : | ||
| 507 | closed ∅ e1 → | ||
| 508 | e1 -->* e2 → nf step e2 → ¬final e2 → | ||
| 509 | ∃ m, interp m ∅ e1 = mfail. | ||
| 510 | Proof. | ||
| 511 | intros Hclosed Hsteps Hnf Hforce. | ||
| 512 | apply interp_complete in Hsteps as ([w|] & m & ? & ?); simplify_eq/=; try by eauto. | ||
| 513 | destruct Hforce. apply final_val_to_expr. | ||
| 514 | Qed. | ||
| 515 | |||
| 516 | Lemma interp_sound_open E e n mv : | ||
| 517 | closed_env E → closed (dom E) e → | ||
| 518 | interp n E e = Res mv → | ||
| 519 | ∃ e', subst_env E e -->* e' ∧ | ||
| 520 | if mv is Some v then e' = val_to_expr v else stuck e'. | ||
| 521 | Proof. | ||
| 522 | revert E e mv. | ||
| 523 | induction n as [|n IH]; intros E e mv HEclosed Heclosed Hinterp; first done. | ||
| 524 | rewrite subst_env_eq. rewrite interp_S in Hinterp. | ||
| 525 | destruct e; simplify_res. | ||
| 526 | - (* ENat *) by eexists. | ||
| 527 | - (* EId *) destruct (_ !! _) as [[E' e]|] eqn:Hx; simplify_res. | ||
| 528 | + apply closed_env_lookup in Hx as Hxclosed; last done. | ||
| 529 | rewrite closed_thunk_eq in Hxclosed. destruct_and!. | ||
| 530 | apply IH in Hinterp as (e' & Hsteps & He'); naive_solver. | ||
| 531 | + eexists; repeat split; [done| |inv 1]. intros [? Hstep]. inv Hstep. | ||
| 532 | - (* EAbs *) by eexists. | ||
| 533 | - (* EApp *) destruct_and!. | ||
| 534 | destruct (interp _ _ _) as [mv'|] eqn:Hinterp'; simplify_res. | ||
| 535 | apply interp_closed in Hinterp' as Hvclosed; [|done..]. | ||
| 536 | apply IH in Hinterp' as (e' & Hsteps & He'); [|done..]. | ||
| 537 | destruct mv' as [v'|]; simplify_res; last first. | ||
| 538 | { eexists; repeat split; [by apply SAppL_rtc| |inv 1]. | ||
| 539 | intros [e'' Hstep]. destruct He' as [Hnf Hfinal]. | ||
| 540 | inv Hstep; [by destruct Hfinal; constructor|]. destruct Hnf. eauto. } | ||
| 541 | destruct (maybe3 VClo v') eqn:?; simplify_res; last first. | ||
| 542 | { eexists; repeat split; [by apply SAppL_rtc| |inv 1]. | ||
| 543 | intros [e'' Hstep]. inv Hstep; destruct v'; by repeat inv_step. } | ||
| 544 | destruct v'; simplify_res. destruct_and!. | ||
| 545 | apply IH in Hinterp as (e'' & Hsteps' & He''). | ||
| 546 | + eexists; split; [|done]. etrans; [by apply SAppL_rtc|]. | ||
| 547 | eapply rtc_l; first by constructor. | ||
| 548 | rewrite subst_env_insert // in Hsteps'. | ||
| 549 | + by apply closed_env_insert. | ||
| 550 | + by rewrite dom_insert_L. | ||
| 551 | Qed. | ||
| 552 | |||
| 553 | Lemma interp_sound n e mv : | ||
| 554 | closed ∅ e → | ||
| 555 | interp n ∅ e = Res mv → | ||
| 556 | ∃ e', e -->* e' ∧ if mv is Some v then e' = val_to_expr v else stuck e'. | ||
| 557 | Proof. | ||
| 558 | intros He Hsteps%interp_sound_open; try done. | ||
| 559 | by rewrite subst_env_empty in Hsteps. | ||
| 560 | Qed. | ||
| 561 | |||
| 562 | (** Final theorems *) | ||
| 563 | Theorem interp_sound_complete_ret e v : | ||
| 564 | closed ∅ e → | ||
| 565 | (∃ w n, interp n ∅ e = mret w ∧ val_to_expr v = val_to_expr w) | ||
| 566 | ↔ e -->* val_to_expr v. | ||
| 567 | Proof. | ||
| 568 | split. | ||
| 569 | - by intros (n & w & (e' & ? & ->)%interp_sound & ->). | ||
| 570 | - intros Hsteps. apply interp_complete in Hsteps as ([] & ? & ? & ?); | ||
| 571 | unfold nf, red; | ||
| 572 | naive_solver eauto using final_val_to_expr, step_not_val_to_expr. | ||
| 573 | Qed. | ||
| 574 | |||
| 575 | Theorem interp_sound_complete_ret_string e s : | ||
| 576 | closed ∅ e → | ||
| 577 | (∃ n, interp n ∅ e = mret (VString s)) ↔ e -->* EString s. | ||
| 578 | Proof. | ||
| 579 | split. | ||
| 580 | - by intros [n (e' & ? & ->)%interp_sound]. | ||
| 581 | - intros Hsteps. apply interp_complete_ret in Hsteps as ([] & ? & ? & ?); | ||
| 582 | simplify_eq/=; eauto. | ||
| 583 | Qed. | ||
| 584 | |||
| 585 | Theorem interp_sound_complete_fail e : | ||
| 586 | closed ∅ e → | ||
| 587 | (∃ n, interp n ∅ e = mfail) ↔ ∃ e', e -->* e' ∧ stuck e'. | ||
| 588 | Proof. | ||
| 589 | split. | ||
| 590 | - by intros [n ?%interp_sound]. | ||
| 591 | - intros (e' & Hsteps & Hnf & Hforced). by eapply interp_complete_fail. | ||
| 592 | Qed. | ||
| 593 | |||
| 594 | Theorem interp_sound_complete_no_fuel e : | ||
| 595 | closed ∅ e → | ||
| 596 | (∀ n, interp n ∅ e = NoFuel) ↔ all_loop step e. | ||
| 597 | Proof. | ||
| 598 | rewrite all_loop_alt. split. | ||
| 599 | - intros Hnofuel e' Hsteps. | ||
| 600 | destruct (red_final_interp e') as [|[|He']]; [done|..]. | ||
| 601 | + apply interp_complete_ret in Hsteps as (w & m & Hinterp & _); [|done..]. | ||
| 602 | by rewrite Hnofuel in Hinterp. | ||
| 603 | + apply interp_sound_complete_fail in He' as (e'' & ? & [Hnf _]); | ||
| 604 | last by eauto using closed_steps. | ||
| 605 | destruct (interp_complete e e'') as (mv & n & Hinterp & _); [done|by etrans|done|]. | ||
| 606 | by rewrite Hnofuel in Hinterp. | ||
| 607 | - intros Hred n. destruct (interp n ∅ e) as [mv|] eqn:Hinterp; [|done]. | ||
| 608 | apply interp_sound in Hinterp as (e' & Hsteps%Hred & Hstuck); [|done]. | ||
| 609 | destruct mv as [v|]; simplify_eq/=. | ||
| 610 | + apply final_nf in Hsteps as []. apply final_val_to_expr. | ||
| 611 | + by destruct Hstuck as [[] ?]. | ||
| 612 | Qed. | ||
| 613 | |||
| 614 | End lambda. | ||
diff --git a/theories/lambda/operational.v b/theories/lambda/operational.v new file mode 100644 index 0000000..b0fa366 --- /dev/null +++ b/theories/lambda/operational.v | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | From mininix Require Export utils. | ||
| 2 | From stdpp Require Import options. | ||
| 3 | |||
| 4 | Module Import lambda. | ||
| 5 | |||
| 6 | Inductive expr := | ||
| 7 | | EString (s : string) | ||
| 8 | | EId (x : string) | ||
| 9 | | EAbs (x : string) (e : expr) | ||
| 10 | | EApp (e1 e2 : expr). | ||
| 11 | |||
| 12 | Fixpoint subst (ds : gmap string expr) (e : expr) : expr := | ||
| 13 | match e with | ||
| 14 | | EString s => EString s | ||
| 15 | | EId x => if ds !! x is Some d then d else EId x | ||
| 16 | | EAbs x e => EAbs x (subst (delete x ds) e) | ||
| 17 | | EApp e1 e2 => EApp (subst ds e1) (subst ds e2) | ||
| 18 | end. | ||
| 19 | |||
| 20 | Reserved Infix "-->" (right associativity, at level 55). | ||
| 21 | Inductive step : expr → expr → Prop := | ||
| 22 | | Sβ x e1 e2 : EApp (EAbs x e1) e2 --> subst {[x:=e2]} e1 | ||
| 23 | | SAppL e1 e1' e2 : e1 --> e1' → EApp e1 e2 --> EApp e1' e2 | ||
| 24 | where "e1 --> e2" := (step e1 e2). | ||
| 25 | |||
| 26 | Infix "-->*" := (rtc step) (right associativity, at level 55). | ||
| 27 | |||
| 28 | Definition final (e : expr) : Prop := | ||
| 29 | match e with | ||
| 30 | | EString _ => True | ||
| 31 | | EAbs _ _ => True | ||
| 32 | | _ => False | ||
| 33 | end. | ||
| 34 | |||
| 35 | Definition stuck (e : expr) : Prop := | ||
| 36 | nf step e ∧ ¬final e. | ||
| 37 | |||
| 38 | End lambda. | ||
diff --git a/theories/lambda/operational_props.v b/theories/lambda/operational_props.v new file mode 100644 index 0000000..c331924 --- /dev/null +++ b/theories/lambda/operational_props.v | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | From mininix Require Export lambda.operational. | ||
| 2 | From stdpp Require Import options. | ||
| 3 | |||
| 4 | Module Import lambda. | ||
| 5 | Export lambda. | ||
| 6 | |||
| 7 | (** Properties of operational semantics *) | ||
| 8 | Lemma step_not_final e1 e2 : e1 --> e2 → ¬final e1. | ||
| 9 | Proof. induction 1; inv 1; naive_solver. Qed. | ||
| 10 | Lemma final_nf e : final e → nf step e. | ||
| 11 | Proof. by intros ? [??%step_not_final]. Qed. | ||
| 12 | |||
| 13 | Lemma SAppL_rtc e1 e1' e2 : e1 -->* e1' → EApp e1 e2 -->* EApp e1' e2. | ||
| 14 | Proof. induction 1; repeat (done || econstructor). Qed. | ||
| 15 | |||
| 16 | Ltac inv_step := repeat | ||
| 17 | match goal with H : ?e --> _ |- _ => assert_fails (is_var e); inv H end. | ||
| 18 | |||
| 19 | Lemma step_det e d1 d2 : | ||
| 20 | e --> d1 → | ||
| 21 | e --> d2 → | ||
| 22 | d1 = d2. | ||
| 23 | Proof. | ||
| 24 | intros Hred1. revert d2. | ||
| 25 | induction Hred1; intros d2 Hred2; inv Hred2; try by inv_step. | ||
| 26 | f_equal. by apply IHHred1. | ||
| 27 | Qed. | ||
| 28 | |||
| 29 | End lambda. | ||