Theory Stream

section ‹Stream Iterators›

theory Stream
imports LazyList
begin

subsection ‹Type definitions for streams›

text ‹Note that everything is strict in the state type.›

domain ('a,'s) Step = Done | Skip 's | Yield (lazy 'a) 's

type_synonym ('a, 's) Stepper = "'s → ('a, 's) Step"

domain ('a,'s) Stream = Stream (lazy "('a, 's) Stepper") 's


subsection ‹Converting from streams to lists›

fixrec
  unfold :: "('a, 's) Stepper -> ('s -> 'a LList)"
where
  "unfold⋅h⋅⊥ = ⊥"
| "s ≠ ⊥ ⟹
    unfold⋅h⋅s =
      (case h⋅s of
        Done ⇒ LNil
      | Skip⋅s' ⇒ unfold⋅h⋅s'
      | Yield⋅x⋅s' ⇒ LCons⋅x⋅(unfold⋅h⋅s'))"

fixrec
  unfoldF :: "('a, 's) Stepper → ('s → 'a LList) → ('s → 'a LList)"
where
  "unfoldF⋅h⋅u⋅⊥ = ⊥"
| "s ≠ ⊥ ⟹
    unfoldF⋅h⋅u⋅s =
      (case h⋅s of
        Done ⇒ LNil
      | Skip⋅s' ⇒ u⋅s'
      | Yield⋅x⋅s' ⇒ LCons⋅x⋅(u⋅s'))"

lemma unfold_eq_fix: "unfold⋅h = fix⋅(unfoldF⋅h)"
proof (rule below_antisym)
  show "unfold⋅h ⊑ fix⋅(unfoldF⋅h)"
    apply (rule unfold.induct, simp, simp)
    apply (subst fix_eq)
    apply (rule cfun_belowI, rename_tac s)
    apply (case_tac "s = ⊥", simp, simp)
    apply (intro monofun_cfun monofun_LAM below_refl, simp_all)
    done
  show "fix⋅(unfoldF⋅h) ⊑ unfold⋅h"
    apply (rule fix_ind, simp, simp)
    apply (subst unfold.unfold)
    apply (rule cfun_belowI, rename_tac s)
    apply (case_tac "s = ⊥", simp, simp)
    apply (intro monofun_cfun monofun_LAM below_refl, simp_all)
    done
qed

lemma unfold_ind:
    fixes P :: "('s → 'a LList) ⇒ bool"
    assumes "adm P" and "P ⊥" and "⋀u. P u ⟹ P (unfoldF⋅h⋅u)"
    shows "P (unfold⋅h)"
unfolding unfold_eq_fix by (rule fix_ind [of P, OF assms])

fixrec
  unfold2 :: "('s → 'a LList) → ('a, 's) Step → 'a LList"
where
  "unfold2⋅u⋅Done = LNil"
| "s ≠ ⊥ ⟹ unfold2⋅u⋅(Skip⋅s) = u⋅s"
| "s ≠ ⊥ ⟹ unfold2⋅u⋅(Yield⋅x⋅s) = LCons⋅x⋅(u⋅s)"

lemma unfold2_strict [simp]: "unfold2⋅u⋅⊥ = ⊥"
by fixrec_simp

lemma unfold: "s ≠ ⊥ ⟹ unfold⋅h⋅s = unfold2⋅(unfold⋅h)⋅(h⋅s)"
by (case_tac "h⋅s", simp_all)

lemma unfoldF: "s ≠ ⊥ ⟹ unfoldF⋅h⋅u⋅s = unfold2⋅u⋅(h⋅s)"
by (case_tac "h⋅s", simp_all)

declare unfold.simps(2) [simp del]
declare unfoldF.simps(2) [simp del]
declare unfoldF [simp]

fixrec
  unstream :: "('a, 's) Stream → 'a LList"
where
  "s ≠ ⊥ ⟹ unstream⋅(Stream⋅h⋅s) = unfold⋅h⋅s"

lemma unstream_strict [simp]: "unstream⋅⊥ = ⊥"
by fixrec_simp


subsection ‹Converting from lists to streams›

fixrec
  streamStep :: "('a LList)⊥ → ('a, ('a LList)⊥) Step"
where
  "streamStep⋅(up⋅LNil) = Done"
| "streamStep⋅(up⋅(LCons⋅x⋅xs)) = Yield⋅x⋅(up⋅xs)"

lemma streamStep_strict [simp]: "streamStep⋅(up⋅⊥) = ⊥"
by fixrec_simp

fixrec
  stream :: "'a LList → ('a, ('a LList)⊥) Stream"
where
  "stream⋅xs = Stream⋅streamStep⋅(up⋅xs)"

lemma stream_defined [simp]: "stream⋅xs ≠ ⊥"
  by simp

lemma unstream_stream [simp]:
  fixes xs :: "'a LList"
  shows "unstream⋅(stream⋅xs) = xs"
by (induct xs, simp_all add: unfold)

declare stream.simps [simp del]


subsection ‹Bisimilarity relation on streams›

definition
  bisimilar :: "('a, 's) Stream ⇒ ('a, 't) Stream ⇒ bool" (infix ‹≈› 50)
where
  "a ≈ b ⟷ unstream⋅a = unstream⋅b ∧ a ≠ ⊥ ∧ b ≠ ⊥"

lemma unstream_cong:
  "a ≈ b ⟹ unstream⋅a = unstream⋅b"
    unfolding bisimilar_def by simp

lemma stream_cong:
  "xs = ys ⟹ stream⋅xs ≈ stream⋅ys"
    unfolding bisimilar_def by simp

lemma stream_unstream_cong:
  "a ≈ b ⟹ stream⋅(unstream⋅a) ≈ b"
    unfolding bisimilar_def by simp

end