babynf-0.1.0.2: lib/Data/BAByNF/Util/Stream.hs
{-# LANGUAGE LambdaCase #-}
module Data.BAByNF.Util.Stream where
import Data.Bifunctor qualified as Bifunctor
import Data.Maybe (isJust, isNothing)
import Control.Applicative (liftA2)
import Control.Monad (when)
import Prelude hiding (take, drop, takeWhile, dropWhile)
import Data.Kind (Type)
newtype Stream e a = Stream
{ runStream :: [e] -> ([e], a)
}
runStream_ :: Stream e a -> [e] -> a
runStream_ stream = snd . runStream stream
instance Functor (Stream e) where
fmap func stream = Stream { runStream = Bifunctor.second func . runStream stream}
instance Applicative (Stream e) where
pure a = Stream { runStream = (, a) }
liftA2 func s1 s2 = Stream { runStream = (\(es1, a) -> Bifunctor.second (func a) . runStream s2 $ es1) . runStream s1 }
instance Monad (Stream e) where
(>>=) s sf = Stream { runStream = (\(es, a) -> runStream (sf a) es ) . runStream s }
hasNext :: Stream e Bool
hasNext = Stream { runStream = \es -> case es of [] -> (es, False); _ -> (es, True) }
take :: Stream e (Maybe e)
take = Stream { runStream = \es -> case es of [] -> (es, Nothing); x:xs -> (xs, Just x)}
drop :: Stream e ()
drop = Stream { runStream = \es -> case es of [] -> (es, ()); _:xs -> (xs, ())}
peek :: Stream e (Maybe e)
peek = Stream { runStream = \es -> case es of [] -> (es, Nothing); x:_ -> (es, Just x)}
takeIf :: (e -> Bool) -> Stream e (Maybe e)
takeIf cond = do
opt <- peek
case opt of
Nothing -> return Nothing
Just x -> if cond x then drop >> return (Just x) else return Nothing
dropIf :: (e -> Bool) -> Stream e ()
dropIf cond = do
opt <- peek
case opt of
Nothing -> return ()
Just x -> when (cond x) drop
takeWhile :: (e -> Bool) -> Stream e [e]
takeWhile cond = do
opt <- takeIf cond
case opt of
Nothing -> return []
Just x -> do
xs <- takeWhile cond
return (x:xs)
dropWhile :: (e -> Bool) -> Stream e ()
dropWhile cond = do
opt <- peek
case opt of
Nothing -> return ()
Just x -> when (cond x) $ drop >> dropWhile cond
find :: (e -> Bool) -> Stream e (Maybe e)
find cond = dropWhile (not . cond) >> takeIf cond
findSeq :: (e -> Bool) -> Stream e [e]
findSeq cond = dropWhile (not . cond) >> takeWhile cond
takeIfMap :: (e -> Maybe a) -> Stream e (Maybe a)
takeIfMap func = do
opt <- peek >>= (\maybeE -> return $ maybeE >>= func)
when (isJust opt) drop >> return opt
takeWhileMap :: (e -> Maybe a) -> Stream e [a]
takeWhileMap func = do
opt <- takeIfMap func
case opt of
Nothing -> return []
Just e -> takeWhileMap func >>= (\es -> return $ e : es)
findMap :: (e -> Maybe a) -> Stream e (Maybe a)
findMap func = dropWhile (isNothing . func) >> takeIfMap func
findSeqMap :: (e -> Maybe a) -> Stream e [a]
findSeqMap func = dropWhile (isNothing . func) >> takeWhileMap func
either :: Stream e (Either l a) -> (a -> Stream e b) -> Stream e (Either l b)
either stream action = stream >>= \case Left l -> return (Left l); Right a -> fmap Right (action a)
either' :: Stream e (Either l a) -> (a -> Stream e (Either l b)) -> Stream e (Either l b)
either' stream action = stream >>= \case Left l -> return (Left l); Right a -> action a
class Propagate (p :: Type -> Type) where
propagate :: (Monad m) => m (p a) -> (a -> m (p b)) -> m (p b)
instance Propagate Maybe where
propagate m1 m2 = m1 >>= \case Nothing -> return Nothing; Just a -> m2 a
instance Propagate (Either a) where
propagate m1 m2 = m1 >>= \case Left e -> return (Left e); Right a -> m2 a
propagate' :: (Propagate p, Monad m) => m (p a) -> m (p b) -> m (p b)
propagate' m1 m2 = propagate m1 (const m2)