{-# LANGUAGE RankNTypes #-}
module Data.Conduit.List
(
sourceList
, sourceNull
, unfold
, unfoldM
, enumFromTo
, iterate
, fold
, foldMap
, take
, drop
, head
, peek
, consume
, sinkNull
, foldMapM
, foldM
, mapM_
, map
, mapMaybe
, mapFoldable
, catMaybes
, concat
, concatMap
, concatMapAccum
, scanl
, scan
, mapAccum
, groupBy
, isolate
, filter
, mapM
, iterM
, scanlM
, scanM
, mapAccumM
, mapMaybeM
, mapFoldableM
, concatMapM
, concatMapAccumM
, sequence
) where
import qualified Prelude
import Prelude
( ($), return, (==), (-), Int
, (.), id, Maybe (..), Monad
, Bool (..)
, (>>)
, (>>=)
, seq
, otherwise
, Enum (succ), Eq
, maybe
, either
, (<=)
)
import Data.Monoid (Monoid, mempty, mappend)
import qualified Data.Foldable as F
import Data.Conduit
import qualified Data.Conduit.Internal as CI
import Control.Monad (when, (<=<), liftM, void)
import Control.Monad.Trans.Class (lift)
unfold :: Monad m
=> (b -> Maybe (a, b))
-> b
-> Producer m a
unfold f =
go
where
go seed =
case f seed of
Just (a, seed') -> yield a >> go seed'
Nothing -> return ()
unfoldM :: Monad m
=> (b -> m (Maybe (a, b)))
-> b
-> Producer m a
unfoldM f =
go
where
go seed = do
mres <- lift $ f seed
case mres of
Just (a, seed') -> yield a >> go seed'
Nothing -> return ()
sourceList :: Monad m => [a] -> Producer m a
sourceList = Prelude.mapM_ yield
enumFromTo :: (Enum a, Eq a, Monad m)
=> a
-> a
-> Producer m a
enumFromTo x = CI.ConduitM . CI.enumFromTo x
{-# INLINE enumFromTo #-}
iterate :: Monad m => (a -> a) -> a -> Producer m a
iterate f =
go
where
go a = yield a >> go (f a)
fold :: Monad m
=> (b -> a -> b)
-> b
-> Consumer a m b
fold f =
loop
where
loop accum =
await >>= maybe (return accum) go
where
go a =
let accum' = f accum a
in accum' `seq` loop accum'
foldM :: Monad m
=> (b -> a -> m b)
-> b
-> Consumer a m b
foldM f =
loop
where
loop accum = do
await >>= maybe (return accum) go
where
go a = do
accum' <- lift $ f accum a
accum' `seq` loop accum'
foldMap :: (Monad m, Monoid b)
=> (a -> b)
-> Consumer a m b
foldMap f =
fold combiner mempty
where
combiner accum = mappend accum . f
foldMapM :: (Monad m, Monoid b)
=> (a -> m b)
-> Consumer a m b
foldMapM f =
foldM combiner mempty
where
combiner accum = liftM (mappend accum) . f
mapM_ :: Monad m
=> (a -> m ())
-> Consumer a m ()
mapM_ f = awaitForever $ lift . f
{-# INLINE [1] mapM_ #-}
srcMapM_ :: Monad m => Source m a -> (a -> m ()) -> m ()
srcMapM_ (CI.ConduitM src) f =
go src
where
go (CI.Done ()) = return ()
go (CI.PipeM mp) = mp >>= go
go (CI.Leftover p ()) = go p
go (CI.HaveOutput p _ o) = f o >> go p
go (CI.NeedInput _ c) = go (c ())
{-# INLINE srcMapM_ #-}
{-# RULES "connect to mapM_" forall f src. src $$ mapM_ f = srcMapM_ src f #-}
drop :: Monad m
=> Int
-> Consumer a m ()
drop =
loop
where
loop i | i <= 0 = return ()
loop count = await >>= maybe (return ()) (\_ -> loop (count - 1))
take :: Monad m
=> Int
-> Consumer a m [a]
take =
loop id
where
loop front 0 = return $ front []
loop front count = await >>= maybe
(return $ front [])
(\x -> loop (front .(x:)) (count - 1))
head :: Monad m => Consumer a m (Maybe a)
head = await
peek :: Monad m => Consumer a m (Maybe a)
peek = await >>= maybe (return Nothing) (\x -> leftover x >> return (Just x))
map :: Monad m => (a -> b) -> Conduit a m b
map f = awaitForever $ yield . f
{-# INLINE [1] map #-}
{-# RULES "source/map fusion $=" forall f src. src $= map f = mapFuseRight src f #-}
{-# RULES "source/map fusion =$=" forall f src. src =$= map f = mapFuseRight src f #-}
mapFuseRight :: Monad m => Source m a -> (a -> b) -> Source m b
mapFuseRight (CI.ConduitM src) f = CI.ConduitM (CI.mapOutput f src)
{-# INLINE mapFuseRight #-}
mapM :: Monad m => (a -> m b) -> Conduit a m b
mapM f = awaitForever $ yield <=< lift . f
iterM :: Monad m => (a -> m ()) -> Conduit a m a
iterM f = awaitForever $ \a -> lift (f a) >> yield a
mapMaybe :: Monad m => (a -> Maybe b) -> Conduit a m b
mapMaybe f = awaitForever $ maybe (return ()) yield . f
mapMaybeM :: Monad m => (a -> m (Maybe b)) -> Conduit a m b
mapMaybeM f = awaitForever $ maybe (return ()) yield <=< lift . f
catMaybes :: Monad m => Conduit (Maybe a) m a
catMaybes = awaitForever $ maybe (return ()) yield
concat :: (Monad m, F.Foldable f) => Conduit (f a) m a
concat = awaitForever $ F.mapM_ yield
concatMap :: Monad m => (a -> [b]) -> Conduit a m b
concatMap f = awaitForever $ sourceList . f
concatMapM :: Monad m => (a -> m [b]) -> Conduit a m b
concatMapM f = awaitForever $ sourceList <=< lift . f
concatMapAccum :: Monad m => (a -> accum -> (accum, [b])) -> accum -> Conduit a m b
concatMapAccum f x0 = void (mapAccum f x0) =$= concat
scanl :: Monad m => (a -> s -> (s, b)) -> s -> Conduit a m b
scanl f s = void $ mapAccum f s
{-# DEPRECATED scanl "Use mapAccum instead" #-}
scanlM :: Monad m => (a -> s -> m (s, b)) -> s -> Conduit a m b
scanlM f s = void $ mapAccumM f s
{-# DEPRECATED scanlM "Use mapAccumM instead" #-}
mapAccum :: Monad m => (a -> s -> (s, b)) -> s -> ConduitM a b m s
mapAccum f =
loop
where
loop s = await >>= maybe (return s) go
where
go a = case f a s of
(s', b) -> yield b >> loop s'
mapAccumM :: Monad m => (a -> s -> m (s, b)) -> s -> ConduitM a b m s
mapAccumM f =
loop
where
loop s = await >>= maybe (return s) go
where
go a = do (s', b) <- lift $ f a s
yield b
loop s'
scan :: Monad m => (a -> b -> b) -> b -> ConduitM a b m b
scan f =
mapAccum $ \a b -> let b' = f a b in (b', b')
scanM :: Monad m => (a -> b -> m b) -> b -> ConduitM a b m b
scanM f =
mapAccumM $ \a b -> do b' <- f a b
return (b', b')
concatMapAccumM :: Monad m => (a -> accum -> m (accum, [b])) -> accum -> Conduit a m b
concatMapAccumM f x0 = void (mapAccumM f x0) =$= concat
mapFoldable :: (Monad m, F.Foldable f) => (a -> f b) -> Conduit a m b
mapFoldable f = awaitForever $ F.mapM_ yield . f
mapFoldableM :: (Monad m, F.Foldable f) => (a -> m (f b)) -> Conduit a m b
mapFoldableM f = awaitForever $ F.mapM_ yield <=< lift . f
consume :: Monad m => Consumer a m [a]
consume =
loop id
where
loop front = await >>= maybe (return $ front []) (\x -> loop $ front . (x:))
groupBy :: Monad m => (a -> a -> Bool) -> Conduit a m [a]
groupBy f =
start
where
start = await >>= maybe (return ()) (loop id)
loop rest x =
await >>= maybe (yield (x : rest [])) go
where
go y
| f x y = loop (rest . (y:)) x
| otherwise = yield (x : rest []) >> loop id y
isolate :: Monad m => Int -> Conduit a m a
isolate =
loop
where
loop 0 = return ()
loop count = await >>= maybe (return ()) (\x -> yield x >> loop (count - 1))
filter :: Monad m => (a -> Bool) -> Conduit a m a
filter f = awaitForever $ \i -> when (f i) (yield i)
filterFuseRight :: Monad m => Source m a -> (a -> Bool) -> Source m a
filterFuseRight (CI.ConduitM src) f =
CI.ConduitM (go src)
where
go (CI.Done ()) = CI.Done ()
go (CI.PipeM mp) = CI.PipeM (liftM go mp)
go (CI.Leftover p i) = CI.Leftover (go p) i
go (CI.HaveOutput p c o)
| f o = CI.HaveOutput (go p) c o
| otherwise = go p
go (CI.NeedInput p c) = CI.NeedInput (go . p) (go . c)
{-# RULES "source/filter fusion $=" forall f src. src $= filter f = filterFuseRight src f #-}
{-# RULES "source/filter fusion =$=" forall f src. src =$= filter f = filterFuseRight src f #-}
{-# INLINE filterFuseRight #-}
sinkNull :: Monad m => Consumer a m ()
sinkNull = awaitForever $ \_ -> return ()
{-# RULES "connect to sinkNull" forall src. src $$ sinkNull = srcSinkNull src #-}
srcSinkNull :: Monad m => Source m a -> m ()
srcSinkNull (CI.ConduitM src) =
go src
where
go (CI.Done ()) = return ()
go (CI.PipeM mp) = mp >>= go
go (CI.Leftover p ()) = go p
go (CI.HaveOutput p _ _) = go p
go (CI.NeedInput _ c) = go (c ())
{-# INLINE srcSinkNull #-}
sourceNull :: Monad m => Producer m a
sourceNull = return ()
sequence :: Monad m
=> Consumer i m o
-> Conduit i m o
sequence sink =
self
where
self = awaitForever $ \i -> leftover i >> sink >>= yield