lean4-htt/library/data/stream.lean

625 lines
21 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
-/
open nat function option
universe variables u v w
def stream (α : Type u) := nat → α
namespace stream
variables {α : Type u} {β : Type v} {δ : Type w}
def cons (a : α) (s : stream α) : stream α :=
λ i,
match i with
| 0 := a
| succ n := s n
end
notation h :: t := cons h t
@[reducible] def head (s : stream α) : α :=
s 0
def tail (s : stream α) : stream α :=
λ i, s (i+1)
def drop (n : nat) (s : stream α) : stream α :=
λ i, s (i+n)
@[reducible] def nth (n : nat) (s : stream α) : α :=
s n
protected lemma eta (s : stream α) : head s :: tail s = s :=
funext (λ i, begin cases i, repeat {reflexivity} end)
lemma nth_zero_cons (a : α) (s : stream α) : nth 0 (a :: s) = a :=
rfl
lemma head_cons (a : α) (s : stream α) : head (a :: s) = a :=
rfl
lemma tail_cons (a : α) (s : stream α) : tail (a :: s) = s :=
rfl
lemma tail_drop (n : nat) (s : stream α) : tail (drop n s) = drop n (tail s) :=
funext (λ i, begin unfold tail drop, simp end)
lemma nth_drop (n m : nat) (s : stream α) : nth n (drop m s) = nth (n+m) s :=
rfl
lemma tail_eq_drop (s : stream α) : tail s = drop 1 s :=
rfl
lemma drop_drop (n m : nat) (s : stream α) : drop n (drop m s) = drop (n+m) s :=
funext (λ i, begin unfold drop, rw add_assoc end)
lemma nth_succ (n : nat) (s : stream α) : nth (succ n) s = nth n (tail s) :=
rfl
lemma drop_succ (n : nat) (s : stream α) : drop (succ n) s = drop n (tail s) :=
rfl
protected lemma ext {s₁ s₂ : stream α} : (∀ n, nth n s₁ = nth n s₂) → s₁ = s₂ :=
assume h, funext h
def all (p : α → Prop) (s : stream α) := ∀ n, p (nth n s)
def any (p : α → Prop) (s : stream α) := ∃ n, p (nth n s)
lemma all_def (p : α → Prop) (s : stream α) : all p s = ∀ n, p (nth n s) :=
rfl
lemma any_def (p : α → Prop) (s : stream α) : any p s = ∃ n, p (nth n s) :=
rfl
protected def mem (a : α) (s : stream α) := any (λ b, a = b) s
instance : has_mem α (stream α) :=
⟨stream.mem⟩
lemma mem_cons (a : α) (s : stream α) : a ∈ (a::s) :=
exists.intro 0 rfl
lemma mem_cons_of_mem {a : α} {s : stream α} (b : α) : a ∈ s → a ∈ b :: s :=
assume ⟨n, h⟩,
exists.intro (succ n) (by rw [nth_succ, tail_cons, h])
lemma eq_or_mem_of_mem_cons {a b : α} {s : stream α} : a ∈ b::s → a = b a ∈ s :=
assume ⟨n, h⟩,
begin
cases n with n',
{left, exact h},
{right, rw [nth_succ, tail_cons] at h, exact ⟨n', h⟩}
end
lemma mem_of_nth_eq {n : nat} {s : stream α} {a : α} : a = nth n s → a ∈ s :=
assume h, exists.intro n h
section map
variable (f : α → β)
def map (s : stream α) : stream β :=
λ n, f (nth n s)
lemma drop_map (n : nat) (s : stream α) : drop n (map f s) = map f (drop n s) :=
stream.ext (λ i, rfl)
lemma nth_map (n : nat) (s : stream α) : nth n (map f s) = f (nth n s) :=
rfl
lemma tail_map (s : stream α) : tail (map f s) = map f (tail s) :=
begin rw tail_eq_drop, reflexivity end
lemma head_map (s : stream α) : head (map f s) = f (head s) :=
rfl
lemma map_eq (s : stream α) : map f s = f (head s) :: map f (tail s) :=
by rw [-stream.eta (map f s), tail_map, head_map]
lemma map_cons (a : α) (s : stream α) : map f (a :: s) = f a :: map f s :=
begin rw [-stream.eta (map f (a :: s)), map_eq], reflexivity end
lemma map_id (s : stream α) : map id s = s :=
rfl
lemma map_map (g : β → δ) (f : α → β) (s : stream α) : map g (map f s) = map (g ∘ f) s :=
rfl
lemma mem_map {a : α} {s : stream α} : a ∈ s → f a ∈ map f s :=
assume ⟨n, h⟩,
exists.intro n (by rw [nth_map, h])
end map
section zip
variable (f : α → β → δ)
def zip (s₁ : stream α) (s₂ : stream β) : stream δ :=
λ n, f (nth n s₁) (nth n s₂)
lemma drop_zip (n : nat) (s₁ : stream α) (s₂ : stream β) : drop n (zip f s₁ s₂) = zip f (drop n s₁) (drop n s₂) :=
stream.ext (λ i, rfl)
lemma nth_zip (n : nat) (s₁ : stream α) (s₂ : stream β) : nth n (zip f s₁ s₂) = f (nth n s₁) (nth n s₂) :=
rfl
lemma head_zip (s₁ : stream α) (s₂ : stream β) : head (zip f s₁ s₂) = f (head s₁) (head s₂) :=
rfl
lemma tail_zip (s₁ : stream α) (s₂ : stream β) : tail (zip f s₁ s₂) = zip f (tail s₁) (tail s₂) :=
rfl
lemma zip_eq (s₁ : stream α) (s₂ : stream β) : zip f s₁ s₂ = f (head s₁) (head s₂) :: zip f (tail s₁) (tail s₂) :=
begin rw [-stream.eta (zip f s₁ s₂)], reflexivity end
end zip
def const (a : α) : stream α :=
λ n, a
lemma mem_const (a : α) : a ∈ const a :=
exists.intro 0 rfl
lemma const_eq (a : α) : const a = a :: const a :=
begin
apply stream.ext, intro n,
cases n, repeat {reflexivity}
end
lemma tail_const (a : α) : tail (const a) = const a :=
suffices tail (a :: const a) = const a, by rwa -const_eq at this,
rfl
lemma map_const (f : α → β) (a : α) : map f (const a) = const (f a) :=
rfl
lemma nth_const (n : nat) (a : α) : nth n (const a) = a :=
rfl
lemma drop_const (n : nat) (a : α) : drop n (const a) = const a :=
stream.ext (λ i, rfl)
def iterate (f : αα) (a : α) : stream α :=
λ n, nat.rec_on n a (λ n r, f r)
lemma head_iterate (f : αα) (a : α) : head (iterate f a) = a :=
rfl
lemma tail_iterate (f : αα) (a : α) : tail (iterate f a) = iterate f (f a) :=
begin
apply funext, intro n,
induction n with n' ih,
{reflexivity},
{unfold tail iterate,
unfold tail iterate at ih,
rw add_one_eq_succ at ih, dsimp at ih,
rw add_one_eq_succ, dsimp, rw ih}
end
lemma iterate_eq (f : αα) (a : α) : iterate f a = a :: iterate f (f a) :=
begin
rw [-stream.eta (iterate f a)],
rw tail_iterate, reflexivity
end
lemma nth_zero_iterate (f : αα) (a : α) : nth 0 (iterate f a) = a :=
rfl
lemma nth_succ_iterate (n : nat) (f : αα) (a : α) : nth (succ n) (iterate f a) = nth n (iterate f (f a)) :=
by rw [nth_succ, tail_iterate]
section bisim
variable (R : stream α → stream α → Prop)
local infix ~ := R
def is_bisimulation := ∀ ⦃s₁ s₂⦄, s₁ ~ s₂ → head s₁ = head s₂ ∧ tail s₁ ~ tail s₂
lemma nth_of_bisim (bisim : is_bisimulation R) : ∀ {s₁ s₂} n, s₁ ~ s₂ → nth n s₁ = nth n s₂ ∧ drop (n+1) s₁ ~ drop (n+1) s₂
| s₁ s₂ 0 h := bisim h
| s₁ s₂ (n+1) h :=
match bisim h with
| ⟨h₁, trel⟩ := nth_of_bisim n trel
end
-- If two streams are bisimilar, then they are equal
lemma eq_of_bisim (bisim : is_bisimulation R) : ∀ {s₁ s₂}, s₁ ~ s₂ → s₁ = s₂ :=
λ s₁ s₂ r, stream.ext (λ n, and.elim_left (nth_of_bisim R bisim n r))
end bisim
lemma bisim_simple (s₁ s₂ : stream α) : head s₁ = head s₂ → s₁ = tail s₁ → s₂ = tail s₂ → s₁ = s₂ :=
assume hh ht₁ ht₂, eq_of_bisim
(λ s₁ s₂, head s₁ = head s₂ ∧ s₁ = tail s₁ ∧ s₂ = tail s₂)
(λ s₁ s₂ ⟨h₁, h₂, h₃⟩,
begin
constructor, exact h₁, rw [-h₂, -h₃], repeat {constructor, repeat {assumption}}
end)
(and.intro hh (and.intro ht₁ ht₂))
lemma coinduction {s₁ s₂ : stream α} :
head s₁ = head s₂ → (∀ (β : Type u) (fr : stream α → β), fr s₁ = fr s₂ → fr (tail s₁) = fr (tail s₂)) → s₁ = s₂ :=
assume hh ht,
eq_of_bisim
(λ s₁ s₂, head s₁ = head s₂ ∧ ∀ (β : Type u) (fr : stream α → β), fr s₁ = fr s₂ → fr (tail s₁) = fr (tail s₂))
(λ s₁ s₂ h,
have h₁ : head s₁ = head s₂, from and.elim_left h,
have h₂ : head (tail s₁) = head (tail s₂), from and.elim_right h α (@head α) h₁,
have h₃ : ∀ (β : Type u) (fr : stream α → β), fr (tail s₁) = fr (tail s₂) → fr (tail (tail s₁)) = fr (tail (tail s₂)), from
λ β fr, and.elim_right h β (λ s, fr (tail s)),
and.intro h₁ (and.intro h₂ h₃))
(and.intro hh ht)
lemma iterate_id (a : α) : iterate id a = const a :=
coinduction
rfl
(λ β fr ch, begin rw [tail_iterate, tail_const], exact ch end)
local attribute [reducible] stream
lemma map_iterate (f : αα) (a : α) : iterate f (f a) = map f (iterate f a) :=
begin
apply funext, intro n,
induction n with n' ih,
{reflexivity},
{ unfold map iterate nth, dsimp,
unfold map iterate nth at ih, dsimp at ih,
rw ih }
end
section corec
def corec (f : α → β) (g : αα) : α → stream β :=
λ a, map f (iterate g a)
def corec_on (a : α) (f : α → β) (g : αα) : stream β :=
corec f g a
lemma corec_def (f : α → β) (g : αα) (a : α) : corec f g a = map f (iterate g a) :=
rfl
lemma corec_eq (f : α → β) (g : αα) (a : α) : corec f g a = f a :: corec f g (g a) :=
begin rw [corec_def, map_eq, head_iterate, tail_iterate], reflexivity end
lemma corec_id_id_eq_const (a : α) : corec id id a = const a :=
by rw [corec_def, map_id, iterate_id]
lemma corec_id_f_eq_iterate (f : αα) (a : α) : corec id f a = iterate f a :=
rfl
end corec
-- corec is also known as unfold
def unfolds (g : α → β) (f : αα) (a : α) : stream β :=
corec g f a
lemma unfolds_eq (g : α → β) (f : αα) (a : α) : unfolds g f a = g a :: unfolds g f (f a) :=
begin unfold unfolds, rw [corec_eq] end
lemma nth_unfolds_head_tail : ∀ (n : nat) (s : stream α), nth n (unfolds head tail s) = nth n s :=
begin
intro n, induction n with n' ih,
{intro s, reflexivity},
{intro s, rw [nth_succ, nth_succ, unfolds_eq, tail_cons, ih]}
end
lemma unfolds_head_eq : ∀ (s : stream α), unfolds head tail s = s :=
λ s, stream.ext (λ n, nth_unfolds_head_tail n s)
def interleave (s₁ s₂ : stream α) : stream α :=
corec_on (s₁, s₂)
(λ ⟨s₁, s₂⟩, head s₁)
(λ ⟨s₁, s₂⟩, (s₂, tail s₁))
infix `⋈`:65 := interleave
lemma interleave_eq (s₁ s₂ : stream α) : s₁ ⋈ s₂ = head s₁ :: head s₂ :: (tail s₁ ⋈ tail s₂) :=
begin
unfold interleave corec_on, rw corec_eq, dsimp, rw corec_eq, reflexivity
end
lemma tail_interleave (s₁ s₂ : stream α) : tail (s₁ ⋈ s₂) = s₂ ⋈ (tail s₁) :=
begin unfold interleave corec_on, rw corec_eq, reflexivity end
lemma interleave_tail_tail (s₁ s₂ : stream α) : tail s₁ ⋈ tail s₂ = tail (tail (s₁ ⋈ s₂)) :=
begin rw [interleave_eq s₁ s₂], reflexivity end
lemma nth_interleave_left : ∀ (n : nat) (s₁ s₂ : stream α), nth (2*n) (s₁ ⋈ s₂) = nth n s₁
| 0 s₁ s₂ := rfl
| (succ n) s₁ s₂ :=
begin
change nth (succ (succ (2*n))) (s₁ ⋈ s₂) = nth (succ n) s₁,
rw [nth_succ, nth_succ, interleave_eq, tail_cons, tail_cons, nth_interleave_left],
reflexivity
end
lemma nth_interleave_right : ∀ (n : nat) (s₁ s₂ : stream α), nth (2*n+1) (s₁ ⋈ s₂) = nth n s₂
| 0 s₁ s₂ := rfl
| (succ n) s₁ s₂ :=
begin
change nth (succ (succ (2*n+1))) (s₁ ⋈ s₂) = nth (succ n) s₂,
rw [nth_succ, nth_succ, interleave_eq, tail_cons, tail_cons, nth_interleave_right],
reflexivity
end
lemma mem_interleave_left {a : α} {s₁ : stream α} (s₂ : stream α) : a ∈ s₁ → a ∈ s₁ ⋈ s₂ :=
assume ⟨n, h⟩,
exists.intro (2*n) (by rw [h, nth_interleave_left])
lemma mem_interleave_right {a : α} {s₁ : stream α} (s₂ : stream α) : a ∈ s₂ → a ∈ s₁ ⋈ s₂ :=
assume ⟨n, h⟩,
exists.intro (2*n+1) (by rw [h, nth_interleave_right])
def even (s : stream α) : stream α :=
corec
(λ s, head s)
(λ s, tail (tail s))
s
def odd (s : stream α) : stream α :=
even (tail s)
lemma odd_eq (s : stream α) : odd s = even (tail s) :=
rfl
lemma head_even (s : stream α) : head (even s) = head s :=
rfl
lemma tail_even (s : stream α) : tail (even s) = even (tail (tail s)) :=
begin unfold even, rw corec_eq, reflexivity end
lemma even_cons_cons (a₁ a₂ : α) (s : stream α) : even (a₁ :: a₂ :: s) = a₁ :: even s :=
begin unfold even, rw corec_eq, reflexivity end
lemma even_tail (s : stream α) : even (tail s) = odd s :=
rfl
lemma even_interleave (s₁ s₂ : stream α) : even (s₁ ⋈ s₂) = s₁ :=
eq_of_bisim
(λ s₁' s₁, ∃ s₂, s₁' = even (s₁ ⋈ s₂))
(λ s₁' s₁ ⟨s₂, h₁⟩,
begin
rw h₁,
constructor,
{reflexivity},
{exact ⟨tail s₂, by rw [interleave_eq, even_cons_cons, tail_cons]⟩}
end)
(exists.intro s₂ rfl)
lemma interleave_even_odd (s₁ : stream α) : even s₁ ⋈ odd s₁ = s₁ :=
eq_of_bisim
(λ s' s, s' = even s ⋈ odd s)
(λ s' s (h : s' = even s ⋈ odd s),
begin
rw h, constructor,
{reflexivity},
{dsimp, rw [odd_eq, odd_eq, tail_interleave, tail_even]}
end)
rfl
lemma nth_even : ∀ (n : nat) (s : stream α), nth n (even s) = nth (2*n) s
| 0 s := rfl
| (succ n) s :=
begin
change nth (succ n) (even s) = nth (succ (succ (2 * n))) s,
rw [nth_succ, nth_succ, tail_even, nth_even], reflexivity
end
lemma nth_odd : ∀ (n : nat) (s : stream α), nth n (odd s) = nth (2*n + 1) s :=
λ n s, begin rw [odd_eq, nth_even], reflexivity end
lemma mem_of_mem_even (a : α) (s : stream α) : a ∈ even s → a ∈ s :=
assume ⟨n, h⟩,
exists.intro (2*n) (by rw [h, nth_even])
lemma mem_of_mem_odd (a : α) (s : stream α) : a ∈ odd s → a ∈ s :=
assume ⟨n, h⟩,
exists.intro (2*n+1) (by rw [h, nth_odd])
def append_stream : list α → stream α → stream α
| [] s := s
| (list.cons a l) s := a :: append_stream l s
lemma nil_append_stream (s : stream α) : append_stream [] s = s :=
rfl
lemma cons_append_stream (a : α) (l : list α) (s : stream α) : append_stream (a::l) s = a :: append_stream l s :=
rfl
infix `++ₛ`:65 := append_stream
lemma append_append_stream : ∀ (l₁ l₂ : list α) (s : stream α), (l₁ ++ l₂) ++ₛ s = l₁ ++ₛ (l₂ ++ₛ s)
| [] l₂ s := rfl
| (list.cons a l₁) l₂ s := by rw [list.cons_append, cons_append_stream, cons_append_stream, append_append_stream]
lemma map_append_stream (f : α → β) : ∀ (l : list α) (s : stream α), map f (l ++ₛ s) = list.map f l ++ₛ map f s
| [] s := rfl
| (list.cons a l) s := by rw [cons_append_stream, list.map_cons, map_cons, cons_append_stream, map_append_stream]
lemma drop_append_stream : ∀ (l : list α) (s : stream α), drop l^.length (l ++ₛ s) = s
| [] s := by reflexivity
| (list.cons a l) s := by rw [list.length_cons, add_one_eq_succ, drop_succ, cons_append_stream, tail_cons, drop_append_stream]
lemma append_stream_head_tail (s : stream α) : [head s] ++ₛ tail s = s :=
by rw [cons_append_stream, nil_append_stream, stream.eta]
lemma mem_append_stream_right : ∀ {a : α} (l : list α) {s : stream α}, a ∈ s → a ∈ l ++ₛ s
| a [] s h := h
| a (list.cons b l) s h :=
have ih : a ∈ l ++ₛ s, from mem_append_stream_right l h,
mem_cons_of_mem _ ih
lemma mem_append_stream_left : ∀ {a : α} {l : list α} (s : stream α), a ∈ l → a ∈ l ++ₛ s
| a [] s h := absurd h (list.not_mem_nil _)
| a (list.cons b l) s h :=
or.elim (list.eq_or_mem_of_mem_cons h)
(λ (aeqb : a = b), exists.intro 0 aeqb)
(λ (ainl : a ∈ l), mem_cons_of_mem b (mem_append_stream_left s ainl))
def approx : nat → stream α → list α
| 0 s := []
| (n+1) s := list.cons (head s) (approx n (tail s))
lemma approx_zero (s : stream α) : approx 0 s = [] :=
rfl
lemma approx_succ (n : nat) (s : stream α) : approx (succ n) s = head s :: approx n (tail s) :=
rfl
lemma nth_approx : ∀ (n : nat) (s : stream α), list.nth (approx (succ n) s) n = some (nth n s)
| 0 s := rfl
| (n+1) s := begin rw [approx_succ, add_one_eq_succ, list.nth_succ, nth_approx], reflexivity end
lemma append_approx_drop : ∀ (n : nat) (s : stream α), append_stream (approx n s) (drop n s) = s :=
begin
intro n,
induction n with n' ih,
{intro s, reflexivity},
{intro s, rw [approx_succ, drop_succ, cons_append_stream, ih (tail s), stream.eta]}
end
-- Take lemma reduces a proof of equality of infinite streams to an
-- induction over all their finite approximations.
lemma take_lemma (s₁ s₂ : stream α) : (∀ (n : nat), approx n s₁ = approx n s₂) → s₁ = s₂ :=
begin
intro h, apply stream.ext, intro n,
induction n with n ih,
{note aux := h 1, unfold approx at aux,
injection aux with aux, exact aux},
{assert h₁ : some (nth (succ n) s₁) = some (nth (succ n) s₂),
{rw [-nth_approx, -nth_approx, h (succ (succ n))]},
injection h₁, assumption}
end
-- auxiliary def for cycle corecursive def
private def cycle_f : α × list α × α × list αα
| (v, _, _, _) := v
-- auxiliary def for cycle corecursive def
private def cycle_g : α × list α × α × list αα × list α × α × list α
| (v₁, [], v₀, l₀) := (v₀, l₀, v₀, l₀)
| (v₁, list.cons v₂ l₂, v₀, l₀) := (v₂, l₂, v₀, l₀)
private lemma cycle_g_cons (a : α) (a₁ : α) (l₁ : list α) (a₀ : α) (l₀ : list α) :
cycle_g (a, a₁::l₁, a₀, l₀) = (a₁, l₁, a₀, l₀) :=
rfl
def cycle : Π (l : list α), l ≠ [] → stream α
| [] h := absurd rfl h
| (list.cons a l) h := corec cycle_f cycle_g (a, l, a, l)
lemma cycle_eq : ∀ (l : list α) (h : l ≠ []), cycle l h = l ++ₛ cycle l h
| [] h := absurd rfl h
| (list.cons a l) h :=
have gen : ∀ l' a', corec cycle_f cycle_g (a', l', a, l) = (a' :: l') ++ₛ corec cycle_f cycle_g (a, l, a, l),
begin
intro l',
induction l' with a₁ l₁ ih,
{intros, rw [corec_eq], reflexivity},
{intros, rw [corec_eq, cycle_g_cons, ih a₁], reflexivity}
end,
gen l a
lemma mem_cycle {a : α} {l : list α} : ∀ (h : l ≠ []), a ∈ l → a ∈ cycle l h :=
assume h ainl, begin rw [cycle_eq], exact mem_append_stream_left _ ainl end
lemma cycle_singleton (a : α) (h : [a] ≠ []) : cycle [a] h = const a :=
coinduction
rfl
(λ β fr ch, by rwa [cycle_eq, const_eq])
def tails (s : stream α) : stream (stream α) :=
corec id tail (tail s)
lemma tails_eq (s : stream α) : tails s = tail s :: tails (tail s) :=
begin unfold tails, rw [corec_eq] end
lemma nth_tails : ∀ (n : nat) (s : stream α), nth n (tails s) = drop n (tail s) :=
begin
intro n, induction n with n' ih,
{intros, reflexivity},
{intro s, rw [nth_succ, drop_succ, tails_eq, tail_cons, ih]}
end
lemma tails_eq_iterate (s : stream α) : tails s = iterate tail (tail s) :=
rfl
def inits_core (l : list α) (s : stream α) : stream (list α) :=
corec_on (l, s)
(λ ⟨a, b⟩, a)
(λ p, match p with (l', s') := (l' ++ [head s'], tail s') end)
def inits (s : stream α) : stream (list α) :=
inits_core [head s] (tail s)
lemma inits_core_eq (l : list α) (s : stream α) : inits_core l s = l :: inits_core (l ++ [head s]) (tail s) :=
begin unfold inits_core corec_on, rw [corec_eq], reflexivity end
lemma tail_inits (s : stream α) : tail (inits s) = inits_core [head s, head (tail s)] (tail (tail s)) :=
begin unfold inits, rw inits_core_eq, reflexivity end
lemma inits_tail (s : stream α) : inits (tail s) = inits_core [head (tail s)] (tail (tail s)) :=
rfl
lemma cons_nth_inits_core : ∀ (a : α) (n : nat) (l : list α) (s : stream α),
a :: nth n (inits_core l s) = nth n (inits_core (a::l) s) :=
begin
intros a n,
induction n with n' ih,
{intros, reflexivity},
{intros l s, rw [nth_succ, inits_core_eq, tail_cons, ih, inits_core_eq (a::l) s], reflexivity }
end
lemma nth_inits : ∀ (n : nat) (s : stream α), nth n (inits s) = approx (succ n) s :=
begin
intro n, induction n with n' ih,
{intros, reflexivity},
{intros, rw [nth_succ, approx_succ, -ih, tail_inits, inits_tail, cons_nth_inits_core]}
end
lemma inits_eq (s : stream α) : inits s = [head s] :: map (list.cons (head s)) (inits (tail s)) :=
begin
apply stream.ext, intro n,
cases n,
{reflexivity},
{rw [nth_inits, nth_succ, tail_cons, nth_map, nth_inits], reflexivity}
end
lemma zip_inits_tails (s : stream α) : zip append_stream (inits s) (tails s) = const s :=
begin
apply stream.ext, intro n,
rw [nth_zip, nth_inits, nth_tails, nth_const, approx_succ,
cons_append_stream, append_approx_drop, stream.eta]
end
def pure (a : α) : stream α :=
const a
def apply (f : stream (α → β)) (s : stream α) : stream β :=
λ n, (nth n f) (nth n s)
infix `⊛`:75 := apply -- input as \o*
lemma identity (s : stream α) : pure id ⊛ s = s :=
rfl
lemma composition (g : stream (β → δ)) (f : stream (α → β)) (s : stream α) : pure comp ⊛ g ⊛ f ⊛ s = g ⊛ (f ⊛ s) :=
rfl
lemma homomorphism (f : α → β) (a : α) : pure f ⊛ pure a = pure (f a) :=
rfl
lemma interchange (fs : stream (α → β)) (a : α) : fs ⊛ pure a = pure (λ f : α → β, f a) ⊛ fs :=
rfl
lemma map_eq_apply (f : α → β) (s : stream α) : map f s = pure f ⊛ s :=
rfl
def nats : stream nat :=
λ n, n
lemma nth_nats (n : nat) : nth n nats = n :=
rfl
lemma nats_eq : nats = 0 :: map succ nats :=
begin
apply stream.ext, intro n,
cases n, reflexivity, rw [nth_succ], reflexivity
end
end stream