From stdpp Require Import gmap base relations. From iris Require Import prelude. From semantics.ts.systemf Require Import lang notation parallel_subst types logrel tactics. (** Exercise 1 (LN Exercise 19): De Bruijn Terms *) Module dbterm. (** Your type of expressions only needs to encompass the operations of our base lambda calculus. *) Inductive expr := | Lit (l : base_lit) | Var (n : nat) | Lam (e : expr) | Plus (e1 e2 : expr) | App (e1 e2 : expr) . (** Formalize substitutions and renamings as functions. *) Definition subt := nat → expr. Definition rent := nat → nat. Implicit Types (σ : subt) (δ : rent) (n x : nat) (e : expr). (* Operations on renamings *) Definition RCons n δ x := match x with | 0 => n | S x => δ x end. Definition RComp δ1 δ2 := δ1 ∘ δ2. Definition RUp δ := RCons 0 (RComp S δ). Fixpoint ren_expr δ e := match e with | Lit l => Lit l | Var x => Var (δ x) | Lam e => Lam (ren_expr (RUp δ) e) | App e1 e2 => App (ren_expr δ e1) (ren_expr δ e2) | Plus e1 e2 => Plus (ren_expr δ e1) (ren_expr δ e2) end. (* Operations on substitutions *) Definition Cons e σ x := match x with | 0 => e | S x => σ x end. Definition ren_subst δ σ n := ren_expr δ (σ n). Definition Up σ := Cons (Var 0) (ren_subst S σ). Fixpoint subst σ e := match e with | Lit l => Lit l | Var x => σ x | Lam e => Lam (subst (Up σ) e) | App e1 e2 => App (subst σ e1) (subst σ e2) | Plus e1 e2 => Plus (subst σ e1) (subst σ e2) end. Goal (subst (λ n, match n with | 0 => Lit (LitInt 42) | 1 => Var 0 | _ => Var n end) (Lam (Plus (Plus (Var 2) (Var 1)) (Var 0)))) = Lam (Plus (Plus (Var 1) (Lit 42%Z)) (Var 0)). Proof. cbn. (* Should be by reflexivity. *) reflexivity. Qed. End dbterm. Section church_encodings. (** Exercise 2 (LN Exercise 24): Church encoding, sum types *) (* a) Define your encoding *) Definition sum_type (A B : type) : type := ∀: (A.[ren (+1)] → #0) → (B.[ren (+1)] → #0) → #0. (* b) Implement inj1, inj2, case *) Definition injl_val (v : val) : val := Λ, λ: "f" "g", "f" v. Definition injl_expr (e : expr) : expr := let: "x" := e in Λ, λ: "f" "g", "f" "x". Definition injr_val (v : val) : val := Λ, λ: "f" "g", "g" v. Definition injr_expr (e : expr) : expr := let: "x" := e in Λ, λ: "f" "g", "g" "x". (* You may want to use the variables x1, x2 for the match arms to fit the typing statements below. *) Definition match_expr (e : expr) (e1 e2 : expr) : expr := (e <> (λ: "x1", e1) (λ: "x2", e2))%E. (* c) Reduction behavior *) (* Some lemmas about substitutions might be useful. Look near the end of the lang.v file! *) Lemma match_expr_red_injl e e1 e2 (vl v' : val) : is_closed [] vl → is_closed ["x1"] e1 → big_step e (injl_val vl) → big_step (subst' "x1" vl e1) v' → big_step (match_expr e e1 e2) v'. Proof. intros. bs_step_det. erewrite (lang.subst_is_closed ["x1"] _ "g"); [ done | done | rewrite elem_of_list_singleton; done]. Qed. Lemma match_expr_red_injr e e1 e2 (vl v' : val) : is_closed [] vl → big_step e (injr_val vl) → big_step (subst' "x2" vl e2) v' → big_step (match_expr e e1 e2) v'. Proof. intros. bs_step_det. Qed. Lemma injr_expr_red e v : big_step e v → big_step (injr_expr e) (injr_val v). Proof. intros. bs_step_det. Qed. Lemma injl_expr_red e v : big_step e v → big_step (injl_expr e) (injl_val v). Proof. intros. bs_step_det. Qed. (* d) Typing rules *) Lemma sum_injl_typed n Γ (e : expr) A B : type_wf n B → type_wf n A → TY n; Γ ⊢ e : A → TY n; Γ ⊢ injl_expr e : sum_type A B. Proof. intros. solve_typing. Qed. Lemma sum_injr_typed n Γ e A B : type_wf n B → type_wf n A → TY n; Γ ⊢ e : B → TY n; Γ ⊢ injr_expr e : sum_type A B. Proof. intros. solve_typing. Qed. Lemma sum_match_typed n Γ A B C e e1 e2 : type_wf n A → type_wf n B → type_wf n C → TY n; Γ ⊢ e : sum_type A B → TY n; <["x1" := A]> Γ ⊢ e1 : C → TY n; <["x2" := B]> Γ ⊢ e2 : C → TY n; Γ ⊢ match_expr e e1 e2 : C. Proof. intros. solve_typing. Qed. (** Exercise 3 (LN Exercise 25): church encoding, list types *) (* a) translate the type of lists into De Bruijn. *) Definition list_type (A : type) : type := ∀: #0 → (A.[ren (+1)] → #0 → #0) → #0. (* b) Implement nil and cons. *) Definition nil_val : val := Λ, λ: "e" "c", "e". Definition cons_val (v1 v2 : val) : val := Λ, λ: "e" "c", "c" v1 (v2 <> "e" "c"). Definition cons_expr (e1 e2 : expr) : expr := let: "p" := (e1, e2) in Λ, λ: "e" "c", "c" (Fst "p") ((Snd "p") <> "e" "c"). (* c) Define typing rules and prove them *) Lemma nil_typed n Γ A : type_wf n A → TY n; Γ ⊢ nil_val : list_type A. Proof. intros. solve_typing. Qed. Lemma cons_typed n Γ (e1 e2 : expr) A : type_wf n A → TY n; Γ ⊢ e2 : list_type A → TY n; Γ ⊢ e1 : A → TY n; Γ ⊢ cons_expr e1 e2 : list_type A. Proof. intros. repeat solve_typing. Qed. (* d) Define a function head of type list A → A + 1 *) Definition head : val := λ: "l", "l" <> (InjR #LitUnit) (λ: "h" <>, InjL "h"). Lemma head_typed n Γ A : type_wf n A → TY n; Γ ⊢ head: (list_type A → (A + Unit)). Proof. intros. solve_typing. Qed. (* e) Define a function [tail] of type list A → list A *) Definition split : val := λ: "l", "l" <> ((InjR #LitUnit), nil_val) (λ: "h" "r", match: (Fst "r") with InjL "h'" => (InjL "h", let: "r'" := Snd "r" in cons_expr "h'" "r'") | InjR <> => (InjL "h", Snd "r") end). Definition tail : val := λ: "l", Snd (split "l"). Lemma tail_typed n Γ A : type_wf n A → TY n; Γ ⊢ tail: (list_type A → list_type A). Proof. intros. repeat solve_typing. Admitted. End church_encodings. Section free_theorems. (** Exercise 4 (LN Exercise 27): Free Theorems I *) (* a) State a free theorem for the type ∀ α, β. α → β → α × β *) Lemma free_thm_1 : ∀ f : val, TY 0; ∅ ⊢ f : (∀: ∀: #1 → #0 → #1 × #0) → ∀ (v1 v2 : val), is_closed [] v1 → is_closed [] v2 → big_step (f <> <> v1 v2) (v1, v2)%V. Proof. intros f [Htycl Hty]%sem_soundness v1 v2 Hcl1 Hcl2. specialize (Hty ∅ δ_any). simp type_interp in Hty. destruct Hty as (v & Hb & Hv). { constructor. } simp type_interp in Hv. destruct Hv as (e & -> & ? & Hv). specialize_sem_type Hv with (λ v, v = v1) as τ1. { naive_solver. } simp type_interp in Hv. destruct Hv as (ve0 & ? & Hv). simp type_interp in Hv. destruct Hv as (e2 & -> & ? & Hv). specialize_sem_type Hv with (λ v, v = v2) as τ2. { naive_solver. } simp type_interp in Hv. destruct Hv as (ve1 & ? & Hv). simp type_interp in Hv. destruct Hv as (x & e0 & -> & ? & Hv). specialize (Hv v1). simp type_interp in Hv. simpl in Hv. destruct Hv as (ve2 & ? & Hv); first done. simp type_interp in Hv. destruct Hv as (x' & e1 & -> & ? & Hv). specialize (Hv v2). simp type_interp in Hv. simpl in Hv. destruct Hv as (ve3 & ? & Hv); first done. simp type_interp in Hv. destruct Hv as (v1' & v2' & -> & Hv1 & Hv2). simp type_interp in Hv1. simpl in Hv1. subst v1'. simp type_interp in Hv2. simpl in Hv2. subst v2'. bs_step_det. by rewrite subst_map_empty in Hb. Qed. (* b) State a free theorem for the type ∀ α, β. α × β → α *) Lemma free_thm_2 : ∀ f : val, TY 0; ∅ ⊢ f : (∀: ∀: #1 × #0 → #1) → ∀ (v1 v2 : val), is_closed [] v1 → is_closed [] v2 → big_step (f <> <> (v1, v2)%E) v1. Proof. intros f [Htycl Hty]%sem_soundness v1 v2 Hcl1 Hcl2. specialize (Hty ∅ δ_any). simp type_interp in Hty. destruct Hty as (v & Hb & Hv). { constructor. } simp type_interp in Hv. destruct Hv as (? & -> & ? & Hv). specialize_sem_type Hv with (λ v, v = v1) as τ1. { naive_solver. } simp type_interp in Hv. destruct Hv as (? & ? & Hv). simp type_interp in Hv. destruct Hv as (? & -> & ? & Hv). specialize_sem_type Hv with (λ v, v = v2) as τ2. { naive_solver. } simp type_interp in Hv. destruct Hv as (? & ? & Hv). simp type_interp in Hv. destruct Hv as (? & ? & -> & ? & Hv). specialize (Hv (v1, v2)%V). simp type_interp in Hv. simpl in Hv. destruct Hv as (ve & ? & Hv). { exists v1, v2. split_and!; first done. all: simp type_interp; simpl; done. } simp type_interp in Hv. simpl in Hv; subst ve. rewrite subst_map_empty in Hb. bs_step_det. Qed. (* c) State a free theorem for the type ∀ α, β. α → β *) Lemma free_thm_3 : ∀ f : val, TY 0; ∅ ⊢ f : (∀: ∀: #1 → #0) → False. Proof. intros f [Htycl Hty]%sem_soundness. specialize (Hty ∅ δ_any). simp type_interp in Hty. destruct Hty as (v & Hb & Hv). { constructor. } simp type_interp in Hv. destruct Hv as (? & -> & ? & Hv). specialize_sem_type Hv with (λ v, v = #0) as τ1. { naive_solver. } simp type_interp in Hv. destruct Hv as (? & ? & Hv). simp type_interp in Hv. destruct Hv as (? & -> & ? & Hv). specialize_sem_type Hv with (λ v, False) as τ2. { naive_solver. } simp type_interp in Hv. destruct Hv as (? & ? & Hv). simp type_interp in Hv. destruct Hv as (? & ? & -> & ? & Hv). specialize (Hv #0). simp type_interp in Hv. simpl in Hv. destruct Hv as (ve & ? & Hv). { done. } (* Oh no! *) simp type_interp in Hv. simpl in Hv. done. Qed. (** Exercise 5 (LN Exercise 28): Free Theorems II *) Lemma free_theorem_either : ∀ f : val, TY 0; ∅ ⊢ f : (∀: #0 → #0 → #0) → ∀ (v1 v2 : val), is_closed [] v1 → is_closed [] v2 → big_step (f <> v1 v2) v1 ∨ big_step (f <> v1 v2) v2. Proof. intros f [Htycl Hty]%sem_soundness v1 v2 Hcl1 Hcl2. specialize (Hty ∅ δ_any). simp type_interp in Hty. destruct Hty as (v & Hb & Hv). { constructor. } simp type_interp in Hv. destruct Hv as (? & -> & ? & Hv). specialize_sem_type Hv with (λ v, v = v1 ∨ v = v2) as τ. { naive_solver. } simp type_interp in Hv. destruct Hv as (? & ? & Hv). simp type_interp in Hv. destruct Hv as (? & ? & -> & ? & Hv). specialize (Hv v1). simp type_interp in Hv. simpl in Hv. destruct Hv as (ve & ? & Hv). { by left. } simp type_interp in Hv. destruct Hv as (? & ? & -> & ? & Hv). specialize (Hv v2). simp type_interp in Hv. simpl in Hv. destruct Hv as (ve & ? & Hv). { by right. } simp type_interp in Hv. simpl in Hv. rewrite subst_map_empty in Hb. destruct Hv as [-> | ->]; [left | right]; bs_step_det. Qed. (** Exercise 6 (LN Exercise 29): Free Theorems III *) (* Hint: you might want to use the fact that our reduction is deterministic. *) Lemma big_step_det e v1 v2 : big_step e v1 → big_step e v2 → v1 = v2. Proof. induction 1 in v2 |-*; inversion 1; subst; eauto 2. all: naive_solver. Qed. Lemma free_theorems_magic : ∀ (A A1 A2 : type) (f g : val), type_wf 0 A → type_wf 0 A1 → type_wf 0 A2 → is_closed [] f → is_closed [] g → TY 0; ∅ ⊢ f : (∀: (A1 → A2 → #0) → #0) → TY 0; ∅ ⊢ g : (A1 → A2 → A) → ∀ v, big_step (f <> g) v → ∃ (v1 v2 : val), big_step (g v1 v2) v. Proof. (* Hint: you may find the following lemmas useful: - [sem_val_rel_cons] - [type_wf_closed] - [val_rel_is_closed] - [big_step_preserve_closed] *) intros A A1 A2 f g HwfA HwfA1 HwfA2 Hclf Hclg [Htyfcl Htyf]%sem_soundness [Htygcl Htyg]%sem_soundness v Hb. specialize (Htyf ∅ δ_any). simp type_interp in Htyf. destruct Htyf as (vf & Hbf & Hvf). { constructor. } specialize (Htyg ∅ δ_any). simp type_interp in Htyg. destruct Htyg as (vg & Hbg & Hvg). { constructor. } rewrite subst_map_empty in Hbf. rewrite subst_map_empty in Hbg. apply big_step_val in Hbf. apply big_step_val in Hbg. subst vf vg. (* if we know that big_step is deterministic *) (* We pick the interpretation [(λ v, ∃ v1 v2, big_step (g v1 v2) v)]. Then we can equate the existential we get from Hvf with v, since big step is deterministic. We need to show that g satisfies this interpretation. For that, we already get v1: A1, v2:A2. So we use the Hvg fact to get a : A with g v1 v2 ↓ a. With that we can show the semantic interpretation. *) simp type_interp in Hvf. destruct Hvf as (ef & -> & ? & Hvf). specialize_sem_type Hvf with (λ v, ∃ (v1 v2 : val), is_closed [] v1 ∧ is_closed [] v2 ∧ big_step (g v1 v2) v) as τ. { intros v' (v1 & v2 & ? & ? & Hb'). eapply big_step_preserve_closed. 2: apply Hb'. simpl. rewrite !andb_True. done. } simp type_interp in Hvf. destruct Hvf as (ve & ? & Hvf). simp type_interp in Hvf. destruct Hvf as (? & ef' & -> & ? & Hvf). specialize (Hvf g). simp type_interp in Hvf. destruct Hvf as (ve2 & Hbe2 & Hvf). { simp type_interp in Hvg. destruct Hvg as (xg0 & eg0 & -> & ? & Hvg). eexists _, _. split_and!; [done | done | ]. intros v1 Hv1. specialize (Hvg v1). simp type_interp in Hvg. destruct Hvg as (? & ? & Hvg). { eapply sem_val_rel_cons. rewrite type_wf_closed; done. } simp type_interp in Hvg. destruct Hvg as (xg1 & eg1 & -> & ? & Hvg). simp type_interp. eexists _. split; first done. simp type_interp. eexists _, _. split_and!; [done | done | ]. intros v2 Hv2. specialize (Hvg v2). simp type_interp in Hvg. destruct Hvg as (? & ? & Hvg). { eapply sem_val_rel_cons. rewrite type_wf_closed; done. } simp type_interp. eexists. split; first done. simp type_interp. simpl. exists v1, v2. split_and!. - eapply val_rel_closed; done. - eapply val_rel_closed; done. - bs_step_det. } simp type_interp in Hvf. simpl in Hvf. destruct Hvf as (v1 & v2 & ? & ? & Hbs). exists v1, v2. assert (ve2 = v) as ->; last done. eapply big_step_det; last apply Hb. bs_step_det. Qed. End free_theorems.