{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE BangPatterns #-} -- | Basic functionality, closely mirroring the list / Foldable api from Prelude. -- -- This module should be imported qualified i.e. `import Piped.Prelude as P`. -- module Piped.Prelude where import Control.Monad import Control.Monad.Trans import Prelude hiding (foldl, scanl, mapM_, last, take, drop, zipWith) import Piped import Piped.Internal -- | Yield only elements satisfying a predicate. -- filter :: Monad m => (i -> Bool) -> Pipe i i m () filter f = awaitForever $ \i -> if f i then yield i else pure () {-# INLINE filter #-} -- | Yield values while they satisfy a predicate, then return. -- takeWhile :: Monad m => (i -> Bool) -> Pipe i i m () takeWhile f = go where go = awaitJust $ \i -> if f i then yield i >> go else leftover i {-# INLINE takeWhile #-} -- | Drop values while they satisfy a predicate, then return. -- -- Note: this does not yield any values, and should be combined with (>>). -- dropWhile :: Monad m => (i -> Bool) -> Pipe i o m () dropWhile f = go where go = awaitJust $ \i -> if f i then go else leftover i {-# INLINE dropWhile #-} -- | Equivalent to `map id`. -- identity :: Monad m => Pipe i i m () identity = awaitForever yield {-# INLINE identity #-} -- | `map` with an accumulator. -- scanl :: forall i o m. (o -> i -> o) -> o -> Pipe i o m () scanl f s = Pipe $ \rest -> fix1 s $ \next !s l r -> runYield r s $ \r -> runAwait l (rest l r ()) $ \i l -> next (f s i) l r {-# INLINE scanl #-} -- | Left fold over input values. -- foldl :: Monad m => (a -> i -> a) -> a -> Pipe i o m a foldl f start = Pipe $ \rest -> fix1 start $ \next !s l r -> runAwait l (rest termLeft r s) $ \i l -> next (f s i) l r {-# INLINE foldl #-} -- | Drop n values. -- -- Note: This will not yield values and should be combined with `>>` -- drop :: Monad m => Int -> Pipe i o m () drop 0 = pure () drop n = awaitJust (\_ -> drop $ n-1) {-# INLINE drop #-} -- | Take n values. -- take :: Monad m => Int -> Pipe i i m () take 0 = pure () take n = awaitJust $ \i -> yield i >> take (n-1) {-# INLINE take #-} -- | Map a pure function over input values. -- map :: Monad m => (i -> o) -> Pipe i o m () map f = awaitForever $ yield . f {-# INLINE map #-} -- | Map a monadic function over input values. -- mapM :: Monad m => (i -> m o) -> Pipe i o m () mapM f = awaitForever $ \i -> lift (f i) >>= yield {-# INLINE mapM #-} -- | Map a monadic function over input values but don't yield anything. -- mapM_ :: Monad m => (i -> m ()) -> Pipe i () m () mapM_ f = awaitForever $ lift . f {-# INLINE mapM_ #-} -- | Skip the first value -- tail :: Monad m => Pipe i i m () tail = await >> identity {-# INLINE tail #-} -- | Return the last value. -- last :: Monad m => Pipe i o m (Maybe i) last = go Nothing where go x = awaitMaybe (pure x) (go . Just) {-# INLINE last #-} -- | Zip two pipes together. -- zip :: Monad m => Pipe () o m () -> Pipe () o' m () -> Pipe () (o, o') m () zip = zipWith (,) {-# INLINE zip #-} -- | Zip two pipes together with a pure function. -- zipWith :: Monad m => (o -> o' -> a) -> Pipe () o m () -> Pipe () o' m () -> Pipe () a m () zipWith f (Pipe f1) (Pipe f2) = Pipe go where go rest _ r = loop (side f1) (side f2) r where exit y = rest termLeft y () side f = Await $ \y -> f (\_ y () -> terminate y) termLeft y loop a1 a2 yield = runAwait a1 (exit yield) $ \i1 a1 -> runAwait a2 (exit yield) $ \i2 a2 -> runYield yield (f i1 i2) $ \yield -> loop a1 a2 yield -- | Concatenate foldable inputs to a single stream of outputs. -- concat :: (Foldable t, Monad m) => Pipe (t i) i m () concat = awaitForever $ foldMap yield {-# INLINE concat #-}