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