{-# LANGUAGE CPP                        #-}
{-# LANGUAGE DataKinds                  #-}
{-# LANGUAGE DeriveFunctor              #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase                 #-}
{-# LANGUAGE PolyKinds                  #-}
{-# LANGUAGE RankNTypes                 #-}
{-# LANGUAGE ScopedTypeVariables        #-}
{-# LANGUAGE TemplateHaskell            #-}
{-# LANGUAGE TypeOperators              #-}
{-# OPTIONS_HADDOCK not-home            #-}

-- |
-- Module      : Data.Conduino.Internal
-- Copyright   : (c) Justin Le 2019
-- License     : BSD3
--
-- Maintainer  : justin@jle.im
-- Stability   : experimental
-- Portability : non-portable
--
-- Internal module exposing the internals of 'Pipe', including its
-- underlying representation and base functor.
--
module Data.Conduino.Internal (
    Pipe(..)
  , PipeF(..)
  , awaitEither
  , yield, yieldLazy
  , trimapPipe, trimapPipeF, mapInput, mapOutput, mapUpRes
  , hoistPipe
  , RecPipe
  , toRecPipe, fromRecPipe
  , withRecPipe
  , runStateP, runStatePS
  , pAwaitF, pYieldF
  ) where

import           Control.Applicative
import           Control.Monad.Catch
import           Control.Monad.Except
import           Control.Monad.Free.Class
import           Control.Monad.Free.TH
import           Control.Monad.RWS
import           Control.Monad.Trans.Free        (FreeT(..), FreeF(..))
import           Control.Monad.Trans.Free.Church
import           Control.Monad.Trans.State
import           Data.Functor
import qualified Control.Monad.Trans.State.Strict  as SS

#if !MIN_VERSION_base(4,13,0)
import           Control.Monad.Fail
#endif

#if MIN_VERSION_base(4,18,0)
import           Control.Monad (MonadPlus)
#endif

-- | Base functor of 'Pipe'.
--
-- A pipe fundamentally has the ability to await and the ability to yield.
-- The other functionality are implemented.
--
-- *  Lifting effects is implemented by the 'MonadTrans' and 'MonadIO'
--    instances that 'FT' gives.
-- *  /Ending/ with a result is implemented by the 'Applicative' instance's
--   'pure' that 'FT' gives.
-- *  Applicative and monadic sequenceing "after a pipe is done" is
--    implemented by the 'Applicative' and 'Monad' instances that 'FT'
--    gives.
--
-- On top of these we implement 'Data.Conduino..|' and other combinators
-- based on the structure that 'FT' gives.  For some functions, it can be
-- easier to use an alternative encoding, 'RecPipe', which is the same
-- thing but explicitly recursive.
data PipeF i o u a =
      PAwaitF (u -> a) (i -> a)
      -- todo: strict version?
    | PYieldF o a
  deriving forall a b. a -> PipeF i o u b -> PipeF i o u a
forall a b. (a -> b) -> PipeF i o u a -> PipeF i o u b
forall i o u a b. a -> PipeF i o u b -> PipeF i o u a
forall i o u a b. (a -> b) -> PipeF i o u a -> PipeF i o u b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> PipeF i o u b -> PipeF i o u a
$c<$ :: forall i o u a b. a -> PipeF i o u b -> PipeF i o u a
fmap :: forall a b. (a -> b) -> PipeF i o u a -> PipeF i o u b
$cfmap :: forall i o u a b. (a -> b) -> PipeF i o u a -> PipeF i o u b
Functor

makeFree ''PipeF

{-# INLINE pYieldF #-}
{-# INLINE pAwaitF #-}

-- | Similar to a conduit from the /conduit/ package.
--
-- For a @'Pipe' i o u m a@, you have:
--
-- *  @i@: Type of input stream (the things you can 'Data.Conduino.await')
-- *  @o@: Type of output stream (the things you 'yield')
-- *  @u@: Type of the /result/ of the upstream pipe (Outputted when
--    upstream pipe terminates)
-- *  @m@: Underlying monad (the things you can 'lift')
-- *  @a@: Result type when pipe terminates (outputted when finished, with
--    'pure' or 'return')
--
-- Some specializations:
--
-- *  If @i@ is @()@, the pipe is a /source/ --- it doesn't need anything
--    to produce items.  It will pump out items on its own, for pipes
--    downstream to receive and process.
--
-- *  If @o@ is 'Data.Void.Void', the pipe is a /sink/ --- it will never
--    'yield' anything downstream.  It will consume items from things
--    upstream, and produce a result (@a@) if and when it terminates.
--
-- *  If @u@ is 'Data.Void.Void', then the pipe's upstream is limitless,
--    and never terminates.  This means that you can use
--    'Data.Conduino.awaitSurely' instead of 'Data.Conduino.await', to get
--    await a value that is guaranteed to come.  You'll get an @i@ instead
--    of a @'Maybe' i@.
--
-- *  If @a@ is 'Data.Void.Void', then the pipe never terminates --- it
--    will keep on consuming and/or producing values forever.  If this is
--    a sink, it means that the sink will never terminate, and so
--    'Data.Conduino.runPipe' will also never terminate.  If it is
--    a source, it means that if you chain something downstream with
--    'Data.Conduino..|', that downstream pipe can use
--    'Data.Conduino.awaitSurely' to guarantee something being passed down.
--
-- Applicative and Monadic sequencing of pipes chains by exhaustion.
--
-- @
-- do pipeX
--    pipeY
--    pipeZ
-- @
--
-- is a pipe itself, that behaves like @pipeX@ until it terminates, then
-- @pipeY@ until it terminates, then @pipeZ@ until it terminates.  The
-- 'Monad' instance allows you to choose "which pipe to behave like next"
-- based on the terminating result of a previous pipe.
--
-- @
-- do x <- pipeX
--    pipeBasedOn x
-- @
--
-- Usually you would use it by chaining together pipes with
-- 'Data.Conduino..|' and then running the result with
-- 'Data.Conduino.runPipe'.
--
-- @
-- 'Data.Conduino.runPipe' $ someSource
--        'Data.Conduino..|' somePipe
--        .| someOtherPipe
--        .| someSink
-- @
--
-- See 'Data.Conduino..|' and 'Data.Conduino.runPipe' for more information
-- on usage.
--
-- For a "prelude" of commonly used 'Pipe's, see
-- "Data.Conduino.Combinators".
--
newtype Pipe i o u m a = Pipe { forall i o u (m :: * -> *) a.
Pipe i o u m a -> FT (PipeF i o u) m a
pipeFree :: FT (PipeF i o u) m a }
  deriving
    ( forall a b. a -> Pipe i o u m b -> Pipe i o u m a
forall a b. (a -> b) -> Pipe i o u m a -> Pipe i o u m b
forall i o u (m :: * -> *) a b.
a -> Pipe i o u m b -> Pipe i o u m a
forall i o u (m :: * -> *) a b.
(a -> b) -> Pipe i o u m a -> Pipe i o u m b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> Pipe i o u m b -> Pipe i o u m a
$c<$ :: forall i o u (m :: * -> *) a b.
a -> Pipe i o u m b -> Pipe i o u m a
fmap :: forall a b. (a -> b) -> Pipe i o u m a -> Pipe i o u m b
$cfmap :: forall i o u (m :: * -> *) a b.
(a -> b) -> Pipe i o u m a -> Pipe i o u m b
Functor
    , forall a. a -> Pipe i o u m a
forall a b. Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m a
forall a b. Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m b
forall a b.
Pipe i o u m (a -> b) -> Pipe i o u m a -> Pipe i o u m b
forall a b c.
(a -> b -> c) -> Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m c
forall i o u (m :: * -> *). Functor (Pipe i o u m)
forall i o u (m :: * -> *) a. a -> Pipe i o u m a
forall i o u (m :: * -> *) a b.
Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m a
forall i o u (m :: * -> *) a b.
Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m b
forall i o u (m :: * -> *) a b.
Pipe i o u m (a -> b) -> Pipe i o u m a -> Pipe i o u m b
forall i o u (m :: * -> *) a b c.
(a -> b -> c) -> Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
<* :: forall a b. Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m a
$c<* :: forall i o u (m :: * -> *) a b.
Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m a
*> :: forall a b. Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m b
$c*> :: forall i o u (m :: * -> *) a b.
Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m b
liftA2 :: forall a b c.
(a -> b -> c) -> Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m c
$cliftA2 :: forall i o u (m :: * -> *) a b c.
(a -> b -> c) -> Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m c
<*> :: forall a b.
Pipe i o u m (a -> b) -> Pipe i o u m a -> Pipe i o u m b
$c<*> :: forall i o u (m :: * -> *) a b.
Pipe i o u m (a -> b) -> Pipe i o u m a -> Pipe i o u m b
pure :: forall a. a -> Pipe i o u m a
$cpure :: forall i o u (m :: * -> *) a. a -> Pipe i o u m a
Applicative
    , forall a. a -> Pipe i o u m a
forall a b. Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m b
forall a b.
Pipe i o u m a -> (a -> Pipe i o u m b) -> Pipe i o u m b
forall i o u (m :: * -> *). Applicative (Pipe i o u m)
forall i o u (m :: * -> *) a. a -> Pipe i o u m a
forall i o u (m :: * -> *) a b.
Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m b
forall i o u (m :: * -> *) a b.
Pipe i o u m a -> (a -> Pipe i o u m b) -> Pipe i o u m b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: forall a. a -> Pipe i o u m a
$creturn :: forall i o u (m :: * -> *) a. a -> Pipe i o u m a
>> :: forall a b. Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m b
$c>> :: forall i o u (m :: * -> *) a b.
Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m b
>>= :: forall a b.
Pipe i o u m a -> (a -> Pipe i o u m b) -> Pipe i o u m b
$c>>= :: forall i o u (m :: * -> *) a b.
Pipe i o u m a -> (a -> Pipe i o u m b) -> Pipe i o u m b
Monad
    , forall i o u (m :: * -> *) a. Monad m => m a -> Pipe i o u m a
forall (m :: * -> *) a. Monad m => m a -> Pipe i o u m a
forall (t :: (* -> *) -> * -> *).
(forall (m :: * -> *) a. Monad m => m a -> t m a) -> MonadTrans t
lift :: forall (m :: * -> *) a. Monad m => m a -> Pipe i o u m a
$clift :: forall i o u (m :: * -> *) a. Monad m => m a -> Pipe i o u m a
MonadTrans
    , MonadFree (PipeF i o u)
    , forall a. IO a -> Pipe i o u m a
forall {i} {o} {u} {m :: * -> *}. MonadIO m => Monad (Pipe i o u m)
forall i o u (m :: * -> *) a. MonadIO m => IO a -> Pipe i o u m a
forall (m :: * -> *).
Monad m -> (forall a. IO a -> m a) -> MonadIO m
liftIO :: forall a. IO a -> Pipe i o u m a
$cliftIO :: forall i o u (m :: * -> *) a. MonadIO m => IO a -> Pipe i o u m a
MonadIO
    , MonadState s
    , MonadReader r
    , MonadWriter w
    , MonadError e
    , MonadRWS r w s
    , forall a. Pipe i o u m a
forall a. Pipe i o u m a -> Pipe i o u m [a]
forall a. Pipe i o u m a -> Pipe i o u m a -> Pipe i o u m a
forall {i} {o} {u} {m :: * -> *}.
Alternative m =>
Applicative (Pipe i o u m)
forall i o u (m :: * -> *) a. Alternative m => Pipe i o u m a
forall i o u (m :: * -> *) a.
Alternative m =>
Pipe i o u m a -> Pipe i o u m [a]
forall i o u (m :: * -> *) a.
Alternative m =>
Pipe i o u m a -> Pipe i o u m a -> Pipe i o u m a
forall (f :: * -> *).
Applicative f
-> (forall a. f a)
-> (forall a. f a -> f a -> f a)
-> (forall a. f a -> f [a])
-> (forall a. f a -> f [a])
-> Alternative f
many :: forall a. Pipe i o u m a -> Pipe i o u m [a]
$cmany :: forall i o u (m :: * -> *) a.
Alternative m =>
Pipe i o u m a -> Pipe i o u m [a]
some :: forall a. Pipe i o u m a -> Pipe i o u m [a]
$csome :: forall i o u (m :: * -> *) a.
Alternative m =>
Pipe i o u m a -> Pipe i o u m [a]
<|> :: forall a. Pipe i o u m a -> Pipe i o u m a -> Pipe i o u m a
$c<|> :: forall i o u (m :: * -> *) a.
Alternative m =>
Pipe i o u m a -> Pipe i o u m a -> Pipe i o u m a
empty :: forall a. Pipe i o u m a
$cempty :: forall i o u (m :: * -> *) a. Alternative m => Pipe i o u m a
Alternative
    , forall a. Pipe i o u m a
forall a. Pipe i o u m a -> Pipe i o u m a -> Pipe i o u m a
forall {i} {o} {u} {m :: * -> *}.
MonadPlus m =>
Monad (Pipe i o u m)
forall {i} {o} {u} {m :: * -> *}.
MonadPlus m =>
Alternative (Pipe i o u m)
forall i o u (m :: * -> *) a. MonadPlus m => Pipe i o u m a
forall i o u (m :: * -> *) a.
MonadPlus m =>
Pipe i o u m a -> Pipe i o u m a -> Pipe i o u m a
forall (m :: * -> *).
Alternative m
-> Monad m
-> (forall a. m a)
-> (forall a. m a -> m a -> m a)
-> MonadPlus m
mplus :: forall a. Pipe i o u m a -> Pipe i o u m a -> Pipe i o u m a
$cmplus :: forall i o u (m :: * -> *) a.
MonadPlus m =>
Pipe i o u m a -> Pipe i o u m a -> Pipe i o u m a
mzero :: forall a. Pipe i o u m a
$cmzero :: forall i o u (m :: * -> *) a. MonadPlus m => Pipe i o u m a
MonadPlus
    , forall e a. Exception e => e -> Pipe i o u m a
forall {i} {o} {u} {m :: * -> *}.
MonadThrow m =>
Monad (Pipe i o u m)
forall i o u (m :: * -> *) e a.
(MonadThrow m, Exception e) =>
e -> Pipe i o u m a
forall (m :: * -> *).
Monad m -> (forall e a. Exception e => e -> m a) -> MonadThrow m
throwM :: forall e a. Exception e => e -> Pipe i o u m a
$cthrowM :: forall i o u (m :: * -> *) e a.
(MonadThrow m, Exception e) =>
e -> Pipe i o u m a
MonadThrow
    , forall e a.
Exception e =>
Pipe i o u m a -> (e -> Pipe i o u m a) -> Pipe i o u m a
forall {i} {o} {u} {m :: * -> *}.
MonadCatch m =>
MonadThrow (Pipe i o u m)
forall i o u (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
Pipe i o u m a -> (e -> Pipe i o u m a) -> Pipe i o u m a
forall (m :: * -> *).
MonadThrow m
-> (forall e a. Exception e => m a -> (e -> m a) -> m a)
-> MonadCatch m
catch :: forall e a.
Exception e =>
Pipe i o u m a -> (e -> Pipe i o u m a) -> Pipe i o u m a
$ccatch :: forall i o u (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
Pipe i o u m a -> (e -> Pipe i o u m a) -> Pipe i o u m a
MonadCatch
    )

instance MonadFail m => MonadFail (Pipe i o u m) where
#if MIN_VERSION_base(4,13,0)
    fail :: forall a. String -> Pipe i o u m a
fail = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. MonadFail m => String -> m a
fail
#else
    fail = lift . Control.Monad.Fail.fail
#endif

-- | Await on upstream output.  Will block until it receives an @i@
-- (expected input type) or a @u@ if the upstream pipe terminates.
awaitEither :: Pipe i o u m (Either u i)
awaitEither :: forall i o u (m :: * -> *). Pipe i o u m (Either u i)
awaitEither = forall (m :: * -> *) i o u.
MonadFree (PipeF i o u) m =>
m (Either u i)
pAwaitF
{-# INLINE awaitEither #-}

-- | Send output downstream.
--
-- Since v0.2.3.0, is strict.  See 'yieldLazy' for the original behavior.
yield :: o -> Pipe i o u m ()
yield :: forall o i u (m :: * -> *). o -> Pipe i o u m ()
yield o
x = o
x seq :: forall a b. a -> b -> b
`seq` forall o i u (m :: * -> *). o -> Pipe i o u m ()
yieldLazy o
x
{-# INLINE yield #-}

-- | Send output downstream without forcing its argument.
--
-- @since 0.2.3.0
yieldLazy :: o -> Pipe i o u m ()
yieldLazy :: forall o i u (m :: * -> *). o -> Pipe i o u m ()
yieldLazy = forall (m :: * -> *) i o u. MonadFree (PipeF i o u) m => o -> m ()
pYieldF
{-# INLINE yieldLazy #-}

-- | Map over the input type, output type, and upstream result type.
--
-- If you want to map over the result type, use 'fmap'.
trimapPipe
    :: (i -> j)
    -> (p -> o)
    -> (u -> v)
    -> Pipe j p v m a
    -> Pipe i o u m a
trimapPipe :: forall i j p o u v (m :: * -> *) a.
(i -> j)
-> (p -> o) -> (u -> v) -> Pipe j p v m a -> Pipe i o u m a
trimapPipe i -> j
f p -> o
g u -> v
h (Pipe FT (PipeF j p v) m a
p) = forall i o u (m :: * -> *) a.
FT (PipeF i o u) m a -> Pipe i o u m a
Pipe (forall (f :: * -> *) (g :: * -> *) (m :: * -> *) b.
(forall a. f a -> g a) -> FT f m b -> FT g m b
transFT (forall i j p o u v a.
(i -> j) -> (p -> o) -> (u -> v) -> PipeF j p v a -> PipeF i o u a
trimapPipeF i -> j
f p -> o
g u -> v
h) FT (PipeF j p v) m a
p)
{-# INLINE trimapPipe #-}

trimapPipeF
    :: (i -> j)
    -> (p -> o)
    -> (u -> v)
    -> PipeF j p v a
    -> PipeF i o u a
trimapPipeF :: forall i j p o u v a.
(i -> j) -> (p -> o) -> (u -> v) -> PipeF j p v a -> PipeF i o u a
trimapPipeF i -> j
f p -> o
g u -> v
h = \case
    PAwaitF v -> a
a j -> a
b -> forall i o u a. (u -> a) -> (i -> a) -> PipeF i o u a
PAwaitF (v -> a
a forall b c a. (b -> c) -> (a -> b) -> a -> c
. u -> v
h) (j -> a
b forall b c a. (b -> c) -> (a -> b) -> a -> c
. i -> j
f)
    PYieldF p
a a
x -> forall i o u a. o -> a -> PipeF i o u a
PYieldF (p -> o
g p
a) a
x
{-# INLINE trimapPipeF #-}

-- | Transform the underlying monad of a pipe.
--
-- Note that if you are trying to work with monad transformers, this is
-- probably not what you want.  See "Data.Conduino.Lift" for tools for
-- working with underlying monad transformers.
hoistPipe
    :: (Monad m, Monad n)
    => (forall x. m x -> n x)
    -> Pipe i o u m a
    -> Pipe i o u n a
hoistPipe :: forall (m :: * -> *) (n :: * -> *) i o u a.
(Monad m, Monad n) =>
(forall x. m x -> n x) -> Pipe i o u m a -> Pipe i o u n a
hoistPipe forall x. m x -> n x
f = forall i o u (m :: * -> *) a.
FT (PipeF i o u) m a -> Pipe i o u m a
Pipe forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) (n :: * -> *) (f :: * -> *) b.
(Monad m, Monad n) =>
(forall a. m a -> n a) -> FT f m b -> FT f n b
hoistFT forall x. m x -> n x
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall i o u (m :: * -> *) a.
Pipe i o u m a -> FT (PipeF i o u) m a
pipeFree
{-# INLINE hoistPipe #-}

-- | (Contravariantly) map over the expected input type.
mapInput :: (i -> j) -> Pipe j o u m a -> Pipe i o u m a
mapInput :: forall i j o u (m :: * -> *) a.
(i -> j) -> Pipe j o u m a -> Pipe i o u m a
mapInput i -> j
f = forall i j p o u v (m :: * -> *) a.
(i -> j)
-> (p -> o) -> (u -> v) -> Pipe j p v m a -> Pipe i o u m a
trimapPipe i -> j
f forall a. a -> a
id forall a. a -> a
id
{-# INLINE mapInput #-}

-- | Map over the downstream output type.
--
-- If you want to map over the result type, use 'fmap'.
mapOutput :: (p -> o) -> Pipe i p u m a -> Pipe i o u m a
mapOutput :: forall p o i u (m :: * -> *) a.
(p -> o) -> Pipe i p u m a -> Pipe i o u m a
mapOutput p -> o
f = forall i j p o u v (m :: * -> *) a.
(i -> j)
-> (p -> o) -> (u -> v) -> Pipe j p v m a -> Pipe i o u m a
trimapPipe forall a. a -> a
id p -> o
f forall a. a -> a
id
{-# INLINE mapOutput #-}

-- | (Contravariantly) map over the upstream result type.
mapUpRes :: (u -> v) -> Pipe i o v m a -> Pipe i o u m a
mapUpRes :: forall u v i o (m :: * -> *) a.
(u -> v) -> Pipe i o v m a -> Pipe i o u m a
mapUpRes = forall i j p o u v (m :: * -> *) a.
(i -> j)
-> (p -> o) -> (u -> v) -> Pipe j p v m a -> Pipe i o u m a
trimapPipe forall a. a -> a
id forall a. a -> a
id
{-# INLINE mapUpRes #-}

-- | A version of 'Pipe' that uses explicit, concrete recursion instead of
-- church-encoding like 'Pipe'.  Some functions --- especially ones that
-- combine multiple pipes into one --- are easier to implement in this
-- form.
type RecPipe i o u = FreeT (PipeF i o u)

-- | Convert from a 'Pipe' to a 'RecPipe'.  While most of this library is
-- defined in terms of 'Pipe', it can be easier to write certain low-level
-- pipe combining functions in terms of 'RecPipe' than 'Pipe'.
toRecPipe :: Monad m => Pipe i o u m a -> RecPipe i o u m a
toRecPipe :: forall (m :: * -> *) i o u a.
Monad m =>
Pipe i o u m a -> RecPipe i o u m a
toRecPipe = forall (m :: * -> *) (f :: * -> *) a.
(Monad m, Functor f) =>
FT f m a -> FreeT f m a
_fromFT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall i o u (m :: * -> *) a.
Pipe i o u m a -> FT (PipeF i o u) m a
pipeFree
{-# INLINE toRecPipe #-}

-- | An inlined version of fromFT
_fromFT :: (Monad m, Functor f) => FT f m a -> FreeT f m a
_fromFT :: forall (m :: * -> *) (f :: * -> *) a.
(Monad m, Functor f) =>
FT f m a -> FreeT f m a
_fromFT (FT forall r. (a -> m r) -> (forall x. (x -> m r) -> f x -> m r) -> m r
k) = forall (f :: * -> *) (m :: * -> *) a.
m (FreeF f a (FreeT f m a)) -> FreeT f m a
FreeT forall a b. (a -> b) -> a -> b
$ forall r. (a -> m r) -> (forall x. (x -> m r) -> f x -> m r) -> m r
k (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. a -> FreeF f a b
Pure) (\x -> m (FreeF f a (FreeT f m a))
xg -> forall (f :: * -> *) (m :: * -> *) a.
FreeT f m a -> m (FreeF f a (FreeT f m a))
runFreeT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) (m :: * -> *) a.
MonadFree f m =>
f (m a) -> m a
wrap forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (f :: * -> *) (m :: * -> *) a.
m (FreeF f a (FreeT f m a)) -> FreeT f m a
FreeT forall b c a. (b -> c) -> (a -> b) -> a -> c
. x -> m (FreeF f a (FreeT f m a))
xg))
{-# INLINE _fromFT #-}

-- | Convert a 'RecPipe' back into a 'Pipe'.
fromRecPipe :: Monad m => RecPipe i o u m a -> Pipe i o u m a
fromRecPipe :: forall (m :: * -> *) i o u a.
Monad m =>
RecPipe i o u m a -> Pipe i o u m a
fromRecPipe = forall i o u (m :: * -> *) a.
FT (PipeF i o u) m a -> Pipe i o u m a
Pipe forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) (f :: * -> *) a.
Monad m =>
FreeT f m a -> FT f m a
toFT
{-# INLINE fromRecPipe #-}

-- | Convenint wrapper over 'toRecPipe' and 'fromRecPipe'.
--
-- @since 0.2.1.0
withRecPipe
    :: (Monad m, Monad n)
    => (RecPipe i o u m a -> RecPipe j p v n b)
    -> Pipe i o u m a
    -> Pipe j p v n b
withRecPipe :: forall (m :: * -> *) (n :: * -> *) i o u a j p v b.
(Monad m, Monad n) =>
(RecPipe i o u m a -> RecPipe j p v n b)
-> Pipe i o u m a -> Pipe j p v n b
withRecPipe RecPipe i o u m a -> RecPipe j p v n b
f = forall (m :: * -> *) i o u a.
Monad m =>
RecPipe i o u m a -> Pipe i o u m a
fromRecPipe forall b c a. (b -> c) -> (a -> b) -> a -> c
. RecPipe i o u m a -> RecPipe j p v n b
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) i o u a.
Monad m =>
Pipe i o u m a -> RecPipe i o u m a
toRecPipe
{-# INLINE withRecPipe #-}

-- | Turn a 'Pipe' that runs over 'StateT' into a "state-modifying 'Pipe'",
-- that returns the final state when it terminates.
--
-- The main usage of this is to "isolate" the state from other pipes in the
-- same chain.  For example, of @p@, @q@, and @r@ are all pipes under
-- 'StateT', then:
--
-- @
--     p
--  .| q
--  .| r
-- @
--
-- will all share underlying state, and each can modify the state that they
-- all three share.  We essentially have global state.
--
-- However, if you use 'runStateP', you can all have them use different
-- encapsulated states.
--
-- @
--     void (runStateP s0 p)
--  .| void (runStateP s1 q)
--  .| runStateP s2 r
-- @
--
-- In this case, each of those three chained pipes will use their own
-- internal states, without sharing.
--
-- This is also useful if you want to chain a pipe over 'StateT' with
-- pipes that don't use state at all: for example if @a@ and @b@ are
-- "non-stateful" pipes (/not/ over 'StateT'), you can do:
--
-- @
--     a
--  .| void (runStateP s1 q)
--  .| b
-- @
--
-- And @a@ and @b@ will be none the wiser to the fact that @q@ uses
-- 'StateT' internally.
--
-- Note to avoid the usage of 'void', 'Data.Conduino.Lift.evalStateP' might
-- be more useful.
--
-- @since 0.2.1.0
runStateP
    :: Monad m
    => s
    -> Pipe i o u (StateT s m) a
    -> Pipe i o u m (a, s)
runStateP :: forall (m :: * -> *) s i o u a.
Monad m =>
s -> Pipe i o u (StateT s m) a -> Pipe i o u m (a, s)
runStateP = forall (m :: * -> *) (n :: * -> *) i o u a j p v b.
(Monad m, Monad n) =>
(RecPipe i o u m a -> RecPipe j p v n b)
-> Pipe i o u m a -> Pipe j p v n b
withRecPipe forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {m :: * -> *} {f :: * -> *} {t} {a}.
(Functor m, Functor f) =>
t -> FreeT f (StateT t m) a -> FreeT f m (a, t)
go
  where
    go :: t -> FreeT f (StateT t m) a -> FreeT f m (a, t)
go t
s (FreeT StateT t m (FreeF f a (FreeT f (StateT t m) a))
p) = forall (f :: * -> *) (m :: * -> *) a.
m (FreeF f a (FreeT f m a)) -> FreeT f m a
FreeT forall a b. (a -> b) -> a -> b
$ forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT StateT t m (FreeF f a (FreeT f (StateT t m) a))
p t
s forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \(FreeF f a (FreeT f (StateT t m) a)
q, t
s') ->
      case FreeF f a (FreeT f (StateT t m) a)
q of
        Pure a
x -> forall (f :: * -> *) a b. a -> FreeF f a b
Pure (a
x, t
s')
        Free f (FreeT f (StateT t m) a)
l -> forall (f :: * -> *) a b. f b -> FreeF f a b
Free forall a b. (a -> b) -> a -> b
$ t -> FreeT f (StateT t m) a -> FreeT f m (a, t)
go t
s' forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> f (FreeT f (StateT t m) a)
l
{-# INLINE runStateP #-}

-- | 'runStateP', but for "Control.Monad.Trans.State.Strict".
--
-- @since 0.2.1.0
runStatePS
    :: Monad m
    => s
    -> Pipe i o u (SS.StateT s m) a
    -> Pipe i o u m (a, s)
runStatePS :: forall (m :: * -> *) s i o u a.
Monad m =>
s -> Pipe i o u (StateT s m) a -> Pipe i o u m (a, s)
runStatePS = forall (m :: * -> *) (n :: * -> *) i o u a j p v b.
(Monad m, Monad n) =>
(RecPipe i o u m a -> RecPipe j p v n b)
-> Pipe i o u m a -> Pipe j p v n b
withRecPipe forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {m :: * -> *} {f :: * -> *} {t} {a}.
(Functor m, Functor f) =>
t -> FreeT f (StateT t m) a -> FreeT f m (a, t)
go
  where
    go :: t -> FreeT f (StateT t m) a -> FreeT f m (a, t)
go t
s (FreeT StateT t m (FreeF f a (FreeT f (StateT t m) a))
p) = forall (f :: * -> *) (m :: * -> *) a.
m (FreeF f a (FreeT f m a)) -> FreeT f m a
FreeT forall a b. (a -> b) -> a -> b
$ forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
SS.runStateT StateT t m (FreeF f a (FreeT f (StateT t m) a))
p t
s forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \(FreeF f a (FreeT f (StateT t m) a)
q, t
s') ->
      case FreeF f a (FreeT f (StateT t m) a)
q of
        Pure a
x -> forall (f :: * -> *) a b. a -> FreeF f a b
Pure (a
x, t
s')
        Free f (FreeT f (StateT t m) a)
l -> forall (f :: * -> *) a b. f b -> FreeF f a b
Free forall a b. (a -> b) -> a -> b
$ t -> FreeT f (StateT t m) a -> FreeT f m (a, t)
go t
s' forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> f (FreeT f (StateT t m) a)
l
{-# INLINE runStatePS #-}