From mininix Require Export lambda.interp_proofs dynlang.interp_proofs. From stdpp Require Import options. Class Lift A B := lift : A → B. Global Hint Mode Lift ! - : typeclass_instances. Arguments lift {_ _ _} !_ /. Notation "⌜ x ⌝" := (lift x) (at level 0). Notation "⌜* x ⌝" := (fmap lift x) (at level 0). Module lambda. Global Instance lambda_expr_lift : Lift lambda.expr dynlang.expr := fix go e := let _ : Lift _ _ := go in match e with | lambda.EString s => dynlang.EString s | lambda.EId x => dynlang.EId ∅ (dynlang.EString x) | lambda.EAbs x e => dynlang.EAbs (dynlang.EString x) ⌜e⌝ | lambda.EApp e1 e2 => dynlang.EApp ⌜e1⌝ ⌜e2⌝ end. Global Instance lambda_thunk_lift : Lift lambda.thunk dynlang.thunk := fix go t := let _ : Lift _ _ := go in dynlang.Thunk ⌜*lambda.thunk_env t⌝ ⌜lambda.thunk_expr t⌝. Global Instance lambda_val_lift : Lift lambda.val dynlang.val := λ v, match v with | lambda.VString s => dynlang.VString s | lambda.VClo x E e => dynlang.VClo x ⌜*E⌝ ⌜e⌝ end. End lambda. Lemma interp_open_lambda_dynlang E e mv n : lambda.closed_env E → lambda.closed (dom E) e → lambda.interp n E e = Res mv → ∃ m, dynlang.interp m ⌜*E⌝ ⌜e⌝ = Res ⌜*mv⌝. Proof. revert E e mv. induction n as [|n IH]; [done|]; intros E e mv HE He Hinterp. rewrite lambda.interp_S in Hinterp. destruct e as [s|z|ex e|e1 e2]; simplify_res. - (* EString *) by exists 1. - (* EId *) apply elem_of_dom in He as [[Et et] Hz]. rewrite Hz /= in Hinterp. apply lambda.closed_env_lookup in Hz as He; last done. rewrite lambda.closed_thunk_eq/= in He. destruct He as [HEtclosed Hetclosed]. apply IH in Hinterp as [m Hinterp]; [|done..]. exists (S (S m)). rewrite !dynlang.interp_S /= -dynlang.interp_S. rewrite lookup_empty /= right_id_L lookup_fmap Hz /=. eauto using dynlang.interp_le with lia. - (* EAbs *) by exists 2. - (* EApp *) destruct He as [He1 He2]. destruct (lambda.interp _ _ e1) as [mw|] eqn:Hinterp1; simplify_res. pose proof Hinterp1 as Hinterp1'. apply lambda.interp_closed in Hinterp1' as Hmw; [|done..]. eapply IH in Hinterp1 as [m1 Hinterp1]; [|done..]. destruct mw as [w|]; simplify_res; last first. { exists (S m1). by rewrite dynlang.interp_S /= Hinterp1. } destruct (maybe3 lambda.VClo w) eqn:?; simplify_res; last first. { exists (S m1). rewrite dynlang.interp_S /= Hinterp1 /=. by destruct w. } destruct w; simplify_res. apply IH in Hinterp as [m2 Hinterp2]. + exists (S (m1 + m2)). rewrite dynlang.interp_S /=. rewrite (dynlang.interp_le Hinterp1) /=; last lia. rewrite fmap_insert /= in Hinterp2. rewrite (dynlang.interp_le Hinterp2) /=; last lia. done. + apply lambda.closed_env_insert; [by split|naive_solver]. + rewrite dom_insert_L. set_solver. Qed. Lemma interp_lambda_dynlang e mv n : lambda.closed ∅ e → lambda.interp n ∅ e = Res mv → ∃ m, dynlang.interp m ∅ ⌜e⌝ = Res ⌜*mv⌝. Proof. intro. by apply interp_open_lambda_dynlang. Qed. Lemma interp_open_dynlang_lambda E e mv n : lambda.closed_env E → lambda.closed (dom E) e → dynlang.interp n ⌜*E⌝ ⌜e⌝ = Res mv → ∃ mw, lambda.interp n E e = Res mw ∧ mv = ⌜*mw⌝. Proof. revert E e mv. induction n as [|n IH]; [done|]; intros E e mv HE He Hinterp. rewrite dynlang.interp_S in Hinterp. destruct e as [s|z|ex e|e1 e2]; simplify_res. - (* EString *) rewrite lambda.interp_S /=. by eexists. - (* EId *) destruct n as [|n]; [done|]. rewrite dynlang.interp_S /= -dynlang.interp_S in Hinterp. apply elem_of_dom in He as [[Et et] Hz]. pose proof (f_equal (fmap lift) Hz) as Hz'. rewrite -lookup_fmap /= in Hz'. rewrite Hz' lookup_empty /= {Hz'} in Hinterp. pose proof Hz as Hz'. apply lambda.closed_env_lookup in Hz' as [HEt Het]; simpl in *; last done. apply IH in Hinterp as (mw & Hinterp & ->); [|done..]. exists mw. rewrite lambda.interp_S /= Hz /=. done. - (* EAbs *) destruct n as [|n]; [done|]. rewrite dynlang.interp_S /= in Hinterp; simplify_res. rewrite lambda.interp_S /=. by eexists. - (* EApp *) destruct He as [He1 He2]. destruct (dynlang.interp _ _ _) as [mw1|] eqn:Hinterp1; simplify_res. eapply IH in Hinterp1 as (mv1 & Hinterp1 & ->); [|done..]. destruct mv1 as [v1|]; simplify_res; last first. { exists None. by rewrite lambda.interp_S /= Hinterp1. } destruct (maybe3 dynlang.VClo _) eqn:?; simplify_res; last first. { exists None. rewrite lambda.interp_S /= Hinterp1 /=. by destruct v1. } destruct v1; simplify_res. change (dynlang.Thunk ⌜*E⌝ ⌜e2⌝) with ⌜lambda.Thunk E e2⌝ in Hinterp. rewrite -fmap_insert in Hinterp. apply lambda.interp_closed in Hinterp1 as Hmw; [|done..]. apply IH in Hinterp as (mv2 & Hinterp2 & ->). + exists mv2. rewrite lambda.interp_S /= Hinterp1 /=. done. + apply lambda.closed_env_insert; [by split|]. naive_solver. + rewrite dom_insert_L. set_solver. Qed. Lemma interp_dynlang_lambda e mv n : lambda.closed ∅ e → dynlang.interp n ∅ ⌜e⌝ = Res mv → ∃ mw, lambda.interp n ∅ e = Res mw ∧ mv = ⌜*mw⌝. Proof. intros. by apply interp_open_dynlang_lambda. Qed. (* The following equivalences about the semantics trivially follow: *) Theorem interp_equiv_ret_string e s : lambda.closed ∅ e → rtc lambda.step e (lambda.EString s) ↔ rtc dynlang.step ⌜e⌝ (dynlang.EString s). Proof. intros. rewrite -lambda.interp_sound_complete_ret_string //. rewrite -dynlang.interp_sound_complete_ret_string. split; intros [n Hinterp]. + by apply interp_lambda_dynlang in Hinterp. + apply interp_dynlang_lambda in Hinterp as ([[]|] & ?); naive_solver. Qed. Theorem interp_equiv_fail e : lambda.closed ∅ e → (∃ e', rtc lambda.step e e' ∧ lambda.stuck e') ↔ (∃ e', rtc dynlang.step ⌜e⌝ e' ∧ dynlang.stuck e'). Proof. intros. rewrite -lambda.interp_sound_complete_fail //. rewrite -dynlang.interp_sound_complete_fail. split; intros [n Hinterp]. + by apply interp_lambda_dynlang in Hinterp. + apply interp_dynlang_lambda in Hinterp as ([] & ?); naive_solver. Qed. Theorem interp_equiv_no_fuel e : lambda.closed ∅ e → all_loop lambda.step e ↔ all_loop dynlang.step ⌜e⌝. Proof. intros He. rewrite -lambda.interp_sound_complete_no_fuel; last done. rewrite -dynlang.interp_sound_complete_no_fuel. split; intros Hnofuel n. - destruct (dynlang.interp n ∅ _) as [mv|] eqn:Hinterp; [|done]. apply interp_dynlang_lambda in Hinterp as (? & Hinterp & _); [|done]. by rewrite Hnofuel in Hinterp. - destruct (lambda.interp n ∅ _) as [mv|] eqn:Hinterp; [|done]. apply interp_lambda_dynlang in Hinterp as [m Hinterp]; [|done..]. by rewrite Hnofuel in Hinterp. Qed.