/- Lecture 02 Exercises -/ -- Recall the definition of `list`. #print inductive list namespace exercises2 def length {a : Type} : list a → nat | [] := 0 | (x :: xs) := nat.succ (length xs) . /-- Add one list to the end of another. -/ def app {a : Type} : list a → list a → list a | [] l2 := l2 | (x :: xs) l2 := x :: (app xs l2) theorem app_nil: forall {a : Type} (l : list a), app l [] = l := begin admit -- TODO end theorem app_assoc: forall {a : Type} (l1 l2 l3: list a), app (app l1 l2) l3 = app l1 (app l2 l3) := begin intros; induction l1 ; { simp [app, *] at * } end /-- Simple but inefficient way to reverse a list. -/ def rev {α : Type} : list α → list α | [] := [] | (x :: xs) := app (rev xs) [x] /-- Tail recursion is faster, but more complicated. -/ def fast_rev_aux {a : Type} : list a → list a → list a | [] acc := acc | (x :: xs) acc := fast_rev_aux xs (x :: acc) def fast_rev {a : Type} (l : list a) : list a := fast_rev_aux l [] /-- Add an element to the end of a list. -/ def snoc {a : Type} : list a → a → list a | [] x := x :: [] | (y :: ys) x := y :: (snoc ys x) theorem snoc_app_singleton: forall A (l: list A) (x: A), snoc l x = app l [x] := begin -- (** TODO *) admit end theorem app_snoc_l: forall {a : Type} (l1 l2 : list a) (x : a), app (snoc l1 x) l2 = app l1 (x :: l2) := begin -- (** TODO *) admit end theorem app_snoc_r: forall A (l1: list A) (l2: list A) (x: A), app l1 (snoc l2 x) = snoc (app l1 l2) x := begin -- (** TODO *) admit end /-- Simple but inefficient way to reverse a list. -/ def rev_snoc {a : Type} : list a → list a | [] := [] | (x :: xs) := snoc (rev_snoc xs) x lemma fast_rev_ok_snoc: forall a (l: list a), fast_rev l = rev_snoc l := begin -- (** TODO -- you will need to define a helper -- very similar to how we proved fast_ref_ok *) admit end /-- Useful in proving rev_length below. -/ lemma plus_1_S: forall (n : nat), n + 1 = nat.succ n := begin intros, induction n, { simp }, { simp * at * } end lemma rev_length: forall (a : Type) (l : list a), length (rev l) = length l := begin admit -- (** TODO -- you will need to define a helper -- that relates length and app *) end lemma rev_involutive: forall A (l: list A), rev (rev l) = l := begin -- (** TODO -- you will need to define a helper -- that relates rev and app, its proof should -- use app_assoc *) admit end /- Solutions Below -/ namespace solutions theorem app_nil: forall {a : Type} (l : list a), app l [] = l := begin intros, induction l, { simp [app] }, { simp [app, *] } end theorem snoc_app_singleton: forall {a : Type} (l: list a) (x: a), snoc l x = app l [x] := begin intros, induction l, { simp [snoc, app] }, { simp [snoc, app, *] }, end theorem app_snoc_l: forall {a : Type} (l1 l2 : list a) (x : a), app (snoc l1 x) l2 = app l1 (x :: l2) := begin intros, induction l1, { simp [snoc, app] }, { simp [snoc, app, *] }, end theorem app_snoc_r: forall A (l1: list A) (l2: list A) (x: A), app l1 (snoc l2 x) = snoc (app l1 l2) x := begin intros, induction l1, { simp [app, snoc] }, { simp [app, snoc, *] }, end lemma fast_rev_ok_snoc: forall a (l: list a), fast_rev l = rev_snoc l := begin intros, induction l, { simp [fast_rev, fast_rev_aux, rev_snoc], }, { simp [fast_rev, fast_rev_aux, rev_snoc], admit } end lemma length_app : forall (a : Type) (l1 l2 : list a), length (app l1 l2) = length l1 + length l2 := begin intros, induction l1; { simp [app, length, *] } end lemma rev_length: forall (a : Type) (l : list a), length (rev l) = length l := begin intros, induction l, { simp [length, rev] }, { simp [rev, length_app, length, *], } end lemma rev_app_singleton : forall (t : Type) (a : t) (l1 l2 : list t), rev (app l1 l2) = app (rev l2) (rev l1) := begin intros, induction l1, { simp [rev, app, app_nil] }, { simp [app, rev, ih_1, app_assoc] } end lemma rev_involutive: forall a (l: list a), rev (rev l) = l := begin intros, induction l, { simp [rev] }, { simp [rev], rw rev_app_singleton, rw ih_1, simp [rev, app], exact a_1 } end end solutions end exercises2