From stdpp Require Import gmap base relations tactics. From iris Require Import prelude. From semantics.ts.stlc Require Import lang notation. (** Exercise 2 (LN Exercise 1): Deterministic Operational Semantics *) Lemma val_no_step e e': step e e' → is_val e → False. Proof. by destruct 1. Qed. (* Note how the above lemma is another way to phrase the statement "values * cannot step" that doesn't need inversion. It can also be used to prove the * phrasing we had to use inversion for in the lecture: *) Lemma val_no_step' (v : val) (e : expr) : step v e -> False. Proof. intros H. eapply val_no_step; first eassumption. apply is_val_val. Qed. (* You might find the following tactic useful, which derives a contradiction when you have a [step e1 e2] assumption and [e1] is a value. Example: H1: step e e' H2: is_val e ===================== ??? Then [val_no_step.] will solve the goal by applying the [val_no_step] lemma. (We neither expect you to understand how exactly the tactic does this nor to be able to write such a tactic yourself. Where useful, we will always provide you with custom tactics and explain in a comment what they do.) *) Ltac val_no_step := match goal with | [H: step ?e1 ?e2 |- _] => solve [exfalso; eapply (val_no_step _ _ H); done] end. Lemma step_det e e' e'': step e e' → step e e'' → e' = e''. Proof. induction 1 in e'' |-*; inversion 1; subst; eauto. all: try val_no_step || naive_solver. Qed. (** Exercise 3 (LN Exercise 2): Call-by-name Semantics *) Inductive cbn_step : expr → expr → Prop := | CBNStepBeta x e e' : cbn_step (App (Lam x e) e') (subst' x e' e) | CBNStepAppL e1 e1' e2 : cbn_step e1 e1' → cbn_step (App e1 e2) (App e1' e2) | CBNStepPlusRed (n1 n2 n3: Z) : (n1 + n2)%Z = n3 → cbn_step (Plus (LitInt n1) (LitInt n2)) (LitInt n3) | CBNStepPlusL e1 e1' e2 : is_val e2 → cbn_step e1 e1' → cbn_step (Plus e1 e2) (Plus e1' e2) | CBNStepPlusR e1 e2 e2' : cbn_step e2 e2' → cbn_step (Plus e1 e2) (Plus e1 e2'). (* We make the eauto tactic aware of the constructors of cbn_step *) #[global] Hint Constructors cbn_step : core. Lemma different_results : ∃ (e: expr) (e1 e2: expr), rtc cbn_step e e1 ∧ rtc step e e2 ∧ is_val e1 ∧ is_val e2 ∧ e1 ≠ e2. Proof. exists ((λ: "x" "y", "x") (4 + 1))%E. do 2 eexists. repeat split. - econstructor 2. econstructor. simpl. reflexivity. - econstructor 2. eauto. econstructor 2. econstructor; simpl; done. reflexivity. - done. - done. - intros ?. injection H as Heq. discriminate Heq. Qed. Lemma val_no_cbn_step e e': cbn_step e e' → is_val e → False. Proof. destruct e; try naive_solver; inversion 1. Qed. (* Same tactic as [val_no_step] but for cbn_step.*) Ltac val_no_cbn_step := match goal with | [H: cbn_step ?e1 ?e2 |- _] => solve [exfalso; eapply (val_no_cbn_step _ _ H); done] end. Lemma cbn_step_det e e' e'': cbn_step e e' → cbn_step e e'' → e' = e''. Proof. induction 1 in e'' |-*; inversion 1; subst; eauto. all: try val_no_cbn_step || naive_solver. Qed. (** Exercise 4 (LN Exercise 3): Reflexive Transitive Closure *) Section rtc. Context {X : Type}. Inductive rtc (R : X → X → Prop) : X → X → Prop := | rtc_base x : rtc R x x | rtc_step x y z : R x y → rtc R y z → rtc R x z. Lemma rtc_reflexive R : Reflexive (rtc R). Proof. unfold Reflexive. intros x. constructor. Qed. Lemma rtc_transitive R : Transitive (rtc R). Proof. unfold Transitive. intros x y z HR1 HR2. induction HR1 as [ | ??? HR HR1 IH]. - apply HR2. - econstructor. + apply HR. + apply IH; done. Qed. Lemma rtc_subrel (R: X → X → Prop) (x y : X): R x y → rtc R x y. Proof. intros ?. econstructor. - done. - eapply rtc_reflexive. Qed. Section typeclass. (* We can use Coq's typeclass mechanism to enable the use of the [transitivity] and [reflexivity] tactics on our goals. Typeclasses enable easy extensions of existing mechanisms -- in this case, by telling Coq to use the knowledge about our definition of [rtc]. *) (* [Transitive] is a typeclass. With [Instance] we provide an instance of it. *) Global Instance rtc_transitive_inst R : Transitive (rtc R). Proof. apply rtc_transitive. Qed. Global Instance rtc_reflexive_inst R : Reflexive (rtc R). Proof. apply rtc_reflexive. Qed. End typeclass. End rtc. (* Let's put this to the test! *) Goal rtc step (LitInt 42) (LitInt 42). Proof. (* this uses the [rtc_reflexive_inst] instance we registered. *) reflexivity. Qed. Goal rtc step (LitInt 32 + (LitInt 5 + LitInt 5)%E)%E (LitInt 42). Proof. (* this uses the [rtc_transitive_inst] instance we registered. *) etransitivity. + eapply rtc_step; eauto. reflexivity. + eapply rtc_step; eauto. reflexivity. Qed. Section stdpp. (* In fact, [rtc] is so common that it is already provided by the [stdpp] library! *) Import stdpp.relations. (* The typeclass instances are also already registered. *) Goal rtc step (LitInt 42) (LitInt 42). Proof. reflexivity. Qed. End stdpp. (* Start by proving these lemmas. Understand why they are useful. *) Lemma plus_right e1 e2 e2': rtc step e2 e2' → rtc step (Plus e1 e2) (Plus e1 e2'). Proof. induction 1. - done. - econstructor. + econstructor 6. done. + done. Qed. Lemma plus_left e1 e1' n: rtc step e1 e1' → rtc step (Plus e1 (LitInt n)) (Plus e1' (LitInt n)). Proof. induction 1. - done. - econstructor. + econstructor. all: done. + done. Qed. (* The exercise: *) Lemma plus_to_consts e1 e2 n m: rtc step e1 (LitInt n) → rtc step e2 (LitInt m) → rtc step (e1 + e2)%E (LitInt (n + m)%Z). Proof. intros H1 H2. etransitivity. - eapply plus_right. done. - etransitivity. + eapply plus_left. done. + eapply rtc_subrel. econstructor. done. Qed. (* Now that you have an understanding of how rtc works, we can make eauto aware of it. *) #[local] Hint Constructors rtc : core. (* See its power here: *) Lemma plus_right_eauto e1 e2 e2': rtc step e2 e2' → rtc step (Plus e1 e2) (Plus e1 e2'). Proof. induction 1; eauto. Abort. (** Exercise 5 (LN Exercise 4): Big-step vs small-step semantics *) (* We first prove a lemma for each of the interesting cases: *) Lemma rtc_step_app_l e1 e1' e2: rtc step e1 e1' → is_val e2 → rtc step (App e1 e2) (App e1' e2). Proof. induction 1; eauto. Qed. Lemma rtc_step_app_r e1 e2 e2': rtc step e2 e2' → rtc step (App e1 e2) (App e1 e2'). Proof. induction 1; eauto. Qed. Lemma rtc_step_plus_l e1 e1' e2: rtc step e1 e1' → is_val e2 → rtc step (Plus e1 e2) (Plus e1' e2). Proof. induction 1; eauto. Qed. Lemma rtc_step_plus_r e1 e2 e2': rtc step e2 e2' → rtc step (Plus e1 e2) (Plus e1 e2'). Proof. induction 1; eauto. Qed. Lemma big_step_steps e v : big_step e v → rtc step e (of_val v). Proof. induction 1 as [ | | e1 e2 v1 v2 H1 IH1 H2 IH2 | e1 e2 x e v2 v H1 IH1 H2 IH2 H3 IH3]. - constructor. - constructor. - etransitivity. eapply rtc_step_plus_r; eauto. etransitivity. eapply rtc_step_plus_l; eauto. econstructor 2. apply StepPlusRed; done. done. - etransitivity. eapply rtc_step_app_r; eauto. etransitivity. eapply rtc_step_app_l; eauto. econstructor 2. simpl. econstructor. eauto. done. Qed. (* Again, we will first prove some lemmas: *) Lemma single_step_big_step_cons e (v : val) : step e v -> big_step e v. Proof. intros H. inversion H as [x e1 e2 He2 Heq1 Heq| | |n1 n2 n3 Heq1 Heq2 Heq| |]; subst. 2-3,5-6: try (destruct v; discriminate). - apply is_val_spec in He2 as [v' <-%of_to_val]. econstructor. + eauto. + apply big_step_vals. + rewrite Heq. apply big_step_vals. - destruct v. + injection Heq as <-. repeat constructor. + exfalso. discriminate Heq. Qed. Lemma step_big_step_cons e e' v : step e e' → big_step e' v → big_step e v. Proof. induction 1 in v |- *. - eapply is_val_spec in H as [w <-%of_to_val]. intros Hbig. econstructor; eauto using big_step_vals. - inversion 1; subst; eauto. - inversion 1; subst; eauto. - inversion 1; subst. eauto. - inversion 1; subst; eauto. - inversion 1; subst; eauto. Restart. (* we can also show this by induction on big_step e' v instead. However, this * turns out to be more ugly. Both base cases are by the lemma we showed before. *) intros Hsmall Hbig. induction Hbig in Hsmall, e |-*. (* with Hsmall and e quantified *) - apply single_step_big_step_cons, Hsmall. - apply single_step_big_step_cons, Hsmall. - inversion Hsmall as [x e3 e4 He4 Heq1 Heq| | | | | ]; subst. + apply is_val_spec in He4 as [v' <-%of_to_val]. econstructor. 1-2: eauto using big_step_vals. rewrite Heq. eauto. + eauto. + eauto. - inversion Hsmall as [x' e3 e4 He4 Htemp Heq| | | | | ]; subst. + apply is_val_spec in He4 as [v' <-%of_to_val]. econstructor. 1-2: eauto using big_step_vals. rewrite Heq. eauto. + eauto. + eauto. Qed. Lemma steps_big_step_cons e e' w: rtc step e e' → big_step e' w → big_step e w. Proof. induction 1; eauto using step_big_step_cons. Qed. Lemma steps_big_step e (v: val): rtc step e v → big_step e v. Proof. (* Note how there is a coercion (automatic conversion) hidden in the * statement of this lemma: *) Set Printing Coercions. (* It is sometimes very useful to temporarily print coercions if rewrites or * destructs do not behave as expected. *) Unset Printing Coercions. intros Hsteps. eapply steps_big_step_cons; eauto using big_step_vals. Qed. (** Exercise 6 (LN Exercise 5): left-to-right evaluation *) Inductive ltr_step : expr → expr → Prop := | LTRStepBeta x e e' : is_val e' → ltr_step (App (Lam x e) e') (subst' x e' e) | LTRStepAppL e1 e1' e2 : ltr_step e1 e1' → ltr_step (App e1 e2) (App e1' e2) | LTRStepAppR e1 e2 e2' : ltr_step e2 e2' → is_val e1 → ltr_step (App e1 e2) (App e1 e2') | LTRStepPlusRed (n1 n2 n3: Z) : (n1 + n2)%Z = n3 → ltr_step (Plus (LitInt n1) (LitInt n2)) (LitInt n3) | LTRStepPlusL e1 e1' e2 : ltr_step e1 e1' → ltr_step (Plus e1 e2) (Plus e1' e2) | LTRStepPlusR e1 e2 e2' : is_val e1 → ltr_step e2 e2' → ltr_step (Plus e1 e2) (Plus e1 e2'). #[global] Hint Constructors ltr_step : core. Lemma different_steps_ltr_step : ∃ (e: expr) (e1 e2: expr), ltr_step e e1 ∧ step e e2 ∧ e1 ≠ e2. Proof. exists ((4 + 1) + (4 + 1))%E. do 2 eexists. repeat split. - econstructor 5. econstructor. done. - econstructor 6. econstructor. done. - intros Heq. injection Heq as Heq. discriminate Heq. Qed. Lemma rtc_ltr_step_app_l e1 e1' e2: rtc ltr_step e1 e1' → rtc ltr_step (App e1 e2) (App e1' e2). Proof. induction 1; eauto. Qed. Lemma rtc_ltr_step_app_r e1 e2 e2': rtc ltr_step e2 e2' → is_val e1 → rtc ltr_step (App e1 e2) (App e1 e2'). Proof. induction 1; eauto. Qed. Lemma rtc_ltr_step_plus_l e1 e1' e2: rtc ltr_step e1 e1' → rtc ltr_step (Plus e1 e2) (Plus e1' e2). Proof. induction 1; eauto. Qed. Lemma rtc_ltr_step_plus_r e1 e2 e2': rtc ltr_step e2 e2' → is_val e1 → rtc ltr_step (Plus e1 e2) (Plus e1 e2'). Proof. induction 1; eauto. Qed. Lemma big_step_ltr_steps e v : big_step e v → rtc ltr_step e (of_val v). Proof. induction 1 as [ | | e1 e2 v1 v2 H1 IH1 H2 IH2 | e1 e2 x e v2 v H1 IH1 H2 IH2 H3 IH3]. - constructor. - constructor. - etransitivity. eapply rtc_ltr_step_plus_l; eauto. etransitivity. eapply rtc_ltr_step_plus_r; eauto. econstructor 2. econstructor; done. done. - etransitivity. eapply rtc_ltr_step_app_l; eauto. etransitivity. eapply rtc_ltr_step_app_r; eauto. econstructor 2. simpl. econstructor. eauto. done. Qed. Lemma ltr_step_big_step_cons e e' v : ltr_step e e' → big_step e' v → big_step e v. Proof. induction 1 in v |-*. - eapply is_val_spec in H as [w H]. eapply of_to_val in H. subst. intros Hbig. econstructor; eauto using big_step_vals. - inversion 1; subst; eauto. - inversion 1; subst; eauto. - inversion 1; subst. eauto. - inversion 1; subst; eauto. - inversion 1; subst; eauto. Qed. Lemma ltr_steps_big_step_cons e e' w: rtc ltr_step e e' → big_step e' w → big_step e w. Proof. induction 1; eauto using ltr_step_big_step_cons. Qed. Lemma ltr_steps_big_step e (v: val): rtc ltr_step e v → big_step e v. Proof. intros Hsteps. eapply ltr_steps_big_step_cons; eauto using big_step_vals. Qed.