{-# LANGUAGE CPP
, NoImplicitPrelude
, RankNTypes
, TypeFamilies
, FunctionalDependencies
, FlexibleInstances
, UndecidableInstances
, MultiParamTypeClasses #-}
#if __GLASGOW_HASKELL__ >= 702
{-# LANGUAGE Safe #-}
#endif
#if MIN_VERSION_transformers(0,4,0)
{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}
#endif
module Control.Monad.Trans.Control
(
MonadTransControl(..), Run
, RunDefault, defaultLiftWith, defaultRestoreT
, MonadBaseControl (..), RunInBase
, ComposeSt, RunInBaseDefault, defaultLiftBaseWith, defaultRestoreM
, control, embed, embed_, captureT, captureM
, liftBaseOp, liftBaseOp_
, liftBaseDiscard, liftBaseOpDiscard
, liftThrough
) where
import Data.Function ( (.), ($), const )
import Data.Monoid ( Monoid, mempty )
import Control.Monad ( Monad, (>>=), return, liftM )
import System.IO ( IO )
import Data.Maybe ( Maybe )
import Data.Either ( Either )
#if MIN_VERSION_base(4,4,0)
import Control.Monad.ST.Lazy.Safe ( ST )
import qualified Control.Monad.ST.Safe as Strict ( ST )
#endif
import Control.Monad.STM ( STM )
import Control.Monad.Trans.Class ( MonadTrans )
import Control.Monad.Trans.Identity ( IdentityT(IdentityT), runIdentityT )
import Control.Monad.Trans.List ( ListT (ListT), runListT )
import Control.Monad.Trans.Maybe ( MaybeT (MaybeT), runMaybeT )
import Control.Monad.Trans.Error ( ErrorT (ErrorT), runErrorT, Error )
import Control.Monad.Trans.Reader ( ReaderT (ReaderT), runReaderT )
import Control.Monad.Trans.State ( StateT (StateT), runStateT )
import Control.Monad.Trans.Writer ( WriterT (WriterT), runWriterT )
import Control.Monad.Trans.RWS ( RWST (RWST), runRWST )
import Control.Monad.Trans.Except ( ExceptT (ExceptT), runExceptT )
import qualified Control.Monad.Trans.RWS.Strict as Strict ( RWST (RWST), runRWST )
import qualified Control.Monad.Trans.State.Strict as Strict ( StateT (StateT), runStateT )
import qualified Control.Monad.Trans.Writer.Strict as Strict ( WriterT(WriterT), runWriterT )
import Data.Functor.Identity ( Identity )
import Control.Monad.Base ( MonadBase )
#if MIN_VERSION_base(4,3,0)
import Control.Monad ( void )
#else
import Data.Functor (Functor, fmap)
void :: Functor f => f a -> f ()
void = fmap (const ())
#endif
import Prelude (id)
class MonadTrans t => MonadTransControl t where
type StT t a :: *
liftWith :: Monad m => (Run t -> m a) -> t m a
restoreT :: Monad m => m (StT t a) -> t m a
type Run t = forall n b. Monad n => t n b -> n (StT t b)
type RunDefault t t' = forall n b. Monad n => t n b -> n (StT t' b)
defaultLiftWith :: (Monad m, MonadTransControl n)
=> (forall b. n m b -> t m b)
-> (forall o b. t o b -> n o b)
-> (RunDefault t n -> m a)
-> t m a
defaultLiftWith t unT = \f -> t $ liftWith $ \run -> f $ run . unT
{-# INLINABLE defaultLiftWith #-}
defaultRestoreT :: (Monad m, MonadTransControl n)
=> (n m a -> t m a)
-> m (StT n a)
-> t m a
defaultRestoreT t = t . restoreT
{-# INLINABLE defaultRestoreT #-}
instance MonadTransControl IdentityT where
type StT IdentityT a = a
liftWith f = IdentityT $ f $ runIdentityT
restoreT = IdentityT
{-# INLINABLE liftWith #-}
{-# INLINABLE restoreT #-}
instance MonadTransControl MaybeT where
type StT MaybeT a = Maybe a
liftWith f = MaybeT $ liftM return $ f $ runMaybeT
restoreT = MaybeT
{-# INLINABLE liftWith #-}
{-# INLINABLE restoreT #-}
instance Error e => MonadTransControl (ErrorT e) where
type StT (ErrorT e) a = Either e a
liftWith f = ErrorT $ liftM return $ f $ runErrorT
restoreT = ErrorT
{-# INLINABLE liftWith #-}
{-# INLINABLE restoreT #-}
instance MonadTransControl (ExceptT e) where
type StT (ExceptT e) a = Either e a
liftWith f = ExceptT $ liftM return $ f $ runExceptT
restoreT = ExceptT
{-# INLINABLE liftWith #-}
{-# INLINABLE restoreT #-}
instance MonadTransControl ListT where
type StT ListT a = [a]
liftWith f = ListT $ liftM return $ f $ runListT
restoreT = ListT
{-# INLINABLE liftWith #-}
{-# INLINABLE restoreT #-}
instance MonadTransControl (ReaderT r) where
type StT (ReaderT r) a = a
liftWith f = ReaderT $ \r -> f $ \t -> runReaderT t r
restoreT = ReaderT . const
{-# INLINABLE liftWith #-}
{-# INLINABLE restoreT #-}
instance MonadTransControl (StateT s) where
type StT (StateT s) a = (a, s)
liftWith f = StateT $ \s ->
liftM (\x -> (x, s))
(f $ \t -> runStateT t s)
restoreT = StateT . const
{-# INLINABLE liftWith #-}
{-# INLINABLE restoreT #-}
instance MonadTransControl (Strict.StateT s) where
type StT (Strict.StateT s) a = (a, s)
liftWith f = Strict.StateT $ \s ->
liftM (\x -> (x, s))
(f $ \t -> Strict.runStateT t s)
restoreT = Strict.StateT . const
{-# INLINABLE liftWith #-}
{-# INLINABLE restoreT #-}
instance Monoid w => MonadTransControl (WriterT w) where
type StT (WriterT w) a = (a, w)
liftWith f = WriterT $ liftM (\x -> (x, mempty))
(f $ runWriterT)
restoreT = WriterT
{-# INLINABLE liftWith #-}
{-# INLINABLE restoreT #-}
instance Monoid w => MonadTransControl (Strict.WriterT w) where
type StT (Strict.WriterT w) a = (a, w)
liftWith f = Strict.WriterT $ liftM (\x -> (x, mempty))
(f $ Strict.runWriterT)
restoreT = Strict.WriterT
{-# INLINABLE liftWith #-}
{-# INLINABLE restoreT #-}
instance Monoid w => MonadTransControl (RWST r w s) where
type StT (RWST r w s) a = (a, s, w)
liftWith f = RWST $ \r s -> liftM (\x -> (x, s, mempty))
(f $ \t -> runRWST t r s)
restoreT mSt = RWST $ \_ _ -> mSt
{-# INLINABLE liftWith #-}
{-# INLINABLE restoreT #-}
instance Monoid w => MonadTransControl (Strict.RWST r w s) where
type StT (Strict.RWST r w s) a = (a, s, w)
liftWith f =
Strict.RWST $ \r s -> liftM (\x -> (x, s, mempty))
(f $ \t -> Strict.runRWST t r s)
restoreT mSt = Strict.RWST $ \_ _ -> mSt
{-# INLINABLE liftWith #-}
{-# INLINABLE restoreT #-}
class MonadBase b m => MonadBaseControl b m | m -> b where
type StM m a :: *
liftBaseWith :: (RunInBase m b -> b a) -> m a
restoreM :: StM m a -> m a
type RunInBase m b = forall a. m a -> b (StM m a)
#define BASE(M) \
instance MonadBaseControl (M) (M) where { \
type StM (M) a = a; \
liftBaseWith f = f id; \
restoreM = return; \
{-# INLINABLE liftBaseWith #-}; \
{-# INLINABLE restoreM #-}}
BASE(IO)
BASE(Maybe)
BASE(Either e)
BASE([])
BASE((->) r)
BASE(Identity)
BASE(STM)
#if MIN_VERSION_base(4,4,0)
BASE(Strict.ST s)
BASE( ST s)
#endif
#undef BASE
type ComposeSt t m a = StM m (StT t a)
type RunInBaseDefault t m b = forall a. t m a -> b (ComposeSt t m a)
defaultLiftBaseWith :: (MonadTransControl t, MonadBaseControl b m)
=> (RunInBaseDefault t m b -> b a) -> t m a
defaultLiftBaseWith = \f -> liftWith $ \run ->
liftBaseWith $ \runInBase ->
f $ runInBase . run
{-# INLINABLE defaultLiftBaseWith #-}
defaultRestoreM :: (MonadTransControl t, MonadBaseControl b m)
=> ComposeSt t m a -> t m a
defaultRestoreM = restoreT . restoreM
{-# INLINABLE defaultRestoreM #-}
#define BODY(T) { \
type StM (T m) a = ComposeSt (T) m a; \
liftBaseWith = defaultLiftBaseWith; \
restoreM = defaultRestoreM; \
{-# INLINABLE liftBaseWith #-}; \
{-# INLINABLE restoreM #-}}
#define TRANS( T) \
instance ( MonadBaseControl b m) => MonadBaseControl b (T m) where BODY(T)
#define TRANS_CTX(CTX, T) \
instance (CTX, MonadBaseControl b m) => MonadBaseControl b (T m) where BODY(T)
TRANS(IdentityT)
TRANS(MaybeT)
TRANS(ListT)
TRANS(ReaderT r)
TRANS(Strict.StateT s)
TRANS( StateT s)
TRANS(ExceptT e)
TRANS_CTX(Error e, ErrorT e)
TRANS_CTX(Monoid w, Strict.WriterT w)
TRANS_CTX(Monoid w, WriterT w)
TRANS_CTX(Monoid w, Strict.RWST r w s)
TRANS_CTX(Monoid w, RWST r w s)
control :: MonadBaseControl b m => (RunInBase m b -> b (StM m a)) -> m a
control f = liftBaseWith f >>= restoreM
{-# INLINABLE control #-}
embed :: MonadBaseControl b m => (a -> m c) -> m (a -> b (StM m c))
embed f = liftBaseWith $ \runInBase -> return (runInBase . f)
{-# INLINABLE embed #-}
embed_ :: MonadBaseControl b m => (a -> m ()) -> m (a -> b ())
embed_ f = liftBaseWith $ \runInBase -> return (void . runInBase . f)
{-# INLINABLE embed_ #-}
captureT :: (MonadTransControl t, Monad (t m), Monad m) => t m (StT t ())
captureT = liftWith $ \runInM -> runInM (return ())
{-# INLINABLE captureT #-}
captureM :: MonadBaseControl b m => m (StM m ())
captureM = liftBaseWith $ \runInBase -> runInBase (return ())
{-# INLINABLE captureM #-}
liftBaseOp :: MonadBaseControl b m
=> ((a -> b (StM m c)) -> b (StM m d))
-> ((a -> m c) -> m d)
liftBaseOp f = \g -> control $ \runInBase -> f $ runInBase . g
{-# INLINABLE liftBaseOp #-}
liftBaseOp_ :: MonadBaseControl b m
=> (b (StM m a) -> b (StM m c))
-> ( m a -> m c)
liftBaseOp_ f = \m -> control $ \runInBase -> f $ runInBase m
{-# INLINABLE liftBaseOp_ #-}
liftBaseDiscard :: MonadBaseControl b m => (b () -> b a) -> (m () -> m a)
liftBaseDiscard f = \m -> liftBaseWith $ \runInBase -> f $ void $ runInBase m
{-# INLINABLE liftBaseDiscard #-}
liftBaseOpDiscard :: MonadBaseControl b m
=> ((a -> b ()) -> b c)
-> (a -> m ()) -> m c
liftBaseOpDiscard f g = liftBaseWith $ \runInBase -> f $ void . runInBase . g
{-# INLINABLE liftBaseOpDiscard #-}
liftThrough
:: (MonadTransControl t, Monad (t m), Monad m)
=> (m (StT t a) -> m (StT t b))
-> t m a -> t m b
liftThrough f t = do
st <- liftWith $ \run -> do
f $ run t
restoreT $ return st