Copyright | Bas van Dijk Anders Kaseorg |
---|---|
License | BSD3 |
Maintainer | Bas van Dijk <v.dijk.bas@gmail.com> |
Safe Haskell | Safe |
Language | Haskell2010 |
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
and SelectT
.
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
for all transformersMonadTransControl
TT
, using the
anddefaultLiftWith
functions on the constructor and deconstructor ofdefaultRestoreT
T
. Define an instance
for the base monad:MonadBaseControl
B Binstance MonadBaseControl B B where type StM B a = a liftBaseWith f = f
id
restoreM =return
Define instances
for all transformers:MonadBaseControl
B m =>MonadBaseControl
B (T m)instance MonadBaseControl b m => MonadBaseControl b (T m) where type StM (T m) a =
ComposeSt
T m a liftBaseWith f =defaultLiftBaseWith
restoreM =defaultRestoreM
Synopsis
- class MonadTrans t => MonadTransControl t stT | t -> stT where
- type Run t stT = forall n b. Monad n => t n b -> n (stT b)
- type RunDefault t stT = forall n b. Monad n => t n b -> n (stT b)
- defaultLiftWith :: (Monad m, MonadTransControl n stT) => (forall b. n m b -> t m b) -> (forall o b. t o b -> n o b) -> (RunDefault t stT -> m a) -> t m a
- defaultRestoreT :: (Monad m, MonadTransControl n stT) => (n m a -> t m a) -> m (stT a) -> t m a
- class MonadBase b m => MonadBaseControl b m stM | m -> b stM where
- liftBaseWith :: (RunInBase m b stM -> b a) -> m a
- restoreM :: stM a -> m a
- type RunInBase m b stM = forall a. m a -> b (stM a)
- type RunInBaseDefault (t :: (* -> *) -> * -> *) (m :: * -> *) (b :: * -> *) (stM :: * -> *) (stT :: * -> *) = forall a. t m a -> b (Compose stM stT a)
- defaultLiftBaseWith :: (MonadTransControl t stT, MonadBaseControl b m stM) => (RunInBaseDefault t m b stM stT -> b a) -> t m a
- defaultRestoreM :: (MonadTransControl t stT, MonadBaseControl b m stM) => Compose stM stT a -> t m a
- control :: MonadBaseControl b m stM => (RunInBase m b stM -> b (stM a)) -> m a
- controlT :: (MonadTransControl t stT, Monad (t m), Monad m) => (Run t stT -> m (stT a)) -> t m a
- embed :: MonadBaseControl b m stM => (a -> m c) -> m (a -> b (stM c))
- embed_ :: MonadBaseControl b m stM => (a -> m ()) -> m (a -> b ())
- captureT :: (MonadTransControl t stT, Monad (t m), Monad m) => t m (stT ())
- captureM :: MonadBaseControl b m stM => m (stM ())
- liftBaseOp :: MonadBaseControl b m stM => ((a -> b (stM c)) -> b (stM d)) -> (a -> m c) -> m d
- liftBaseOp_ :: MonadBaseControl b m stM => (b (stM a) -> b (stM c)) -> m a -> m c
- liftBaseDiscard :: MonadBaseControl b m stM => (b () -> b a) -> m () -> m a
- liftBaseOpDiscard :: MonadBaseControl b m stM => ((a -> b ()) -> b c) -> (a -> m ()) -> m c
- liftThrough :: (MonadTransControl t stT, Monad (t m), Monad m) => (m (stT a) -> m (stT b)) -> t m a -> t m b
MonadTransControl
class MonadTrans t => MonadTransControl t stT | t -> stT where Source #
liftWith :: Monad m => (Run t stT -> 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.
restoreT :: Monad m => m (stT 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
Instances
MonadTransControl ListT [] Source # | |
MonadTransControl MaybeT Maybe Source # | |
MonadTransControl (IdentityT :: (Type -> Type) -> Type -> Type) Identity Source # | |
MonadTransControl (ReaderT r) Identity Source # | |
Error e => MonadTransControl (ErrorT e) (Either e) Source # | |
MonadTransControl (ExceptT e) (Either e) Source # | |
MonadTransControl (StateT s) ((,) s) Source # | |
MonadTransControl (StateT s) ((,) s) Source # | |
Monoid w => MonadTransControl (WriterT w) ((,) w) Source # | |
Monoid w => MonadTransControl (WriterT w) ((,) w) Source # | |
Monoid w => MonadTransControl (RWST r w s) ((,,) w s) Source # | |
Monoid w => MonadTransControl (RWST r w s) ((,,) w s) Source # | |
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 stT = forall n b. Monad n => t n b -> n (stT b) Source #
A function like Run
that runs a monad transformer t
which wraps the
monad transformer t'
. This is used in defaultLiftWith
.
:: (Monad m, MonadTransControl n stT) | |
=> (forall b. n m b -> t m b) | Monad constructor |
-> (forall o b. t o b -> n o b) | Monad deconstructor |
-> (RunDefault t stT -> m a) | |
-> t m a |
Default definition for the liftWith
method.
:: (Monad m, MonadTransControl n stT) | |
=> (n m a -> t m a) | Monad constructor |
-> m (stT a) | |
-> t m a |
Default definition for the restoreT
method.
MonadBaseControl
class MonadBase b m => MonadBaseControl b m stM | m -> b stM where Source #
liftBaseWith :: (RunInBase m b stM -> 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.
restoreM :: stM 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
Instances
type RunInBase m b stM = forall a. m a -> b (stM 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
.
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 = fid
restoreM =return
type RunInBaseDefault (t :: (* -> *) -> * -> *) (m :: * -> *) (b :: * -> *) (stM :: * -> *) (stT :: * -> *) = forall a. t m a -> b (Compose stM stT 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 stT, MonadBaseControl b m stM) => (RunInBaseDefault t m b stM stT -> 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 stT, MonadBaseControl b m stM) => Compose stM stT a -> t m a Source #
Utility functions
control :: MonadBaseControl b m stM => (RunInBase m b stM -> b (stM a)) -> m a Source #
An often used composition: control f =
liftBaseWith
f >>= restoreM
controlT :: (MonadTransControl t stT, Monad (t m), Monad m) => (Run t stT -> m (stT a)) -> t m a Source #
embed :: MonadBaseControl b m stM => (a -> m c) -> m (a -> b (stM c)) Source #
Embed a transformer function as an function in the base monad returning a mutated transformer state.
embed_ :: MonadBaseControl b m stM => (a -> m ()) -> m (a -> b ()) Source #
Performs the same function as embed
, but discards transformer state
from the embedded function.
captureT :: (MonadTransControl t stT, Monad (t m), Monad m) => t m (stT ()) Source #
Capture the current state of a transformer
captureM :: MonadBaseControl b m stM => m (stM ()) Source #
Capture the current state above the base monad
liftBaseOp :: MonadBaseControl b m stM => ((a -> b (stM c)) -> b (stM 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 ::MonadBaseControl
IO
m => (Ptr a -> m c) -> m c
liftBaseOp_ :: MonadBaseControl b m stM => (b (stM a) -> b (stM 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_ ::MonadBaseControl
IO
m => m a -> m a
liftBaseDiscard :: MonadBaseControl b m stM => (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 ::MonadBaseControl
IO
m => m () -> m ThreadId
liftBaseOpDiscard :: MonadBaseControl b m stM => ((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) ::MonadBaseControl
IO
m => m () -> m ()
liftThrough :: (MonadTransControl t stT, Monad (t m), Monad m) => (m (stT a) -> m (stT b)) -> t m a -> t m b Source #
Transform an action in t m
using a transformer that operates on the underlying monad m