{-# LANGUAGE CPP #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE Trustworthy #-}
module Pipes (
Proxy
, X
, Effect
, Effect'
, runEffect
, Producer
, Producer'
, yield
, for
, (~>)
, (<~)
, Consumer
, Consumer'
, await
, (>~)
, (~<)
, Pipe
, cat
, (>->)
, (<-<)
, ListT(..)
, runListT
, Enumerable(..)
, next
, each
, every
, discard
, module Control.Monad
, module Control.Monad.IO.Class
, module Control.Monad.Trans.Class
, module Control.Monad.Morph
, Foldable
) where
import Control.Monad (void, MonadPlus(mzero, mplus))
import Control.Monad.Catch (MonadThrow(..), MonadCatch(..))
import Control.Monad.Except (MonadError(..))
import Control.Monad.Fail (MonadFail(..))
import Control.Monad.IO.Class (MonadIO(liftIO))
import Control.Monad.Reader (MonadReader(..))
import Control.Monad.State (MonadState(..))
import Control.Monad.Trans.Class (MonadTrans(lift))
import Control.Monad.Trans.Except (ExceptT, runExceptT)
import Control.Monad.Trans.Identity (IdentityT(runIdentityT))
import Control.Monad.Trans.Maybe (MaybeT(runMaybeT))
import Control.Monad.Writer (MonadWriter(..))
import Control.Monad.Zip (MonadZip(..))
import Pipes.Core
import Pipes.Internal (Proxy(..))
import qualified Data.Foldable as F
#if MIN_VERSION_base(4,8,0)
import Control.Applicative (Alternative(..))
#else
import Control.Applicative
import Data.Foldable (Foldable)
import Data.Traversable (Traversable(..))
#endif
import Data.Semigroup
import Control.Monad.Morph (MFunctor(hoist), MMonad(embed))
infixl 4 <~
infixr 4 ~>
infixl 5 ~<
infixr 5 >~
infixl 7 >->
infixr 7 <-<
yield :: Functor m => a -> Producer' a m ()
yield = respond
{-# INLINABLE [1] yield #-}
for :: Functor m
=> Proxy x' x b' b m a'
-> (b -> Proxy x' x c' c m b')
-> Proxy x' x c' c m a'
for = (//>)
{-# INLINABLE [0] for #-}
{-# RULES
"for (for p f) g" forall p f g . for (for p f) g = for p (\a -> for (f a) g)
; "for p yield" forall p . for p yield = p
; "for (yield x) f" forall x f . for (yield x) f = f x
; "for cat f" forall f .
for cat f =
let go = do
x <- await
f x
go
in go
; "f >~ (g >~ p)" forall f g p . f >~ (g >~ p) = (f >~ g) >~ p
; "await >~ p" forall p . await >~ p = p
; "p >~ await" forall p . p >~ await = p
; "m >~ cat" forall m .
m >~ cat =
let go = do
x <- m
yield x
go
in go
; "p1 >-> (p2 >-> p3)" forall p1 p2 p3 .
p1 >-> (p2 >-> p3) = (p1 >-> p2) >-> p3
; "p >-> cat" forall p . p >-> cat = p
; "cat >-> p" forall p . cat >-> p = p
#-}
(~>)
:: Functor m
=> (a -> Proxy x' x b' b m a')
-> (b -> Proxy x' x c' c m b')
-> (a -> Proxy x' x c' c m a')
(~>) = (/>/)
{-# INLINABLE (~>) #-}
(<~)
:: Functor m
=> (b -> Proxy x' x c' c m b')
-> (a -> Proxy x' x b' b m a')
-> (a -> Proxy x' x c' c m a')
g <~ f = f ~> g
{-# INLINABLE (<~) #-}
await :: Functor m => Consumer' a m a
await = request ()
{-# INLINABLE [1] await #-}
(>~)
:: Functor m
=> Proxy a' a y' y m b
-> Proxy () b y' y m c
-> Proxy a' a y' y m c
p1 >~ p2 = (\() -> p1) >\\ p2
{-# INLINABLE [1] (>~) #-}
(~<)
:: Functor m
=> Proxy () b y' y m c
-> Proxy a' a y' y m b
-> Proxy a' a y' y m c
p2 ~< p1 = p1 >~ p2
{-# INLINABLE (~<) #-}
cat :: Functor m => Pipe a a m r
cat = pull ()
{-# INLINABLE [1] cat #-}
(>->)
:: Functor m
=> Proxy a' a () b m r
-> Proxy () b c' c m r
-> Proxy a' a c' c m r
p1 >-> p2 = (\() -> p1) +>> p2
{-# INLINABLE [1] (>->) #-}
newtype ListT m a = Select { enumerate :: Producer a m () }
instance Functor m => Functor (ListT m) where
fmap f p = Select (for (enumerate p) (\a -> yield (f a)))
{-# INLINE fmap #-}
instance Functor m => Applicative (ListT m) where
pure a = Select (yield a)
{-# INLINE pure #-}
mf <*> mx = Select (
for (enumerate mf) (\f ->
for (enumerate mx) (\x ->
yield (f x) ) ) )
instance Monad m => Monad (ListT m) where
return = pure
{-# INLINE return #-}
m >>= f = Select (for (enumerate m) (\a -> enumerate (f a)))
{-# INLINE (>>=) #-}
#if !MIN_VERSION_base(4,13,0)
fail _ = mzero
{-# INLINE fail #-}
#endif
instance Monad m => MonadFail (ListT m) where
fail _ = mzero
{-# INLINE fail #-}
instance Foldable m => Foldable (ListT m) where
foldMap f = go . enumerate
where
go p = case p of
Request v _ -> closed v
Respond a fu -> f a `mappend` go (fu ())
M m -> F.foldMap go m
Pure _ -> mempty
{-# INLINE foldMap #-}
instance (Functor m, Traversable m) => Traversable (ListT m) where
traverse k (Select p) = fmap Select (traverse_ p)
where
traverse_ (Request v _ ) = closed v
traverse_ (Respond a fu) = _Respond <$> k a <*> traverse_ (fu ())
where
_Respond a_ a' = Respond a_ (\_ -> a')
traverse_ (M m ) = fmap M (traverse traverse_ m)
traverse_ (Pure r ) = pure (Pure r)
instance MonadTrans ListT where
lift m = Select (do
a <- lift m
yield a )
instance (MonadIO m) => MonadIO (ListT m) where
liftIO m = lift (liftIO m)
{-# INLINE liftIO #-}
instance (Functor m) => Alternative (ListT m) where
empty = Select (return ())
{-# INLINE empty #-}
p1 <|> p2 = Select (do
enumerate p1
enumerate p2 )
instance (Monad m) => MonadPlus (ListT m) where
mzero = empty
{-# INLINE mzero #-}
mplus = (<|>)
{-# INLINE mplus #-}
instance MFunctor ListT where
hoist morph = Select . hoist morph . enumerate
{-# INLINE hoist #-}
instance MMonad ListT where
embed f (Select p0) = Select (loop p0)
where
loop (Request a' fa ) = Request a' (\a -> loop (fa a ))
loop (Respond b fb') = Respond b (\b' -> loop (fb' b'))
loop (M m ) = for (enumerate (fmap loop (f m))) id
loop (Pure r ) = Pure r
{-# INLINE embed #-}
instance (Functor m) => Semigroup (ListT m a) where
(<>) = (<|>)
{-# INLINE (<>) #-}
instance (Functor m) => Monoid (ListT m a) where
mempty = empty
{-# INLINE mempty #-}
#if !(MIN_VERSION_base(4,11,0))
mappend = (<|>)
{-# INLINE mappend #-}
#endif
instance (MonadState s m) => MonadState s (ListT m) where
get = lift get
{-# INLINE get #-}
put s = lift (put s)
{-# INLINE put #-}
state f = lift (state f)
{-# INLINE state #-}
instance (MonadWriter w m) => MonadWriter w (ListT m) where
writer = lift . writer
{-# INLINE writer #-}
tell w = lift (tell w)
{-# INLINE tell #-}
listen l = Select (go (enumerate l) mempty)
where
go p w = case p of
Request a' fa -> Request a' (\a -> go (fa a ) w)
Respond b fb' -> Respond (b, w) (\b' -> go (fb' b') w)
M m -> M (do
(p', w') <- listen m
return (go p' $! mappend w w') )
Pure r -> Pure r
pass l = Select (go (enumerate l) mempty)
where
go p w = case p of
Request a' fa -> Request a' (\a -> go (fa a ) w)
Respond (b, f) fb' -> M (pass (return
(Respond b (\b' -> go (fb' b') (f w)), \_ -> f w) ))
M m -> M (do
(p', w') <- listen m
return (go p' $! mappend w w') )
Pure r -> Pure r
instance (MonadReader i m) => MonadReader i (ListT m) where
ask = lift ask
{-# INLINE ask #-}
local f l = Select (local f (enumerate l))
{-# INLINE local #-}
reader f = lift (reader f)
{-# INLINE reader #-}
instance (MonadError e m) => MonadError e (ListT m) where
throwError e = lift (throwError e)
{-# INLINE throwError #-}
catchError l k = Select (catchError (enumerate l) (\e -> enumerate (k e)))
{-# INLINE catchError #-}
instance MonadThrow m => MonadThrow (ListT m) where
throwM = Select . throwM
{-# INLINE throwM #-}
instance MonadCatch m => MonadCatch (ListT m) where
catch l k = Select (Control.Monad.Catch.catch (enumerate l) (\e -> enumerate (k e)))
{-# INLINE catch #-}
instance Monad m => MonadZip (ListT m) where
mzipWith f = go
where
go xs ys = Select $ do
xres <- lift $ next (enumerate xs)
case xres of
Left r -> return r
Right (x, xnext) -> do
yres <- lift $ next (enumerate ys)
case yres of
Left r -> return r
Right (y, ynext) -> do
yield (f x y)
enumerate (go (Select xnext) (Select ynext))
runListT :: Monad m => ListT m a -> m ()
runListT l = runEffect (enumerate (l >> mzero))
{-# INLINABLE runListT #-}
class Enumerable t where
toListT :: Monad m => t m a -> ListT m a
instance Enumerable ListT where
toListT = id
instance Enumerable IdentityT where
toListT m = Select $ do
a <- lift $ runIdentityT m
yield a
instance Enumerable MaybeT where
toListT m = Select $ do
x <- lift $ runMaybeT m
case x of
Nothing -> return ()
Just a -> yield a
instance Enumerable (ExceptT e) where
toListT m = Select $ do
x <- lift $ runExceptT m
case x of
Left _ -> return ()
Right a -> yield a
next :: Monad m => Producer a m r -> m (Either r (a, Producer a m r))
next = go
where
go p = case p of
Request v _ -> closed v
Respond a fu -> return (Right (a, fu ()))
M m -> m >>= go
Pure r -> return (Left r)
{-# INLINABLE next #-}
each :: (Functor m, Foldable f) => f a -> Producer' a m ()
each = F.foldr (\a p -> yield a >> p) (return ())
{-# INLINABLE each #-}
every :: (Monad m, Enumerable t) => t m a -> Producer' a m ()
every it = discard >\\ enumerate (toListT it)
{-# INLINABLE every #-}
discard :: Monad m => a -> m ()
discard _ = return ()
{-# INLINABLE discard #-}
(<-<)
:: Functor m
=> Proxy () b c' c m r
-> Proxy a' a () b m r
-> Proxy a' a c' c m r
p2 <-< p1 = p1 >-> p2
{-# INLINABLE (<-<) #-}