| Copyright | Bas van Dijk Anders Kaseorg | 
|---|---|
| License | BSD3 | 
| Maintainer | Bas van Dijk <v.dijk.bas@gmail.com> | 
| Safe Haskell | Safe | 
| Language | Haskell2010 | 
Control.Monad.Trans.Control
Description
This module defines the type class MonadBaseControl, a subset of
MonadBase into which generic control operations such as catch can be
lifted from IO or any other base monad. Instances are based on monad
transformers in MonadTransControl, which includes all standard monad
transformers in the transformers library except ContT.
See the lifted-base
package which uses monad-control to lift IO
operations from the base library (like catch or bracket) into any monad
that is an instance of MonadBase or MonadBaseControl.
See the following tutorial by Michael Snoyman on how to use this package:
https://www.yesodweb.com/book/monad-control
Quick implementation guide
Given a base monad B and a stack of transformers T:
- Define instances MonadTransControlTT, using thedefaultLiftWithdefaultRestoreTT.
- Define an instance - MonadBaseControlB B- instance MonadBaseControl B B where type StM B a = a liftBaseWith f = f- idrestoreM =- return
- Define instances - MonadBaseControlB m =>- MonadBaseControlB (T m)- instance MonadBaseControl b m => MonadBaseControl b (T m) where type StM (T m) a =- ComposeStT m a liftBaseWith f =- defaultLiftBaseWithrestoreM =- defaultRestoreM
Synopsis
- class MonadTrans t => MonadTransControl t where
- 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
- defaultRestoreT :: (Monad m, MonadTransControl n) => (n m a -> t m a) -> m (StT n a) -> t m a
- type RunDefault2 t n n' = forall m b. (Monad m, Monad (n' m)) => t m b -> m (StT n' (StT n b))
- defaultLiftWith2 :: (Monad m, Monad (n' m), MonadTransControl n, MonadTransControl n') => (forall b. n (n' m) b -> t m b) -> (forall o b. t o b -> n (n' o) b) -> (RunDefault2 t n n' -> m a) -> t m a
- defaultRestoreT2 :: (Monad m, Monad (n' m), MonadTransControl n, MonadTransControl n') => (n (n' m) a -> t m a) -> m (StT n' (StT n a)) -> t m a
- 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)
- 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
- defaultRestoreM :: (MonadTransControl t, MonadBaseControl b m) => ComposeSt t m a -> t m a
- control :: MonadBaseControl b m => (RunInBase m b -> b (StM m a)) -> m a
- controlT :: (MonadTransControl t, Monad (t m), Monad m) => (Run t -> m (StT t a)) -> t m a
- embed :: MonadBaseControl b m => (a -> m c) -> m (a -> b (StM m c))
- embed_ :: MonadBaseControl b m => (a -> m ()) -> m (a -> b ())
- captureT :: (MonadTransControl t, Monad (t m), Monad m) => t m (StT t ())
- captureM :: MonadBaseControl b m => m (StM m ())
- liftBaseOp :: MonadBaseControl b m => ((a -> b (StM m c)) -> b (StM m d)) -> (a -> m c) -> m d
- liftBaseOp_ :: MonadBaseControl b m => (b (StM m a) -> b (StM m c)) -> m a -> m c
- liftBaseDiscard :: MonadBaseControl b m => (b () -> b a) -> m () -> m a
- liftBaseOpDiscard :: MonadBaseControl b m => ((a -> b ()) -> b c) -> (a -> m ()) -> m c
- liftThrough :: (MonadTransControl t, Monad (t m), Monad m) => (m (StT t a) -> m (StT t b)) -> t m a -> t m b
MonadTransControl
class MonadTrans t => MonadTransControl t where Source #
The MonadTransControl type class is a stronger version of MonadTrans
Instances of MonadTranslift
MonadTransControl
This allows to lift functions that have a monad transformer in both positive and negative position. Take, for example, the function
withFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r
MonadTranswithFile
 function:
withFileLifted :: MonadTrans t => FilePath -> IOMode -> (Handle -> IO r) -> t IO r withFileLifted file mode action = lift (withFile file mode action)
However, MonadTranswithFileLifted
 accept a function that returns t IO. The reason is that we need to take
 away the transformer layer in order to pass the function to withFileMonadTransControl
withFileLifted' :: (Monad (t IO), MonadTransControl t) => FilePath -> IOMode -> (Handle -> t IO r) -> t IO r withFileLifted' file mode action = liftWith (\run -> withFile file mode (run . action)) >>= restoreT . return
Associated Types
Monadic state of t.
The monadic state of a monad transformer is the result type of its run
 function, e.g.:
runReaderT::ReaderTr m a -> r -> m aStT(ReaderTr) a ~ arunStateT::StateTs m a -> s -> m (a, s)StT(StateTs) a ~ (a, s)runMaybeT::MaybeTm a -> m (Maybea)StTMaybeTa ~Maybea
Provided type instances:
StTIdentityTa ~ a StTMaybeTa ~Maybea StT (ErrorTe) a ~Errore =>Eithere a StT (ExceptTe) a ~Eithere a StTListTa ~ [a] StT (ReaderTr) a ~ a StT (StateTs) a ~ (a, s) StT (WriterTw) a ~Monoidw => (a, w) StT (RWSTr w s) a ~Monoidw => (a, s, w)
Methods
liftWith :: Monad m => (Run t -> m a) -> t m a Source #
liftWith is similar to lift in that it lifts a computation from
 the argument monad to the constructed monad.
Instances should satisfy similar laws as the MonadTrans laws:
liftWith (\_ -> return a) = return a
liftWith (\_ -> m >>= f) = liftWith (\_ -> m) >>= (\a -> liftWith (\_ -> f a))
The difference with lift is that before lifting the m computation
 liftWith captures the state of t. It then provides the m
 computation with a Run function that allows running t n computations in
 n (for all n) on the captured state, e.g.
withFileLifted :: (Monad (t IO), MonadTransControl t) => FilePath -> IOMode -> (Handle -> t IO r) -> t IO r withFileLifted file mode action = liftWith (\run -> withFile file mode (run . action)) >>= restoreT . return
If the Run function is ignored, liftWith coincides with lift:
lift f = liftWith (\_ -> f)
Implementations use the Run
liftWith ::Monadm => ((Monadn =>ReaderTr n b -> n b) -> m a) ->ReaderTr m a liftWith f =ReaderT(\r -> f (\action ->runReaderTaction r)) liftWith ::Monadm => ((Monadn =>StateTs n b -> n (b, s)) -> m a) ->StateTs m a liftWith f =StateT(\s ->liftM(\x -> (x, s)) (f (\action ->runStateTaction s))) liftWith ::Monadm => ((Monadn =>MaybeTn b -> n (Maybeb)) -> m a) ->MaybeTm a liftWith f =MaybeT(liftMJust(frunMaybeT))
restoreT :: Monad m => m (StT t a) -> t m a Source #
Construct a t computation from the monadic state of t that is
 returned from a Run function.
Instances should satisfy:
liftWith (\run -> run t) >>= restoreT . return = t
restoreT is usually implemented through the constructor of the monad
 transformer:
ReaderT:: (r -> m a) ->ReaderTr m a restoreT :: m a ->ReaderTr m a restoreT action =ReaderT{ runReaderT =constaction }StateT:: (s -> m (a, s)) ->StateTs m a restoreT :: m (a, s) ->StateTs m a restoreT action =StateT{ runStateT =constaction }MaybeT:: m (Maybea) ->MaybeTm a restoreT :: m (Maybea) ->MaybeTm a restoreT action =MaybeTaction
Example type signatures:
restoreT ::Monadm => m a ->IdentityTm a restoreT ::Monadm => m (Maybea) ->MaybeTm a restoreT :: (Monadm,Errore) => m (Eithere a) ->ErrorTe m a restoreT ::Monadm => m (Eithere a) ->ExceptTe m a restoreT ::Monadm => m [a] ->ListTm a restoreT ::Monadm => m a ->ReaderTr m a restoreT ::Monadm => m (a, s) ->StateTs m a restoreT :: (Monadm,Monoidw) => m (a, w) ->WriterTw m a restoreT :: (Monadm,Monoidw) => m (a, s, w) ->RWSTr w s m a
Instances
| MonadTransControl MaybeT Source # | |
| MonadTransControl (ExceptT e) Source # | |
| MonadTransControl (IdentityT :: (Type -> Type) -> Type -> Type) Source # | |
| MonadTransControl (ReaderT r) Source # | |
| MonadTransControl (StateT s) Source # | |
| MonadTransControl (StateT s) Source # | |
| Monoid w => MonadTransControl (WriterT w) Source # | |
| Monoid w => MonadTransControl (WriterT w) Source # | |
| Monoid w => MonadTransControl (RWST r w s) Source # | |
| Monoid w => MonadTransControl (RWST r w s) Source # | |
type Run t = forall n b. Monad n => t n b -> n (StT t b) Source #
A function that runs a transformed monad t n on the monadic state that
 was captured by liftWith
A Run t function yields a computation in n that returns the monadic state
 of t. This state can later be used to restore a t computation using
 restoreT.
Example type equalities:
RunIdentityT~ forall n b.Monadn =>IdentityTn b -> n b RunMaybeT~ forall n b.Monadn =>MaybeTn b -> n (Maybeb) Run (ErrorTe) ~ forall n b. (Monadn,Errore) =>ErrorTe n b -> n (Eithere b) Run (ExceptTe) ~ forall n b.Monadn =>ExceptTe n b -> n (Eithere b) RunListT~ forall n b.Monadn =>ListTn b -> n [b] Run (ReaderTr) ~ forall n b.Monadn =>ReaderTr n b -> n b Run (StateTs) ~ forall n b.Monadn =>StateTs n b -> n (a, s) Run (WriterTw) ~ forall n b. (Monadn,Monoidw) =>WriterTw n b -> n (a, w) Run (RWSTr w s) ~ forall n b. (Monadn,Monoidw) =>RWSTr w s n b -> n (a, s, w)
This type is usually satisfied by the run function of a transformer:
fliprunReaderT:: r -> Run (ReaderTr)fliprunStateT:: s -> Run (StateTs)runMaybeT:: RunMaybeT
Defaults
The following functions can be used to define a MonadTransControl instance
 for a monad transformer which simply is a newtype around another monad
 transformer which already has a MonadTransControl instance. For example:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeFamilies #-}
newtype CounterT m a = CounterT {unCounterT :: StateT Int m a}
  deriving (Monad, MonadTrans)
instance MonadTransControl CounterT where
    type StT CounterT a = StT (StateT Int) a
    liftWith = defaultLiftWith CounterT unCounterT
    restoreT = defaultRestoreT CounterT
type RunDefault t t' = forall n b. Monad n => t n b -> n (StT t' b) Source #
A function like Run that runs a monad transformer t which wraps the
 monad transformer t'. This is used in defaultLiftWith.
Arguments
| :: (Monad m, MonadTransControl n) | |
| => (forall b. n m b -> t m b) | Monad constructor | 
| -> (forall o b. t o b -> n o b) | Monad deconstructor | 
| -> (RunDefault t n -> m a) | |
| -> t m a | 
Default definition for the liftWith method.
Arguments
| :: (Monad m, MonadTransControl n) | |
| => (n m a -> t m a) | Monad constructor | 
| -> m (StT n a) | |
| -> t m a | 
Default definition for the restoreT method.
Defaults for a stack of two
The following functions can be used to define a MonadTransControl instance
 for a monad transformer stack of two.
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype CalcT m a = CalcT { unCalcT :: StateT Int (ExceptT String m) a }
  deriving (Monad, MonadTrans)
instance MonadTransControl CalcT where
    type StT CalcT a = StT (ExceptT String) (StT (StateT Int) a)
    liftWith = defaultLiftWith2 CalcT unCalcT
    restoreT = defaultRestoreT2 CalcT
type RunDefault2 t n n' = forall m b. (Monad m, Monad (n' m)) => t m b -> m (StT n' (StT n b)) Source #
A function like Run that runs a monad transformer t which wraps the
 monad transformers n and n'. This is used in defaultLiftWith2.
Arguments
| :: (Monad m, Monad (n' m), MonadTransControl n, MonadTransControl n') | |
| => (forall b. n (n' m) b -> t m b) | Monad constructor | 
| -> (forall o b. t o b -> n (n' o) b) | Monad deconstructor | 
| -> (RunDefault2 t n n' -> m a) | |
| -> t m a | 
Default definition for the liftWith method.
Arguments
| :: (Monad m, Monad (n' m), MonadTransControl n, MonadTransControl n') | |
| => (n (n' m) a -> t m a) | Monad constructor | 
| -> m (StT n' (StT n a)) | |
| -> t m a | 
Default definition for the restoreT method for double MonadTransControl.
MonadBaseControl
class MonadBase b m => MonadBaseControl b m | m -> b where Source #
Writing instances
The usual way to write a MonadBaseControlB is to write an instance MonadBaseControl B B
 for the base monad, and MonadTransControl T instances for every transformer
 T. Instances for MonadBaseControlComposeStdefaultLiftBaseWithdefaultRestoreM
Associated Types
Monadic state that m adds to the base monad b.
For all base (non-transformed) monads, StM m a ~ a:
StMIOa ~ a StMMaybea ~ a StM (Eithere) a ~ a StM [] a ~ a StM ((->) r) a ~ a StMIdentitya ~ a StMSTMa ~ a StM (STs) a ~ a
If m is a transformed monad, m ~ t b, StMt (given by its StT from MonadTransControl). For a
 transformer stack, StM
StM (IdentityTm) a ~ComposeStIdentityTm a ~ StM m a StM (MaybeTm) a ~ComposeStMaybeTm a ~ StM m (Maybea) StM (ErrorTe m) a ~ComposeStErrorTm a ~Errore => StM m (Eithere a) StM (ExceptTe m) a ~ComposeStExceptTm a ~ StM m (Eithere a) StM (ListTm) a ~ComposeStListTm a ~ StM m [a] StM (ReaderTr m) a ~ComposeStReaderTm a ~ StM m a StM (StateTs m) a ~ComposeStStateTm a ~ StM m (a, s) StM (WriterTw m) a ~ComposeStWriterTm a ~Monoidw => StM m (a, w) StM (RWSTr w s m) a ~ComposeStRWSTm a ~Monoidw => StM m (a, s, w)
Methods
liftBaseWith :: (RunInBase m b -> b a) -> m a Source #
liftBaseWith is similar to liftIO and liftBase in that it
 lifts a base computation to the constructed monad.
Instances should satisfy similar laws as the MonadIO and MonadBase laws:
liftBaseWith (\_ -> return a) = return a
liftBaseWith (\_ -> m >>= f) = liftBaseWith (\_ -> m) >>= (\a -> liftBaseWith (\_ -> f a))
As Li-yao Xia explains, parametricity guarantees that
f $ liftBaseWith q = liftBaseWith $ runInBase -> f $ q runInBase
The difference with liftBase is that before lifting the base computation
 liftBaseWith captures the state of m. It then provides the base
 computation with a RunInBase function that allows running m
 computations in the base monad on the captured state:
withFileLifted :: MonadBaseControl IO m => FilePath -> IOMode -> (Handle -> m a) -> m a
withFileLifted file mode action = liftBaseWith (\runInBase -> withFile file mode (runInBase . action)) >>= restoreM
                             -- = control $ \runInBase -> withFile file mode (runInBase . action)
                             -- = liftBaseOp (withFile file mode) action
liftBaseWithdefaultLiftBaseWith
restoreM :: StM m a -> m a Source #
Construct a m computation from the monadic state of m that is
 returned from a RunInBase function.
Instances should satisfy:
liftBaseWith (\runInBase -> runInBase m) >>= restoreM = m
restoreMdefaultRestoreM
Instances
type RunInBase m b = forall a. m a -> b (StM m a) Source #
A function that runs a m computation on the monadic state that was
 captured by liftBaseWith
A RunInBase m function yields a computation in the base monad of m that
 returns the monadic state of m. This state can later be used to restore the
 m computation using restoreM.
Example type equalities:
RunInBase (IdentityTm) b ~ forall a.IdentityTm a -> b (StMm a) RunInBase (MaybeTm) b ~ forall a.MaybeTm a -> b (StMm (Maybea)) RunInBase (ErrorTe m) b ~ forall a.Errore =>ErrorTe m a -> b (StMm (Eithere a)) RunInBase (ExceptTe m) b ~ forall a.ExceptTe m a -> b (StMm (Eithere a)) RunInBase (ListTm) b ~ forall a.ListTm a -> b (StMm [a]) RunInBase (ReaderTr m) b ~ forall a.ReaderTm a -> b (StMm a) RunInBase (StateTs m) b ~ forall a.StateTs m a -> b (StMm (a, s)) RunInBase (WriterTw m) b ~ forall a.Monoidw =>WriterTw m a -> b (StMm (a, w)) RunInBase (RWSTr w s m) b ~ forall a.Monoidw =>RWSTr w s m a -> b (StMm (a, s, w))
For a transformed base monad m ~ t b, 'RunInBase m b' ~ .Run t
Defaults
Note that by using the following default definitions it's easy to make a
 monad transformer T an instance of MonadBaseControl:
instance MonadBaseControl b m => MonadBaseControl b (T m) where
    type StM (T m) a = ComposeSt T m a
    liftBaseWith     = defaultLiftBaseWith
    restoreM         = defaultRestoreM
Defining an instance for a base monad B is equally straightforward:
instance MonadBaseControl B B where
    type StM B a   = a
    liftBaseWith f = f id
    restoreM       = return
type ComposeSt t m a = StM m (StT t a) Source #
Handy type synonym that composes the monadic states of t and m.
It can be used to define the StM for new MonadBaseControl instances.
type RunInBaseDefault t m b = forall a. t m a -> b (ComposeSt t m a) Source #
A function like RunInBase that runs a monad transformer t in its base
 monad b. It is used in defaultLiftBaseWith.
defaultLiftBaseWith :: (MonadTransControl t, MonadBaseControl b m) => (RunInBaseDefault t m b -> b a) -> t m a Source #
Default definition for the liftBaseWith method.
Note that it composes a liftWith of t with a liftBaseWith of m to
 give a liftBaseWith of t m:
defaultLiftBaseWith = \f ->liftWith$ \run ->liftBaseWith$ \runInBase -> f $ runInBase . run
defaultRestoreM :: (MonadTransControl t, MonadBaseControl b m) => ComposeSt t m a -> t m a Source #
Utility functions
control :: MonadBaseControl b m => (RunInBase m b -> b (StM m a)) -> m a Source #
An often used composition: control f = liftBaseWith f >>= restoreM
Example:
liftedBracket :: MonadBaseControl IO m => m a -> (a -> m b) -> (a -> m c) -> m c
liftedBracket acquire release action = control $ \runInBase ->
    bracket (runInBase acquire)
            (\saved -> runInBase (restoreM saved >>= release))
            (\saved -> runInBase (restoreM saved >>= action))
embed :: MonadBaseControl b m => (a -> m c) -> m (a -> b (StM m c)) Source #
Embed a transformer function as an function in the base monad returning a mutated transformer state.
embed_ :: MonadBaseControl b m => (a -> m ()) -> m (a -> b ()) Source #
Performs the same function as embed, but discards transformer state
 from the embedded function.
captureT :: (MonadTransControl t, Monad (t m), Monad m) => t m (StT t ()) Source #
Capture the current state of a transformer
captureM :: MonadBaseControl b m => m (StM m ()) Source #
Capture the current state above the base monad
liftBaseOp :: MonadBaseControl b m => ((a -> b (StM m c)) -> b (StM m d)) -> (a -> m c) -> m d Source #
liftBaseOp is a particular application of liftBaseWith that allows
 lifting control operations of type:
((a -> b c) -> b c)
to:
(MonadBaseControl b m => (a -> m c) -> m c)For example:
liftBaseOp alloca :: (Storable a,MonadBaseControlIOm) => (Ptr a -> m c) -> m c
liftBaseOp_ :: MonadBaseControl b m => (b (StM m a) -> b (StM m c)) -> m a -> m c Source #
liftBaseOp_ is a particular application of liftBaseWith that allows
 lifting control operations of type:
(b a -> b a)
to:
(MonadBaseControl b m => m a -> m a)For example:
liftBaseOp_ mask_ ::MonadBaseControlIOm => m a -> m a
liftBaseDiscard :: MonadBaseControl b m => (b () -> b a) -> m () -> m a Source #
liftBaseDiscard is a particular application of liftBaseWith that allows
 lifting control operations of type:
(b () -> b a)
to:
(MonadBaseControl b m => m () -> m a)Note that, while the argument computation m () has access to the captured
 state, all its side-effects in m are discarded. It is run only for its
 side-effects in the base monad b.
For example:
liftBaseDiscard forkIO ::MonadBaseControlIOm => m () -> m ThreadId
liftBaseOpDiscard :: MonadBaseControl b m => ((a -> b ()) -> b c) -> (a -> m ()) -> m c Source #
liftBaseOpDiscard is a particular application of liftBaseWith that allows
 lifting control operations of type:
((a -> b ()) -> b c)
to:
(MonadBaseControl b m => (a -> m ()) -> m c)Note that, while the argument computation m () has access to the captured
 state, all its side-effects in m are discarded. It is run only for its
 side-effects in the base monad b.
For example:
liftBaseDiscard (runServer addr port) ::MonadBaseControlIOm => m () -> m ()
liftThrough :: (MonadTransControl t, Monad (t m), Monad m) => (m (StT t a) -> m (StT t b)) -> t m a -> t m b Source #
Transform an action in t m using a transformer that operates on the underlying monad m