File: Mathlib/Data/Seq/WSeq.lean

full_name: Stream'.WSeq
code: /-- Weak sequences.

  While the `Seq` structure allows for lists which may not be finite,
  a weak sequence also allows the computation of each element to
  involve an indeterminate amount of computation, including possibly
  an infinite loop. This is represented as a regular `Seq` interspersed
  with `none` elements to indicate that computation is ongoing.

  This model is appropriate for Haskell style lazy lists, and is closed
  under most interesting computation patterns on infinite lists,
  but conversely it is difficult to extract elements from it. -/
def WSeq (α) 
goal: Type u_1

full_name: Stream'.WSeq.ofSeq
code: /-- Turn a sequence into a weak sequence -/
@[coe]
def ofSeq : Seq α → WSeq α 
goal: Stream'.Seq α → Stream'.WSeq α

full_name: Stream'.WSeq.ofList
code: /-- Turn a list into a weak sequence -/
@[coe]
def ofList (l : List α) : WSeq α 
goal: Stream'.WSeq α

full_name: Stream'.WSeq.ofStream
code: /-- Turn a stream into a weak sequence -/
@[coe]
def ofStream (l : Stream' α) : WSeq α 
goal: Stream'.WSeq α

full_name: Stream'.WSeq.coeSeq
code: instance coeSeq : Coe (Seq α) (WSeq α) 
goal: Coe (Stream'.Seq α) (Stream'.WSeq α)

full_name: Stream'.WSeq.coeList
code: instance coeList : Coe (List α) (WSeq α) 
goal: Coe (List α) (Stream'.WSeq α)

full_name: Stream'.WSeq.coeStream
code: instance coeStream : Coe (Stream' α) (WSeq α) 
goal: Coe (Stream' α) (Stream'.WSeq α)

full_name: Stream'.WSeq.nil
code: /-- The empty weak sequence -/
def nil : WSeq α 
goal: Stream'.WSeq α

full_name: Stream'.WSeq.inhabited
code: instance inhabited : Inhabited (WSeq α) 
goal: Inhabited (Stream'.WSeq α)

full_name: Stream'.WSeq.cons
code: /-- Prepend an element to a weak sequence -/
def cons (a : α) : WSeq α → WSeq α 
goal: Stream'.WSeq α → Stream'.WSeq α

full_name: Stream'.WSeq.think
code: /-- Compute for one tick, without producing any elements -/
def think : WSeq α → WSeq α 
goal: Stream'.WSeq α → Stream'.WSeq α

full_name: Stream'.WSeq.destruct
code: /-- Destruct a weak sequence, to (eventually possibly) produce either
  `none` for `nil` or `some (a, s)` if an element is produced. -/
def destruct : WSeq α → Computation (Option (α × WSeq α)) 
goal: Stream'.WSeq α → Computation (Option (α × Stream'.WSeq α))

full_name: Stream'.WSeq.recOn
code: /-- Recursion principle for weak sequences, compare with `List.recOn`. -/
def recOn {C : WSeq α → Sort v} (s : WSeq α) (h1 : C nil) (h2 : ∀ x s, C (cons x s))
    (h3 : ∀ s, C (think s)) : C s 
goal: C s

full_name: Stream'.WSeq.Mem
code: /-- membership for weak sequences-/
protected def Mem (a : α) (s : WSeq α) 
goal: Prop

full_name: Stream'.WSeq.membership
code: instance membership : Membership α (WSeq α) 
goal: Membership α (Stream'.WSeq α)

full_name: Stream'.WSeq.not_mem_nil
code: theorem not_mem_nil (a : α) : a ∉ @nil α 
goal: ¬a ∈ Stream'.WSeq.nil

full_name: Stream'.WSeq.head
code: /-- Get the head of a weak sequence. This involves a possibly
  infinite computation. -/
def head (s : WSeq α) : Computation (Option α) 
goal: Computation (Option α)

full_name: Stream'.WSeq.flatten
code: /-- Encode a computation yielding a weak sequence into additional
  `think` constructors in a weak sequence -/
def flatten : Computation (WSeq α) → WSeq α 
goal: Computation (Stream'.WSeq α) → Stream'.WSeq α

full_name: Stream'.WSeq.tail
code: /-- Get the tail of a weak sequence. This doesn't need a `Computation`
  wrapper, unlike `head`, because `flatten` allows us to hide this
  in the construction of the weak sequence itself. -/
def tail (s : WSeq α) : WSeq α 
goal: Stream'.WSeq α

full_name: Stream'.WSeq.drop
code: /-- drop the first `n` elements from `s`. -/
def drop (s : WSeq α) : ℕ → WSeq α
  
goal: ℕ → Stream'.WSeq α

full_name: Stream'.WSeq.get?
code: /-- Get the nth element of `s`. -/
def get? (s : WSeq α) (n : ℕ) : Computation (Option α) 
goal: Computation (Option α)

full_name: Stream'.WSeq.toList
code: /-- Convert `s` to a list (if it is finite and completes in finite time). -/
def toList (s : WSeq α) : Computation (List α) 
goal: Computation (List α)

full_name: Stream'.WSeq.length
code: /-- Get the length of `s` (if it is finite and completes in finite time). -/
def length (s : WSeq α) : Computation ℕ 
goal: Computation ℕ

full_name: Stream'.WSeq.IsFinite
code: /-- A weak sequence is finite if `toList s` terminates. Equivalently,
  it is a finite number of `think` and `cons` applied to `nil`. -/
class IsFinite (s : WSeq α) : Prop where
  out : (toList s).Terminates
goal: Prop

full_name: Stream'.WSeq.IsFinite.out
code: /-- A weak sequence is finite if `toList s` terminates. Equivalently,
  it is a finite number of `think` and `cons` applied to `nil`. -/
class IsFinite (s : WSeq α) : Prop where
  out : (toList s).Terminates
goal: s.toList.Terminates

full_name: Stream'.WSeq.toList_terminates
code: instance toList_terminates (s : WSeq α) [h : IsFinite s] : (toList s).Terminates 
goal: s.toList.Terminates

full_name: Stream'.WSeq.get
code: /-- Get the list corresponding to a finite weak sequence. -/
def get (s : WSeq α) [IsFinite s] : List α 
goal: List α

full_name: Stream'.WSeq.Productive
code: /-- A weak sequence is *productive* if it never stalls forever - there are
 always a finite number of `think`s between `cons` constructors.
 The sequence itself is allowed to be infinite though. -/
class Productive (s : WSeq α) : Prop where
  get?_terminates : ∀ n, (get? s n).Terminates
goal: Prop

full_name: Stream'.WSeq.Productive.get?_terminates
code: /-- A weak sequence is *productive* if it never stalls forever - there are
 always a finite number of `think`s between `cons` constructors.
 The sequence itself is allowed to be infinite though. -/
class Productive (s : WSeq α) : Prop where
  get?_terminates : ∀ n, (get? s n).Terminates
goal: (s.get? n).Terminates

full_name: Stream'.WSeq.productive_iff
code: theorem productive_iff (s : WSeq α) : Productive s ↔ ∀ n, (get? s n).Terminates 
goal: s.Productive ↔ ∀ (n : ℕ), (s.get? n).Terminates

full_name: Stream'.WSeq.get?_terminates
code: instance get?_terminates (s : WSeq α) [h : Productive s] : ∀ n, (get? s n).Terminates 
goal: (s.get? n).Terminates

full_name: Stream'.WSeq.head_terminates
code: instance head_terminates (s : WSeq α) [Productive s] : (head s).Terminates 
goal: s.head.Terminates

full_name: Stream'.WSeq.updateNth
code: /-- Replace the `n`th element of `s` with `a`. -/
def updateNth (s : WSeq α) (n : ℕ) (a : α) : WSeq α 
goal: Stream'.WSeq α

full_name: Stream'.WSeq.removeNth
code: /-- Remove the `n`th element of `s`. -/
def removeNth (s : WSeq α) (n : ℕ) : WSeq α 
goal: Stream'.WSeq α

full_name: Stream'.WSeq.filterMap
code: /-- Map the elements of `s` over `f`, removing any values that yield `none`. -/
def filterMap (f : α → Option β) : WSeq α → WSeq β 
goal: Stream'.WSeq α → Stream'.WSeq β

full_name: Stream'.WSeq.filter
code: /-- Select the elements of `s` that satisfy `p`. -/
def filter (p : α → Prop) [DecidablePred p] : WSeq α → WSeq α 
goal: Stream'.WSeq α → Stream'.WSeq α

full_name: Stream'.WSeq.find
code: /-- Get the first element of `s` satisfying `p`. -/
def find (p : α → Prop) [DecidablePred p] (s : WSeq α) : Computation (Option α) 
goal: Computation (Option α)

full_name: Stream'.WSeq.zipWith
code: /-- Zip a function over two weak sequences -/
def zipWith (f : α → β → γ) (s1 : WSeq α) (s2 : WSeq β) : WSeq γ 
goal: Stream'.WSeq γ

full_name: Stream'.WSeq.zip
code: /-- Zip two weak sequences into a single sequence of pairs -/
def zip : WSeq α → WSeq β → WSeq (α × β) 
goal: Stream'.WSeq α → Stream'.WSeq β → Stream'.WSeq (α × β)

full_name: Stream'.WSeq.findIndexes
code: /-- Get the list of indexes of elements of `s` satisfying `p` -/
def findIndexes (p : α → Prop) [DecidablePred p] (s : WSeq α) : WSeq ℕ 
goal: Stream'.WSeq ℕ

full_name: Stream'.WSeq.findIndex
code: /-- Get the index of the first element of `s` satisfying `p` -/
def findIndex (p : α → Prop) [DecidablePred p] (s : WSeq α) : Computation ℕ 
goal: Computation ℕ

full_name: Stream'.WSeq.indexOf
code: /-- Get the index of the first occurrence of `a` in `s` -/
def indexOf [DecidableEq α] (a : α) : WSeq α → Computation ℕ 
goal: Stream'.WSeq α → Computation ℕ

full_name: Stream'.WSeq.indexesOf
code: /-- Get the indexes of occurrences of `a` in `s` -/
def indexesOf [DecidableEq α] (a : α) : WSeq α → WSeq ℕ 
goal: Stream'.WSeq α → Stream'.WSeq ℕ

full_name: Stream'.WSeq.union
code: /-- `union s1 s2` is a weak sequence which interleaves `s1` and `s2` in
  some order (nondeterministically). -/
def union (s1 s2 : WSeq α) : WSeq α 
goal: Stream'.WSeq α

full_name: Stream'.WSeq.isEmpty
code: /-- Returns `true` if `s` is `nil` and `false` if `s` has an element -/
def isEmpty (s : WSeq α) : Computation Bool 
goal: Computation Bool

full_name: Stream'.WSeq.compute
code: /-- Calculate one step of computation -/
def compute (s : WSeq α) : WSeq α 
goal: Stream'.WSeq α

full_name: Stream'.WSeq.take
code: /-- Get the first `n` elements of a weak sequence -/
def take (s : WSeq α) (n : ℕ) : WSeq α 
goal: Stream'.WSeq α

full_name: Stream'.WSeq.splitAt
code: /-- Split the sequence at position `n` into a finite initial segment
  and the weak sequence tail -/
def splitAt (s : WSeq α) (n : ℕ) : Computation (List α × WSeq α) 
goal: Computation (List α × Stream'.WSeq α)

full_name: Stream'.WSeq.any
code: /-- Returns `true` if any element of `s` satisfies `p` -/
def any (s : WSeq α) (p : α → Bool) : Computation Bool 
goal: Computation Bool

full_name: Stream'.WSeq.all
code: /-- Returns `true` if every element of `s` satisfies `p` -/
def all (s : WSeq α) (p : α → Bool) : Computation Bool 
goal: Computation Bool

full_name: Stream'.WSeq.scanl
code: /-- Apply a function to the elements of the sequence to produce a sequence
  of partial results. (There is no `scanr` because this would require
  working from the end of the sequence, which may not exist.) -/
def scanl (f : α → β → α) (a : α) (s : WSeq β) : WSeq α 
goal: Stream'.WSeq α

full_name: Stream'.WSeq.inits
code: /-- Get the weak sequence of initial segments of the input sequence -/
def inits (s : WSeq α) : WSeq (List α) 
goal: Stream'.WSeq (List α)

full_name: Stream'.WSeq.collect
code: /-- Like take, but does not wait for a result. Calculates `n` steps of
  computation and returns the sequence computed so far -/
def collect (s : WSeq α) (n : ℕ) : List α 
goal: List α

full_name: Stream'.WSeq.append
code: /-- Append two weak sequences. As with `Seq.append`, this may not use
  the second sequence if the first one takes forever to compute -/
def append : WSeq α → WSeq α → WSeq α 
goal: Stream'.WSeq α → Stream'.WSeq α → Stream'.WSeq α

full_name: Stream'.WSeq.map
code: /-- Map a function over a weak sequence -/
def map (f : α → β) : WSeq α → WSeq β 
goal: Stream'.WSeq α → Stream'.WSeq β

full_name: Stream'.WSeq.join
code: /-- Flatten a sequence of weak sequences. (Note that this allows
  empty sequences, unlike `Seq.join`.) -/
def join (S : WSeq (WSeq α)) : WSeq α 
goal: Stream'.WSeq α

full_name: Stream'.WSeq.bind
code: /-- Monadic bind operator for weak sequences -/
def bind (s : WSeq α) (f : α → WSeq β) : WSeq β 
goal: Stream'.WSeq β

full_name: Stream'.WSeq.LiftRelO
code: /-- lift a relation to a relation over weak sequences -/
@[simp]
def LiftRelO (R : α → β → Prop) (C : WSeq α → WSeq β → Prop) :
    Option (α × WSeq α) → Option (β × WSeq β) → Prop
  
goal: Option (α × Stream'.WSeq α) → Option (β × Stream'.WSeq β) → Prop

full_name: Stream'.WSeq.LiftRelO.imp
code: theorem LiftRelO.imp {R S : α → β → Prop} {C D : WSeq α → WSeq β → Prop} (H1 : ∀ a b, R a b → S a b)
    (H2 : ∀ s t, C s t → D s t) : ∀ {o p}, LiftRelO R C o p → LiftRelO S D o p
  
goal: Stream'.WSeq.LiftRelO R C o p → Stream'.WSeq.LiftRelO S D o p

full_name: Stream'.WSeq.LiftRelO.imp_right
code: theorem LiftRelO.imp_right (R : α → β → Prop) {C D : WSeq α → WSeq β → Prop}
    (H : ∀ s t, C s t → D s t) {o p} : LiftRelO R C o p → LiftRelO R D o p 
goal: Stream'.WSeq.LiftRelO R C o p → Stream'.WSeq.LiftRelO R D o p

full_name: Stream'.WSeq.BisimO
code: /-- Definition of bisimilarity for weak sequences-/
@[simp]
def BisimO (R : WSeq α → WSeq α → Prop) : Option (α × WSeq α) → Option (α × WSeq α) → Prop 
goal: Option (α × Stream'.WSeq α) → Option (α × Stream'.WSeq α) → Prop

full_name: Stream'.WSeq.BisimO.imp
code: theorem BisimO.imp {R S : WSeq α → WSeq α → Prop} (H : ∀ s t, R s t → S s t) {o p} :
    BisimO R o p → BisimO S o p 
goal: Stream'.WSeq.BisimO R o p → Stream'.WSeq.BisimO S o p

full_name: Stream'.WSeq.LiftRel
code: /-- Two weak sequences are `LiftRel R` related if they are either both empty,
  or they are both nonempty and the heads are `R` related and the tails are
  `LiftRel R` related. (This is a coinductive definition.) -/
def LiftRel (R : α → β → Prop) (s : WSeq α) (t : WSeq β) : Prop 
goal: Prop

full_name: Stream'.WSeq.Equiv
code: /-- If two sequences are equivalent, then they have the same values and
  the same computational behavior (i.e. if one loops forever then so does
  the other), although they may differ in the number of `think`s needed to
  arrive at the answer. -/
def Equiv : WSeq α → WSeq α → Prop 
goal: Stream'.WSeq α → Stream'.WSeq α → Prop

full_name: Stream'.WSeq.liftRel_destruct
code: theorem liftRel_destruct {R : α → β → Prop} {s : WSeq α} {t : WSeq β} :
    LiftRel R s t → Computation.LiftRel (LiftRelO R (LiftRel R)) (destruct s) (destruct t)
  
goal: Stream'.WSeq.LiftRel R s t →
  Computation.LiftRel (Stream'.WSeq.LiftRelO R (Stream'.WSeq.LiftRel R)) s.destruct t.destruct

full_name: Stream'.WSeq.liftRel_destruct_iff
code: theorem liftRel_destruct_iff {R : α → β → Prop} {s : WSeq α} {t : WSeq β} :
    LiftRel R s t ↔ Computation.LiftRel (LiftRelO R (LiftRel R)) (destruct s) (destruct t) 
goal: Stream'.WSeq.LiftRel R s t ↔
  Computation.LiftRel (Stream'.WSeq.LiftRelO R (Stream'.WSeq.LiftRel R)) s.destruct t.destruct

full_name: Stream'.WSeq.«_aux_Mathlib_Data_Seq_WSeq___macroRules_Stream'_WSeq_term_~ʷ__1»
code: infixl:50 " ~ʷ " => Equiv
goal: Lean.Macro

full_name: Stream'.WSeq._aux_Mathlib_Data_Seq_WSeq___unexpand_Stream'_WSeq_Equiv_1
code: infixl:50 " ~ʷ " => Equiv
goal: Lean.PrettyPrinter.Unexpander

full_name: Stream'.WSeq.destruct_congr
code: theorem destruct_congr {s t : WSeq α} :
    s ~ʷ t → Computation.LiftRel (BisimO (· ~ʷ ·)) (destruct s) (destruct t) 
goal: s ~ʷ t → Computation.LiftRel (Stream'.WSeq.BisimO fun x x_1 => x ~ʷ x_1) s.destruct t.destruct

full_name: Stream'.WSeq.destruct_congr_iff
code: theorem destruct_congr_iff {s t : WSeq α} :
    s ~ʷ t ↔ Computation.LiftRel (BisimO (· ~ʷ ·)) (destruct s) (destruct t) 
goal: s ~ʷ t ↔ Computation.LiftRel (Stream'.WSeq.BisimO fun x x_1 => x ~ʷ x_1) s.destruct t.destruct

full_name: Stream'.WSeq.LiftRel.refl
code: theorem LiftRel.refl (R : α → α → Prop) (H : Reflexive R) : Reflexive (LiftRel R) 
goal: Reflexive (Stream'.WSeq.LiftRel R)

full_name: Stream'.WSeq.LiftRelO.swap
code: theorem LiftRelO.swap (R : α → β → Prop) (C) :
    swap (LiftRelO R C) = LiftRelO (swap R) (swap C) 
goal: Function.swap (Stream'.WSeq.LiftRelO R C) = Stream'.WSeq.LiftRelO (Function.swap R) (Function.swap C)

full_name: Stream'.WSeq.LiftRel.swap_lem
code: theorem LiftRel.swap_lem {R : α → β → Prop} {s1 s2} (h : LiftRel R s1 s2) :
    LiftRel (swap R) s2 s1 
goal: Stream'.WSeq.LiftRel (Function.swap R) s2 s1

full_name: Stream'.WSeq.LiftRel.swap
code: theorem LiftRel.swap (R : α → β → Prop) : swap (LiftRel R) = LiftRel (swap R) 
goal: Function.swap (Stream'.WSeq.LiftRel R) = Stream'.WSeq.LiftRel (Function.swap R)

full_name: Stream'.WSeq.LiftRel.symm
code: theorem LiftRel.symm (R : α → α → Prop) (H : Symmetric R) : Symmetric (LiftRel R) 
goal: Symmetric (Stream'.WSeq.LiftRel R)

full_name: Stream'.WSeq.LiftRel.trans
code: theorem LiftRel.trans (R : α → α → Prop) (H : Transitive R) : Transitive (LiftRel R) 
goal: Transitive (Stream'.WSeq.LiftRel R)

full_name: Stream'.WSeq.LiftRel.equiv
code: theorem LiftRel.equiv (R : α → α → Prop) : Equivalence R → Equivalence (LiftRel R)
  
goal: Equivalence R → Equivalence (Stream'.WSeq.LiftRel R)

full_name: Stream'.WSeq.Equiv.refl
code: @[refl]
theorem Equiv.refl : ∀ s : WSeq α, s ~ʷ s 
goal: s ~ʷ s

full_name: Stream'.WSeq.Equiv.symm
code: @[symm]
theorem Equiv.symm : ∀ {s t : WSeq α}, s ~ʷ t → t ~ʷ s 
goal: s ~ʷ t → t ~ʷ s

full_name: Stream'.WSeq.Equiv.trans
code: @[trans]
theorem Equiv.trans : ∀ {s t u : WSeq α}, s ~ʷ t → t ~ʷ u → s ~ʷ u 
goal: s ~ʷ t → t ~ʷ u → s ~ʷ u

full_name: Stream'.WSeq.Equiv.equivalence
code: theorem Equiv.equivalence : Equivalence (@Equiv α) 
goal: Equivalence Stream'.WSeq.Equiv

full_name: Stream'.WSeq.destruct_nil
code: @[simp]
theorem destruct_nil : destruct (nil : WSeq α) = Computation.pure none 
goal: Stream'.WSeq.nil.destruct = Computation.pure none

full_name: Stream'.WSeq.destruct_cons
code: @[simp]
theorem destruct_cons (a : α) (s) : destruct (cons a s) = Computation.pure (some (a, s)) 
goal: (Stream'.WSeq.cons a s).destruct = Computation.pure (some (a, s))

full_name: Stream'.WSeq.destruct_think
code: @[simp]
theorem destruct_think (s : WSeq α) : destruct (think s) = (destruct s).think 
goal: s.think.destruct = s.destruct.think

full_name: Stream'.WSeq.seq_destruct_nil
code: @[simp]
theorem seq_destruct_nil : Seq.destruct (nil : WSeq α) = none 
goal: Stream'.Seq.destruct Stream'.WSeq.nil = none

full_name: Stream'.WSeq.seq_destruct_cons
code: @[simp]
theorem seq_destruct_cons (a : α) (s) : Seq.destruct (cons a s) = some (some a, s) 
goal: Stream'.Seq.destruct (Stream'.WSeq.cons a s) = some (some a, s)

full_name: Stream'.WSeq.seq_destruct_think
code: @[simp]
theorem seq_destruct_think (s : WSeq α) : Seq.destruct (think s) = some (none, s) 
goal: Stream'.Seq.destruct s.think = some (none, s)

full_name: Stream'.WSeq.head_nil
code: @[simp]
theorem head_nil : head (nil : WSeq α) = Computation.pure none 
goal: Stream'.WSeq.nil.head = Computation.pure none

full_name: Stream'.WSeq.head_cons
code: @[simp]
theorem head_cons (a : α) (s) : head (cons a s) = Computation.pure (some a) 
goal: (Stream'.WSeq.cons a s).head = Computation.pure (some a)

full_name: Stream'.WSeq.head_think
code: @[simp]
theorem head_think (s : WSeq α) : head (think s) = (head s).think 
goal: s.think.head = s.head.think

full_name: Stream'.WSeq.flatten_pure
code: @[simp]
theorem flatten_pure (s : WSeq α) : flatten (Computation.pure s) = s 
goal: Stream'.WSeq.flatten (Computation.pure s) = s

full_name: Stream'.WSeq.flatten_think
code: @[simp]
theorem flatten_think (c : Computation (WSeq α)) : flatten c.think = think (flatten c) 
goal: Stream'.WSeq.flatten c.think = (Stream'.WSeq.flatten c).think

full_name: Stream'.WSeq.destruct_flatten
code: @[simp]
theorem destruct_flatten (c : Computation (WSeq α)) : destruct (flatten c) = c >>= destruct 
goal: (Stream'.WSeq.flatten c).destruct = c >>= Stream'.WSeq.destruct

full_name: Stream'.WSeq.head_terminates_iff
code: theorem head_terminates_iff (s : WSeq α) : Terminates (head s) ↔ Terminates (destruct s) 
goal: s.head.Terminates ↔ s.destruct.Terminates

full_name: Stream'.WSeq.tail_nil
code: @[simp]
theorem tail_nil : tail (nil : WSeq α) = nil 
goal: Stream'.WSeq.nil.tail = Stream'.WSeq.nil

full_name: Stream'.WSeq.tail_cons
code: @[simp]
theorem tail_cons (a : α) (s) : tail (cons a s) = s 
goal: (Stream'.WSeq.cons a s).tail = s

full_name: Stream'.WSeq.tail_think
code: @[simp]
theorem tail_think (s : WSeq α) : tail (think s) = (tail s).think 
goal: s.think.tail = s.tail.think

full_name: Stream'.WSeq.dropn_nil
code: @[simp]
theorem dropn_nil (n) : drop (nil : WSeq α) n = nil 
goal: Stream'.WSeq.nil.drop n = Stream'.WSeq.nil

full_name: Stream'.WSeq.dropn_cons
code: @[simp]
theorem dropn_cons (a : α) (s) (n) : drop (cons a s) (n + 1) = drop s n 
goal: (Stream'.WSeq.cons a s).drop (n + 1) = s.drop n

full_name: Stream'.WSeq.dropn_think
code: @[simp]
theorem dropn_think (s : WSeq α) (n) : drop (think s) n = (drop s n).think 
goal: s.think.drop n = (s.drop n).think

full_name: Stream'.WSeq.dropn_add
code: theorem dropn_add (s : WSeq α) (m) : ∀ n, drop s (m + n) = drop (drop s m) n
  
goal: s.drop (m + n) = (s.drop m).drop n

full_name: Stream'.WSeq.dropn_tail
code: theorem dropn_tail (s : WSeq α) (n) : drop (tail s) n = drop s (n + 1) 
goal: s.tail.drop n = s.drop (n + 1)

full_name: Stream'.WSeq.get?_add
code: theorem get?_add (s : WSeq α) (m n) : get? s (m + n) = get? (drop s m) n 
goal: s.get? (m + n) = (s.drop m).get? n

full_name: Stream'.WSeq.get?_tail
code: theorem get?_tail (s : WSeq α) (n) : get? (tail s) n = get? s (n + 1) 
goal: s.tail.get? n = s.get? (n + 1)

full_name: Stream'.WSeq.join_nil
code: @[simp]
theorem join_nil : join nil = (nil : WSeq α) 
goal: Stream'.WSeq.nil.join = Stream'.WSeq.nil

full_name: Stream'.WSeq.join_think
code: @[simp]
theorem join_think (S : WSeq (WSeq α)) : join (think S) = think (join S) 
goal: S.think.join = S.join.think

full_name: Stream'.WSeq.join_cons
code: @[simp]
theorem join_cons (s : WSeq α) (S) : join (cons s S) = think (append s (join S)) 
goal: (Stream'.WSeq.cons s S).join = (s.append S.join).think

full_name: Stream'.WSeq.nil_append
code: @[simp]
theorem nil_append (s : WSeq α) : append nil s = s 
goal: Stream'.WSeq.nil.append s = s

full_name: Stream'.WSeq.cons_append
code: @[simp]
theorem cons_append (a : α) (s t) : append (cons a s) t = cons a (append s t) 
goal: (Stream'.WSeq.cons a s).append t = Stream'.WSeq.cons a (s.append t)

full_name: Stream'.WSeq.think_append
code: @[simp]
theorem think_append (s t : WSeq α) : append (think s) t = think (append s t) 
goal: s.think.append t = (s.append t).think

full_name: Stream'.WSeq.append_nil
code: @[simp]
theorem append_nil (s : WSeq α) : append s nil = s 
goal: s.append Stream'.WSeq.nil = s

full_name: Stream'.WSeq.append_assoc
code: @[simp]
theorem append_assoc (s t u : WSeq α) : append (append s t) u = append s (append t u) 
goal: (s.append t).append u = s.append (t.append u)

full_name: Stream'.WSeq.tail.aux
code: /-- auxiliary definition of tail over weak sequences-/
@[simp]
def tail.aux : Option (α × WSeq α) → Computation (Option (α × WSeq α))
  
goal: Option (α × Stream'.WSeq α) → Computation (Option (α × Stream'.WSeq α))

full_name: Stream'.WSeq.destruct_tail
code: theorem destruct_tail (s : WSeq α) : destruct (tail s) = destruct s >>= tail.aux 
goal: s.tail.destruct = s.destruct >>= Stream'.WSeq.tail.aux

full_name: Stream'.WSeq.drop.aux
code: /-- auxiliary definition of drop over weak sequences-/
@[simp]
def drop.aux : ℕ → Option (α × WSeq α) → Computation (Option (α × WSeq α))
  
goal: ℕ → Option (α × Stream'.WSeq α) → Computation (Option (α × Stream'.WSeq α))

full_name: Stream'.WSeq.drop.aux_none
code: theorem drop.aux_none : ∀ n, @drop.aux α n none = Computation.pure none
  
goal: Stream'.WSeq.drop.aux n none = Computation.pure none

full_name: Stream'.WSeq.destruct_dropn
code: theorem destruct_dropn : ∀ (s : WSeq α) (n), destruct (drop s n) = destruct s >>= drop.aux n
  
goal: (s.drop n).destruct = s.destruct >>= Stream'.WSeq.drop.aux n

full_name: Stream'.WSeq.head_terminates_of_head_tail_terminates
code: theorem head_terminates_of_head_tail_terminates (s : WSeq α) [T : Terminates (head (tail s))] :
    Terminates (head s) 
goal: s.head.Terminates

full_name: Stream'.WSeq.destruct_some_of_destruct_tail_some
code: theorem destruct_some_of_destruct_tail_some {s : WSeq α} {a} (h : some a ∈ destruct (tail s)) :
    ∃ a', some a' ∈ destruct s 
goal: ∃ a', some a' ∈ s.destruct

full_name: Stream'.WSeq.head_some_of_head_tail_some
code: theorem head_some_of_head_tail_some {s : WSeq α} {a} (h : some a ∈ head (tail s)) :
    ∃ a', some a' ∈ head s 
goal: ∃ a', some a' ∈ s.head

full_name: Stream'.WSeq.head_some_of_get?_some
code: theorem head_some_of_get?_some {s : WSeq α} {a n} (h : some a ∈ get? s n) :
    ∃ a', some a' ∈ head s 
goal: ∃ a', some a' ∈ s.head

full_name: Stream'.WSeq.productive_tail
code: instance productive_tail (s : WSeq α) [Productive s] : Productive (tail s) 
goal: s.tail.Productive

full_name: Stream'.WSeq.productive_dropn
code: instance productive_dropn (s : WSeq α) [Productive s] (n) : Productive (drop s n) 
goal: (s.drop n).Productive

full_name: Stream'.WSeq.toSeq
code: /-- Given a productive weak sequence, we can collapse all the `think`s to
  produce a sequence. -/
def toSeq (s : WSeq α) [Productive s] : Seq α 
goal: Stream'.Seq α

full_name: Stream'.WSeq.get?_terminates_le
code: theorem get?_terminates_le {s : WSeq α} {m n} (h : m ≤ n) :
    Terminates (get? s n) → Terminates (get? s m) 
goal: (s.get? n).Terminates → (s.get? m).Terminates

full_name: Stream'.WSeq.head_terminates_of_get?_terminates
code: theorem head_terminates_of_get?_terminates {s : WSeq α} {n} :
    Terminates (get? s n) → Terminates (head s) 
goal: (s.get? n).Terminates → s.head.Terminates

full_name: Stream'.WSeq.destruct_terminates_of_get?_terminates
code: theorem destruct_terminates_of_get?_terminates {s : WSeq α} {n} (T : Terminates (get? s n)) :
    Terminates (destruct s) 
goal: s.destruct.Terminates

full_name: Stream'.WSeq.mem_rec_on
code: theorem mem_rec_on {C : WSeq α → Prop} {a s} (M : a ∈ s) (h1 : ∀ b s', a = b ∨ C s' → C (cons b s'))
    (h2 : ∀ s, C s → C (think s)) : C s 
goal: C s

full_name: Stream'.WSeq.mem_think
code: @[simp]
theorem mem_think (s : WSeq α) (a) : a ∈ think s ↔ a ∈ s 
goal: a ∈ s.think ↔ a ∈ s

full_name: Stream'.WSeq.eq_or_mem_iff_mem
code: theorem eq_or_mem_iff_mem {s : WSeq α} {a a' s'} :
    some (a', s') ∈ destruct s → (a ∈ s ↔ a = a' ∨ a ∈ s') 
goal: some (a', s') ∈ s.destruct → (a ∈ s ↔ a = a' ∨ a ∈ s')

full_name: Stream'.WSeq.mem_cons_iff
code: @[simp]
theorem mem_cons_iff (s : WSeq α) (b) {a} : a ∈ cons b s ↔ a = b ∨ a ∈ s 
goal: a ∈ Stream'.WSeq.cons b s ↔ a = b ∨ a ∈ s

full_name: Stream'.WSeq.mem_cons_of_mem
code: theorem mem_cons_of_mem {s : WSeq α} (b) {a} (h : a ∈ s) : a ∈ cons b s 
goal: a ∈ Stream'.WSeq.cons b s

full_name: Stream'.WSeq.mem_cons
code: theorem mem_cons (s : WSeq α) (a) : a ∈ cons a s 
goal: a ∈ Stream'.WSeq.cons a s

full_name: Stream'.WSeq.mem_of_mem_tail
code: theorem mem_of_mem_tail {s : WSeq α} {a} : a ∈ tail s → a ∈ s 
goal: a ∈ s.tail → a ∈ s

full_name: Stream'.WSeq.mem_of_mem_dropn
code: theorem mem_of_mem_dropn {s : WSeq α} {a} : ∀ {n}, a ∈ drop s n → a ∈ s
  
goal: a ∈ s.drop n → a ∈ s

full_name: Stream'.WSeq.get?_mem
code: theorem get?_mem {s : WSeq α} {a n} : some a ∈ get? s n → a ∈ s 
goal: some a ∈ s.get? n → a ∈ s

full_name: Stream'.WSeq.exists_get?_of_mem
code: theorem exists_get?_of_mem {s : WSeq α} {a} (h : a ∈ s) : ∃ n, some a ∈ get? s n 
goal: ∃ n, some a ∈ s.get? n

full_name: Stream'.WSeq.exists_dropn_of_mem
code: theorem exists_dropn_of_mem {s : WSeq α} {a} (h : a ∈ s) :
    ∃ n s', some (a, s') ∈ destruct (drop s n) 
goal: ∃ n s', some (a, s') ∈ (s.drop n).destruct

full_name: Stream'.WSeq.liftRel_dropn_destruct
code: theorem liftRel_dropn_destruct {R : α → β → Prop} {s t} (H : LiftRel R s t) :
    ∀ n, Computation.LiftRel (LiftRelO R (LiftRel R)) (destruct (drop s n)) (destruct (drop t n))
  
goal: Computation.LiftRel (Stream'.WSeq.LiftRelO R (Stream'.WSeq.LiftRel R)) (s.drop n).destruct (t.drop n).destruct

full_name: Stream'.WSeq.exists_of_liftRel_left
code: theorem exists_of_liftRel_left {R : α → β → Prop} {s t} (H : LiftRel R s t) {a} (h : a ∈ s) :
    ∃ b, b ∈ t ∧ R a b 
goal: ∃ b, b ∈ t ∧ R a b

full_name: Stream'.WSeq.exists_of_liftRel_right
code: theorem exists_of_liftRel_right {R : α → β → Prop} {s t} (H : LiftRel R s t) {b} (h : b ∈ t) :
    ∃ a, a ∈ s ∧ R a b 
goal: ∃ a, a ∈ s ∧ R a b

full_name: Stream'.WSeq.head_terminates_of_mem
code: theorem head_terminates_of_mem {s : WSeq α} {a} (h : a ∈ s) : Terminates (head s) 
goal: s.head.Terminates

full_name: Stream'.WSeq.of_mem_append
code: theorem of_mem_append {s₁ s₂ : WSeq α} {a : α} : a ∈ append s₁ s₂ → a ∈ s₁ ∨ a ∈ s₂ 
goal: a ∈ s₁.append s₂ → a ∈ s₁ ∨ a ∈ s₂

full_name: Stream'.WSeq.mem_append_left
code: theorem mem_append_left {s₁ s₂ : WSeq α} {a : α} : a ∈ s₁ → a ∈ append s₁ s₂ 
goal: a ∈ s₁ → a ∈ s₁.append s₂

full_name: Stream'.WSeq.exists_of_mem_map
code: theorem exists_of_mem_map {f} {b : β} : ∀ {s : WSeq α}, b ∈ map f s → ∃ a, a ∈ s ∧ f a = b
  
goal: b ∈ Stream'.WSeq.map f s → ∃ a, a ∈ s ∧ f a = b

full_name: Stream'.WSeq.liftRel_nil
code: @[simp]
theorem liftRel_nil (R : α → β → Prop) : LiftRel R nil nil 
goal: Stream'.WSeq.LiftRel R Stream'.WSeq.nil Stream'.WSeq.nil

full_name: Stream'.WSeq.liftRel_cons
code: @[simp]
theorem liftRel_cons (R : α → β → Prop) (a b s t) :
    LiftRel R (cons a s) (cons b t) ↔ R a b ∧ LiftRel R s t 
goal: Stream'.WSeq.LiftRel R (Stream'.WSeq.cons a s) (Stream'.WSeq.cons b t) ↔ R a b ∧ Stream'.WSeq.LiftRel R s t

full_name: Stream'.WSeq.liftRel_think_left
code: @[simp]
theorem liftRel_think_left (R : α → β → Prop) (s t) : LiftRel R (think s) t ↔ LiftRel R s t 
goal: Stream'.WSeq.LiftRel R s.think t ↔ Stream'.WSeq.LiftRel R s t

full_name: Stream'.WSeq.liftRel_think_right
code: @[simp]
theorem liftRel_think_right (R : α → β → Prop) (s t) : LiftRel R s (think t) ↔ LiftRel R s t 
goal: Stream'.WSeq.LiftRel R s t.think ↔ Stream'.WSeq.LiftRel R s t

full_name: Stream'.WSeq.cons_congr
code: theorem cons_congr {s t : WSeq α} (a : α) (h : s ~ʷ t) : cons a s ~ʷ cons a t 
goal: Stream'.WSeq.cons a s ~ʷ Stream'.WSeq.cons a t

full_name: Stream'.WSeq.think_equiv
code: theorem think_equiv (s : WSeq α) : think s ~ʷ s 
goal: s.think ~ʷ s

full_name: Stream'.WSeq.think_congr
code: theorem think_congr {s t : WSeq α} (h : s ~ʷ t) : think s ~ʷ think t 
goal: s.think ~ʷ t.think

full_name: Stream'.WSeq.head_congr
code: theorem head_congr : ∀ {s t : WSeq α}, s ~ʷ t → head s ~ head t 
goal: s ~ʷ t → s.head.Equiv t.head

full_name: Stream'.WSeq.flatten_equiv
code: theorem flatten_equiv {c : Computation (WSeq α)} {s} (h : s ∈ c) : flatten c ~ʷ s 
goal: Stream'.WSeq.flatten c ~ʷ s

full_name: Stream'.WSeq.liftRel_flatten
code: theorem liftRel_flatten {R : α → β → Prop} {c1 : Computation (WSeq α)} {c2 : Computation (WSeq β)}
    (h : c1.LiftRel (LiftRel R) c2) : LiftRel R (flatten c1) (flatten c2) 
goal: Stream'.WSeq.LiftRel R (Stream'.WSeq.flatten c1) (Stream'.WSeq.flatten c2)

full_name: Stream'.WSeq.flatten_congr
code: theorem flatten_congr {c1 c2 : Computation (WSeq α)} :
    Computation.LiftRel Equiv c1 c2 → flatten c1 ~ʷ flatten c2 
goal: Computation.LiftRel Stream'.WSeq.Equiv c1 c2 → Stream'.WSeq.flatten c1 ~ʷ Stream'.WSeq.flatten c2

full_name: Stream'.WSeq.tail_congr
code: theorem tail_congr {s t : WSeq α} (h : s ~ʷ t) : tail s ~ʷ tail t 
goal: s.tail ~ʷ t.tail

full_name: Stream'.WSeq.dropn_congr
code: theorem dropn_congr {s t : WSeq α} (h : s ~ʷ t) (n) : drop s n ~ʷ drop t n 
goal: s.drop n ~ʷ t.drop n

full_name: Stream'.WSeq.get?_congr
code: theorem get?_congr {s t : WSeq α} (h : s ~ʷ t) (n) : get? s n ~ get? t n 
goal: (s.get? n).Equiv (t.get? n)

full_name: Stream'.WSeq.mem_congr
code: theorem mem_congr {s t : WSeq α} (h : s ~ʷ t) (a) : a ∈ s ↔ a ∈ t 
goal: a ∈ s ↔ a ∈ t

full_name: Stream'.WSeq.productive_congr
code: theorem productive_congr {s t : WSeq α} (h : s ~ʷ t) : Productive s ↔ Productive t 
goal: s.Productive ↔ t.Productive

full_name: Stream'.WSeq.Equiv.ext
code: theorem Equiv.ext {s t : WSeq α} (h : ∀ n, get? s n ~ get? t n) : s ~ʷ t 
goal: s ~ʷ t

full_name: Stream'.WSeq.length_eq_map
code: theorem length_eq_map (s : WSeq α) : length s = Computation.map List.length (toList s) 
goal: s.length = Computation.map List.length s.toList

full_name: Stream'.WSeq.ofList_nil
code: @[simp]
theorem ofList_nil : ofList [] = (nil : WSeq α) 
goal: ↑[] = Stream'.WSeq.nil

full_name: Stream'.WSeq.ofList_cons
code: @[simp]
theorem ofList_cons (a : α) (l) : ofList (a::l) = cons a (ofList l) 
goal: ↑(a :: l) = Stream'.WSeq.cons a ↑l

full_name: Stream'.WSeq.toList'_nil
code: @[simp]
theorem toList'_nil (l : List α) :
    Computation.corec (fun ⟨l, s⟩ =>
      match Seq.destruct s with
      | none => Sum.inl l.reverse
      | some (none, s') => Sum.inr (l, s')
      | some (some a, s') => Sum.inr (a::l, s')) (l, nil) = Computation.pure l.reverse 
goal: Computation.corec
    (fun x =>
      match x with
      | (l, s) =>
        match Stream'.Seq.destruct s with
        | none => Sum.inl l.reverse
        | some (none, s') => Sum.inr (l, s')
        | some (some a, s') => Sum.inr (a :: l, s'))
    (l, Stream'.WSeq.nil) =
  Computation.pure l.reverse

full_name: Stream'.WSeq.toList'_cons
code: @[simp]
theorem toList'_cons (l : List α) (s : WSeq α) (a : α) :
    Computation.corec (fun ⟨l, s⟩ =>
      match Seq.destruct s with
      | none => Sum.inl l.reverse
      | some (none, s') => Sum.inr (l, s')
      | some (some a, s') => Sum.inr (a::l, s')) (l, cons a s) =
      (Computation.corec (fun ⟨l, s⟩ =>
        match Seq.destruct s with
        | none => Sum.inl l.reverse
        | some (none, s') => Sum.inr (l, s')
        | some (some a, s') => Sum.inr (a::l, s')) (a::l, s)).think 
goal: Computation.corec
    (fun x =>
      match x with
      | (l, s) =>
        match Stream'.Seq.destruct s with
        | none => Sum.inl l.reverse
        | some (none, s') => Sum.inr (l, s')
        | some (some a, s') => Sum.inr (a :: l, s'))
    (l, Stream'.WSeq.cons a s) =
  (Computation.corec
      (fun x =>
        match x with
        | (l, s) =>
          match Stream'.Seq.destruct s with
          | none => Sum.inl l.reverse
          | some (none, s') => Sum.inr (l, s')
          | some (some a, s') => Sum.inr (a :: l, s'))
      (a :: l, s)).think

full_name: Stream'.WSeq.toList'_think
code: @[simp]
theorem toList'_think (l : List α) (s : WSeq α) :
    Computation.corec (fun ⟨l, s⟩ =>
      match Seq.destruct s with
      | none => Sum.inl l.reverse
      | some (none, s') => Sum.inr (l, s')
      | some (some a, s') => Sum.inr (a::l, s')) (l, think s) =
      (Computation.corec (fun ⟨l, s⟩ =>
        match Seq.destruct s with
        | none => Sum.inl l.reverse
        | some (none, s') => Sum.inr (l, s')
        | some (some a, s') => Sum.inr (a::l, s')) (l, s)).think 
goal: Computation.corec
    (fun x =>
      match x with
      | (l, s) =>
        match Stream'.Seq.destruct s with
        | none => Sum.inl l.reverse
        | some (none, s') => Sum.inr (l, s')
        | some (some a, s') => Sum.inr (a :: l, s'))
    (l, s.think) =
  (Computation.corec
      (fun x =>
        match x with
        | (l, s) =>
          match Stream'.Seq.destruct s with
          | none => Sum.inl l.reverse
          | some (none, s') => Sum.inr (l, s')
          | some (some a, s') => Sum.inr (a :: l, s'))
      (l, s)).think

full_name: Stream'.WSeq.toList'_map
code: theorem toList'_map (l : List α) (s : WSeq α) :
    Computation.corec (fun ⟨l, s⟩ =>
      match Seq.destruct s with
      | none => Sum.inl l.reverse
      | some (none, s') => Sum.inr (l, s')
      | some (some a, s') => Sum.inr (a :: l, s')) (l, s) = (l.reverse ++ ·) <$> toList s 
goal: Computation.corec
    (fun x =>
      match x with
      | (l, s) =>
        match Stream'.Seq.destruct s with
        | none => Sum.inl l.reverse
        | some (none, s') => Sum.inr (l, s')
        | some (some a, s') => Sum.inr (a :: l, s'))
    (l, s) =
  (fun x => l.reverse ++ x) <$> s.toList

full_name: Stream'.WSeq.toList_cons
code: @[simp]
theorem toList_cons (a : α) (s) : toList (cons a s) = (List.cons a <$> toList s).think 
goal: (Stream'.WSeq.cons a s).toList = (List.cons a <$> s.toList).think

full_name: Stream'.WSeq.toList_nil
code: @[simp]
theorem toList_nil : toList (nil : WSeq α) = Computation.pure [] 
goal: Stream'.WSeq.nil.toList = Computation.pure []

full_name: Stream'.WSeq.toList_ofList
code: theorem toList_ofList (l : List α) : l ∈ toList (ofList l) 
goal: l ∈ (↑l).toList

full_name: Stream'.WSeq.destruct_ofSeq
code: @[simp]
theorem destruct_ofSeq (s : Seq α) :
    destruct (ofSeq s) = Computation.pure (s.head.map fun a => (a, ofSeq s.tail)) 
goal: (↑s).destruct = Computation.pure (Option.map (fun a => (a, ↑s.tail)) s.head)

full_name: Stream'.WSeq.head_ofSeq
code: @[simp]
theorem head_ofSeq (s : Seq α) : head (ofSeq s) = Computation.pure s.head 
goal: (↑s).head = Computation.pure s.head

full_name: Stream'.WSeq.tail_ofSeq
code: @[simp]
theorem tail_ofSeq (s : Seq α) : tail (ofSeq s) = ofSeq s.tail 
goal: (↑s).tail = ↑s.tail

full_name: Stream'.WSeq.dropn_ofSeq
code: @[simp]
theorem dropn_ofSeq (s : Seq α) : ∀ n, drop (ofSeq s) n = ofSeq (s.drop n)
  
goal: (↑s).drop n = ↑(s.drop n)

full_name: Stream'.WSeq.get?_ofSeq
code: theorem get?_ofSeq (s : Seq α) (n) : get? (ofSeq s) n = Computation.pure (Seq.get? s n) 
goal: (↑s).get? n = Computation.pure (s.get? n)

full_name: Stream'.WSeq.productive_ofSeq
code: instance productive_ofSeq (s : Seq α) : Productive (ofSeq s) 
goal: (↑s).Productive

full_name: Stream'.WSeq.toSeq_ofSeq
code: theorem toSeq_ofSeq (s : Seq α) : toSeq (ofSeq s) = s 
goal: (↑s).toSeq = s

full_name: Stream'.WSeq.ret
code: /-- The monadic `return a` is a singleton list containing `a`. -/
def ret (a : α) : WSeq α 
goal: Stream'.WSeq α

full_name: Stream'.WSeq.map_nil
code: @[simp]
theorem map_nil (f : α → β) : map f nil = nil 
goal: Stream'.WSeq.map f Stream'.WSeq.nil = Stream'.WSeq.nil

full_name: Stream'.WSeq.map_cons
code: @[simp]
theorem map_cons (f : α → β) (a s) : map f (cons a s) = cons (f a) (map f s) 
goal: Stream'.WSeq.map f (Stream'.WSeq.cons a s) = Stream'.WSeq.cons (f a) (Stream'.WSeq.map f s)

full_name: Stream'.WSeq.map_think
code: @[simp]
theorem map_think (f : α → β) (s) : map f (think s) = think (map f s) 
goal: Stream'.WSeq.map f s.think = (Stream'.WSeq.map f s).think

full_name: Stream'.WSeq.map_id
code: @[simp]
theorem map_id (s : WSeq α) : map id s = s 
goal: Stream'.WSeq.map id s = s

full_name: Stream'.WSeq.map_ret
code: @[simp]
theorem map_ret (f : α → β) (a) : map f (ret a) = ret (f a) 
goal: Stream'.WSeq.map f (Stream'.WSeq.ret a) = Stream'.WSeq.ret (f a)

full_name: Stream'.WSeq.map_append
code: @[simp]
theorem map_append (f : α → β) (s t) : map f (append s t) = append (map f s) (map f t) 
goal: Stream'.WSeq.map f (s.append t) = (Stream'.WSeq.map f s).append (Stream'.WSeq.map f t)

full_name: Stream'.WSeq.map_comp
code: theorem map_comp (f : α → β) (g : β → γ) (s : WSeq α) : map (g ∘ f) s = map g (map f s) 
goal: Stream'.WSeq.map (g ∘ f) s = Stream'.WSeq.map g (Stream'.WSeq.map f s)

full_name: Stream'.WSeq.mem_map
code: theorem mem_map (f : α → β) {a : α} {s : WSeq α} : a ∈ s → f a ∈ map f s 
goal: a ∈ s → f a ∈ Stream'.WSeq.map f s

full_name: Stream'.WSeq.exists_of_mem_join
code: theorem exists_of_mem_join {a : α} : ∀ {S : WSeq (WSeq α)}, a ∈ join S → ∃ s, s ∈ S ∧ a ∈ s 
goal: a ∈ S.join → ∃ s, s ∈ S ∧ a ∈ s

full_name: Stream'.WSeq.exists_of_mem_bind
code: theorem exists_of_mem_bind {s : WSeq α} {f : α → WSeq β} {b} (h : b ∈ bind s f) :
    ∃ a ∈ s, b ∈ f a 
goal: ∃ a, a ∈ s ∧ b ∈ f a

full_name: Stream'.WSeq.destruct_map
code: theorem destruct_map (f : α → β) (s : WSeq α) :
    destruct (map f s) = Computation.map (Option.map (Prod.map f (map f))) (destruct s) 
goal: (Stream'.WSeq.map f s).destruct = Computation.map (Option.map (Prod.map f (Stream'.WSeq.map f))) s.destruct

full_name: Stream'.WSeq.liftRel_map
code: theorem liftRel_map {δ} (R : α → β → Prop) (S : γ → δ → Prop) {s1 : WSeq α} {s2 : WSeq β}
    {f1 : α → γ} {f2 : β → δ} (h1 : LiftRel R s1 s2) (h2 : ∀ {a b}, R a b → S (f1 a) (f2 b)) :
    LiftRel S (map f1 s1) (map f2 s2) 
goal: Stream'.WSeq.LiftRel S (Stream'.WSeq.map f1 s1) (Stream'.WSeq.map f2 s2)

full_name: Stream'.WSeq.map_congr
code: theorem map_congr (f : α → β) {s t : WSeq α} (h : s ~ʷ t) : map f s ~ʷ map f t 
goal: Stream'.WSeq.map f s ~ʷ Stream'.WSeq.map f t

full_name: Stream'.WSeq.destruct_append.aux
code: /-- auxiliary definition of `destruct_append` over weak sequences-/
@[simp]
def destruct_append.aux (t : WSeq α) : Option (α × WSeq α) → Computation (Option (α × WSeq α))
  
goal: Option (α × Stream'.WSeq α) → Computation (Option (α × Stream'.WSeq α))

full_name: Stream'.WSeq.destruct_append
code: theorem destruct_append (s t : WSeq α) :
    destruct (append s t) = (destruct s).bind (destruct_append.aux t) 
goal: (s.append t).destruct = s.destruct.bind (Stream'.WSeq.destruct_append.aux t)

full_name: Stream'.WSeq.destruct_join.aux
code: /-- auxiliary definition of `destruct_join` over weak sequences-/
@[simp]
def destruct_join.aux : Option (WSeq α × WSeq (WSeq α)) → Computation (Option (α × WSeq α))
  
goal: Option (Stream'.WSeq α × Stream'.WSeq (Stream'.WSeq α)) → Computation (Option (α × Stream'.WSeq α))

full_name: Stream'.WSeq.destruct_join
code: theorem destruct_join (S : WSeq (WSeq α)) :
    destruct (join S) = (destruct S).bind destruct_join.aux 
goal: S.join.destruct = S.destruct.bind Stream'.WSeq.destruct_join.aux

full_name: Stream'.WSeq.liftRel_append
code: theorem liftRel_append (R : α → β → Prop) {s1 s2 : WSeq α} {t1 t2 : WSeq β} (h1 : LiftRel R s1 t1)
    (h2 : LiftRel R s2 t2) : LiftRel R (append s1 s2) (append t1 t2) 
goal: Stream'.WSeq.LiftRel R (s1.append s2) (t1.append t2)

full_name: Stream'.WSeq.liftRel_join.lem
code: theorem liftRel_join.lem (R : α → β → Prop) {S T} {U : WSeq α → WSeq β → Prop}
    (ST : LiftRel (LiftRel R) S T)
    (HU :
      ∀ s1 s2,
        (∃ s t S T,
            s1 = append s (join S) ∧
              s2 = append t (join T) ∧ LiftRel R s t ∧ LiftRel (LiftRel R) S T) →
          U s1 s2)
    {a} (ma : a ∈ destruct (join S)) : ∃ b, b ∈ destruct (join T) ∧ LiftRelO R U a b 
goal: ∃ b, b ∈ T.join.destruct ∧ Stream'.WSeq.LiftRelO R U a b

full_name: Stream'.WSeq.liftRel_join
code: theorem liftRel_join (R : α → β → Prop) {S : WSeq (WSeq α)} {T : WSeq (WSeq β)}
    (h : LiftRel (LiftRel R) S T) : LiftRel R (join S) (join T) 
goal: Stream'.WSeq.LiftRel R S.join T.join

full_name: Stream'.WSeq.join_congr
code: theorem join_congr {S T : WSeq (WSeq α)} (h : LiftRel Equiv S T) : join S ~ʷ join T 
goal: S.join ~ʷ T.join

full_name: Stream'.WSeq.liftRel_bind
code: theorem liftRel_bind {δ} (R : α → β → Prop) (S : γ → δ → Prop) {s1 : WSeq α} {s2 : WSeq β}
    {f1 : α → WSeq γ} {f2 : β → WSeq δ} (h1 : LiftRel R s1 s2)
    (h2 : ∀ {a b}, R a b → LiftRel S (f1 a) (f2 b)) : LiftRel S (bind s1 f1) (bind s2 f2) 
goal: Stream'.WSeq.LiftRel S (s1.bind f1) (s2.bind f2)

full_name: Stream'.WSeq.bind_congr
code: theorem bind_congr {s1 s2 : WSeq α} {f1 f2 : α → WSeq β} (h1 : s1 ~ʷ s2) (h2 : ∀ a, f1 a ~ʷ f2 a) :
    bind s1 f1 ~ʷ bind s2 f2 
goal: s1.bind f1 ~ʷ s2.bind f2

full_name: Stream'.WSeq.join_ret
code: @[simp]
theorem join_ret (s : WSeq α) : join (ret s) ~ʷ s 
goal: (Stream'.WSeq.ret s).join ~ʷ s

full_name: Stream'.WSeq.join_map_ret
code: @[simp]
theorem join_map_ret (s : WSeq α) : join (map ret s) ~ʷ s 
goal: (Stream'.WSeq.map Stream'.WSeq.ret s).join ~ʷ s

full_name: Stream'.WSeq.join_append
code: @[simp]
theorem join_append (S T : WSeq (WSeq α)) : join (append S T) ~ʷ append (join S) (join T) 
goal: (S.append T).join ~ʷ S.join.append T.join

full_name: Stream'.WSeq.bind_ret
code: @[simp]
theorem bind_ret (f : α → β) (s) : bind s (ret ∘ f) ~ʷ map f s 
goal: s.bind (Stream'.WSeq.ret ∘ f) ~ʷ Stream'.WSeq.map f s

full_name: Stream'.WSeq.ret_bind
code: @[simp]
theorem ret_bind (a : α) (f : α → WSeq β) : bind (ret a) f ~ʷ f a 
goal: (Stream'.WSeq.ret a).bind f ~ʷ f a

full_name: Stream'.WSeq.map_join
code: @[simp]
theorem map_join (f : α → β) (S) : map f (join S) = join (map (map f) S) 
goal: Stream'.WSeq.map f S.join = (Stream'.WSeq.map (Stream'.WSeq.map f) S).join

full_name: Stream'.WSeq.join_join
code: @[simp]
theorem join_join (SS : WSeq (WSeq (WSeq α))) : join (join SS) ~ʷ join (map join SS) 
goal: SS.join.join ~ʷ (Stream'.WSeq.map Stream'.WSeq.join SS).join

full_name: Stream'.WSeq.bind_assoc
code: @[simp]
theorem bind_assoc (s : WSeq α) (f : α → WSeq β) (g : β → WSeq γ) :
    bind (bind s f) g ~ʷ bind s fun x : α => bind (f x) g 
goal: (s.bind f).bind g ~ʷ s.bind fun x => (f x).bind g

full_name: Stream'.WSeq.monad
code: instance monad : Monad WSeq 
goal: Monad Stream'.WSeq