piped-0.1.0.0: src/Piped/Compose.hs
-- | Pipe composition can be supply or demand driven, which refers to how the pipeline is
-- initiated. Supply driven initiates the left side first.
--
-- When a pipe terminates, one side must return a value. Unless the pipeline is run
-- in resumable mode, the other sides may never "complete" in that they do not
-- return a value. If they allocate resources, MonadResource or similar should be
-- used to handle cleanup (see 'Piped.Extras.bracketPipe').
--
-- Right hand termination works by indicating that no more values are available.
--
-- In a mode where either side can return a value, no special termination logic is invoked,
-- execution ends the first time a side returns.
--
-- Left termination is not provided; since there is no way to indicate to the left side
-- that the right has terminated, and potential solutions involve discarding values.
-- However, the "either" modes are also suitable for left termination.
--
module Piped.Compose
(
-- ** Operators
--
(.|)
, (|.)
-- ** Demand driven
--
-- | The right hand side is run first. The left hand side is only
-- invoked by calling `await`.
--
, composeDemand
, composeDemandEither
-- ** Supply driven
--
-- | The left hand side is run first. If it returns immediately, the right
-- hand side is invoked only in the case of `composeSupply`.
--
, composeSupply
, composeSupplyEither
) where
import Piped.Internal
-- | Demand driven; same as 'composeDemand
--
(.|) :: Monad m => Pipe i e m () -> Pipe e o m b -> Pipe i o m b
(.|) = composeDemand
{-# INLINE (.|) #-}
-- | Supply driven; same as 'composeSupplyEither
--
(|.) :: Monad m => Pipe i e m a -> Pipe e o m a -> Pipe i o m a
(|.) = composeSupplyEither
{-# INLINE (|.) #-}
-- | The right side is run first, only the right side may return a value.
--
composeDemand :: Monad m => Pipe i e m () -> Pipe e o m b -> Pipe i o m b
composeDemand (Pipe f1) (Pipe f2) =
Pipe $ \rest l r ->
f2 (\_ -> rest termLeft) (Await $ f1 (\_ r _ -> terminate r) l) r
{-# INLINE composeDemand #-}
-- | The right side is run first, either side may return a value.
--
composeDemandEither :: Monad m => Pipe i e m a -> Pipe e o m a -> Pipe i o m a
composeDemandEither (Pipe f1) (Pipe f2) =
Pipe $ \rest l r ->
f2 (\_ -> rest termLeft) (Await $ f1 (\l -> rest l . termRight) l) r
{-# INLINE composeDemandEither #-}
-- | The left side is run first, only the right side may return a value.
--
composeSupply :: Monad m => Pipe i e m () -> Pipe e o m b -> Pipe i o m b
composeSupply (Pipe f1) (Pipe f2) =
Pipe $ \rest l r ->
f1 (\_ r _ -> terminate r) l $
Yield
( f2 (\_ -> rest termLeft) termLeft r)
(\i left -> f2 (\_ -> rest termLeft) (addLeftover i left) r)
{-# INLINE composeSupply #-}
-- | The left side is run first, either side may return a value.
--
composeSupplyEither :: Monad m => Pipe i e m a -> Pipe e o m a -> Pipe i o m a
composeSupplyEither (Pipe f1) (Pipe f2) =
Pipe $ \rest l r ->
f1 (\l r -> rest l $ termRight r) l $
Yield
( f2 (\_ -> rest termLeft) termLeft r)
(\i left -> f2 (\_ -> rest termLeft) (addLeftover i left) r)
{-# INLINE composeSupplyEither #-}