module Data.Bitstream.Fusion.Monadic
( genericLength
, genericTake
, genericDrop
, genericIndex
, genericReplicate
, genericReplicateM
, genericUnfoldrN
, genericUnfoldrNM
, genericFindIndex
, genericFindIndexM
, genericIndexed
)
where
import Data.Vector.Fusion.Stream.Monadic
import Data.Vector.Fusion.Stream.Size
import Prelude hiding ((!!), drop, replicate, take)
import Prelude.Unicode
genericLength ∷ (Monad m, Num n) ⇒ Stream m α → m n
genericLength = foldl' (\n _ → n+1) 0
genericTake ∷ (Monad m, Integral n) ⇒ n → Stream m α → Stream m α
genericTake n (Stream step s0 sz) = Stream step' (s0, 0) (toMax sz)
where
step' (s, i)
| i < n
= do r ← step s
case r of
Yield α s' → return $ Yield α (s', i+1)
Skip s' → return $ Skip (s', i )
Done → return Done
| otherwise
= return Done
genericDrop ∷ (Monad m, Integral n) ⇒ n → Stream m α → Stream m α
genericDrop n0 (Stream step s0 sz) = Stream step' (s0, Just n0) (toMax sz)
where
step' (s, Just n)
| n > 0
= do r ← step s
case r of
Yield _ s' → return $ Skip (s', Just (n1))
Skip s' → return $ Skip (s', Just n)
Done → return Done
| otherwise
= return $ Skip (s, Nothing)
step' (s, Nothing)
= do r ← step s
case r of
Yield α s' → return $ Yield α (s', Nothing)
Skip s' → return $ Skip (s', Nothing)
Done → return Done
genericIndex ∷ (Monad m, Integral n, Show n) ⇒ Stream m α → n → m α
genericIndex (Stream step s0 _) i0
| i0 < 0 = fail ("genericIndex: out of range: " ⧺ show i0)
| otherwise = index_loop s0 0
where
index_loop s i
= do r ← step s
case r of
Yield α s'
| i ≡ i0 → return α
| otherwise → index_loop s' (i+1)
Skip s' → index_loop s' i
Done → fail ("genericIndex: out of range: " ⧺ show i)
genericReplicate ∷ (Monad m, Integral n) ⇒ n → α → Stream m α
genericReplicate n = genericReplicateM n ∘ return
genericReplicateM ∷ (Monad m, Integral n) ⇒ n → m α → Stream m α
genericReplicateM n0 mα = unfoldrM go n0
where
go n | n ≤ 0 = return Nothing
| otherwise = do α ← mα
return $ Just (α, n1)
genericUnfoldrN ∷ (Monad m, Integral n) ⇒ n → (β → Maybe (α, β)) → β → Stream m α
genericUnfoldrN n f = genericUnfoldrNM n (return ∘ f)
genericUnfoldrNM ∷ (Monad m, Integral n) ⇒ n → (β → m (Maybe (α, β))) → β → Stream m α
genericUnfoldrNM n0 f β0 = unfoldrM go (n0, β0)
where
go (!n, β)
| n ≤ 0 = return Nothing
| otherwise = do r ← f β
return $ do (α, β') ← r
return (α, (n1, β'))
genericFindIndex ∷ (Monad m, Integral n) ⇒ (α → Bool) → Stream m α → m (Maybe n)
genericFindIndex f = genericFindIndexM (return ∘ f)
genericFindIndexM ∷ (Monad m, Integral n) ⇒ (α → m Bool) → Stream m α → m (Maybe n)
genericFindIndexM f (Stream step s0 _) = findIndex_loop s0 0
where
findIndex_loop s i
= do r ← step s
case r of
Yield α s' → do b ← f α
if b then return $ Just i
else findIndex_loop s' (i+1)
Skip s' → findIndex_loop s' i
Done → return Nothing
genericIndexed ∷ (Monad m, Integral n) ⇒ Stream m α → Stream m (n, α)
genericIndexed (Stream step s0 sz) = Stream step' (s0, 0) sz
where
step' (s, i)
= do r ← step s
case r of
Yield α s' → return $ Yield (i, α) (s', i+1)
Skip s' → return $ Skip (s', i )
Done → return Done