Portability | Requires RankNTypes |
---|---|
Stability | experimental |
Maintainer | Bas van Dijk <v.dijk.bas@gmail.com> |
This module defines the class MonadTransControl
of monad transformers
through which control operations can be lifted. Instances are
included for all the standard monad transformers from the
transformers
library except ContT
.
idLiftControl
and liftLiftControlBase
are provided to assist creation of
MonadControlIO
-like classes (see Control.Monad.IO.Control) based on core
monads other than IO
.
- class MonadTrans t => MonadTransControl t where
- liftControl :: Monad m => (Run t -> m α) -> t m α
- type Run t = forall n o β. (Monad n, Monad o, Monad (t o)) => t n β -> n (t o β)
- control :: (Monad m, Monad (t m), MonadTransControl t) => (Run t -> m (t m α)) -> t m α
- idLiftControl :: Monad m => (RunInBase m m -> m α) -> m α
- type RunInBase m base = forall β. m β -> base (m β)
- liftLiftControlBase :: (MonadTransControl t, Monad (t m), Monad m, Monad base) => ((RunInBase m base -> base α) -> m α) -> (RunInBase (t m) base -> base α) -> t m α
MonadTransControl
class MonadTrans t => MonadTransControl t whereSource
MonadTransControl
is the class of monad transformers supporting an
extra operation liftControl
, enabling control operations (functions that
use monadic actions as input instead of just output) to be lifted
through the transformer.
liftControl :: Monad m => (Run t -> m α) -> t m αSource
liftControl
is used to peel off the outer layer of a transformed
monadic action, allowing an transformed action t m a
to be
treated as a base action m a
.
More precisely, liftControl
captures the monadic state of t
at the
point where it is bound (in t m
), yielding a function of type:
Run
t = forall n o b. (Monad n, Monad o) => t n b -> n (t o b)
This function runs a transformed monadic action t n b
in the inner monad n
using the captured state, and leaves the
result t o b
in the monad n
after all side effects in n
have occurred.
This can be used to lift control operations with types such as
M a -> M a
into the transformed monad t M
:
instance Monad M foo :: M a -> M a foo' :: (MonadTransControl
t,Monad
(t M)) => t M a -> t M a foo' a =control
$ run -> -- run :: t M a -> M (t M a) foo $ run a -- uses foo :: M (t M a) -> M (t M a)
Instances should satisfy similar laws as the MonadTrans
laws:
liftControl . const . return = return
liftControl (const (m >>= f)) = liftControl (const m) >>= liftControl . const . f
Additionally instances should satisfy:
control
$ \run -> run t = t
MonadTransControl MaybeT | |
MonadTransControl ListT | |
MonadTransControl IdentityT | |
Monoid w => MonadTransControl (WriterT w) | |
Monoid w => MonadTransControl (WriterT w) | |
MonadTransControl (StateT s) | |
MonadTransControl (StateT s) | |
MonadTransControl (ReaderT r) | |
Error e => MonadTransControl (ErrorT e) | |
Monoid w => MonadTransControl (RWST r w s) | |
Monoid w => MonadTransControl (RWST r w s) |
control :: (Monad m, Monad (t m), MonadTransControl t) => (Run t -> m (t m α)) -> t m αSource
An often used composition: control =
join
. liftControl
Lifting
idLiftControl :: Monad m => (RunInBase m m -> m α) -> m αSource
idLiftControl
acts as the "identity" liftControl
operation from a monad
m
to itself.
idLiftControl f = f $ liftM return
It serves as the base case for a class like MonadControlIO
, which
allows control operations in some base monad (here IO
) to be
lifted through arbitrary stacks of zero or more monad transformers
in one call. For example, Control.Monad.IO.Control defines:
class MonadIO m => MonadControlIO m where liftControlIO :: (RunInBase m IO -> IO b) -> m b
instance MonadControlIO IO where liftControlIO = idLiftControl
:: (MonadTransControl t, Monad (t m), Monad m, Monad base) | |
=> ((RunInBase m base -> base α) -> m α) |
|
-> (RunInBase (t m) base -> base α) -> t m α |
liftLiftControlBase
is used to compose two liftControl
operations:
the outer provided by a MonadTransControl
instance,
and the inner provided as the argument.
It satisfies
.
liftLiftControlBase
idLiftControl
= liftControl
It serves as the induction step of a MonadControlIO
-like class. For
example, Control.Monad.IO.Control defines:
instance MonadControlIO m => MonadControlIO (StateT s m) where liftControlIO = liftLiftControlBase liftControlIO
using the MonadTransControl
instance of
.
StateT
s
The following shows the recursive structure of liftControlIO
applied to a
stack of three monad transformers with IO as the base monad: t1 (t2 (t3 IO)) a
:
liftControlIO =liftLiftControlBase
$liftLiftControlBase
$liftLiftControlBase
$idLiftControl
= \f ->liftControl
$ \run1 -> -- Capture state of t1, run1 ::Run
t1liftControl
$ \run2 -> -- Capture state of t2, run2 ::Run
t2liftControl
$ \run3 -> -- Capture state of t3, run3 ::Run
t3 let run ::RunInBase
(t1 (t2 (t3 IO))) IO run = -- Restore stateliftM
(join
.lift
) -- :: IO ( t2 (t3 IO) (t1 (t2 (t3 IO)) a)) -> IO ( t1 (t2 (t3 IO)) a) .liftM
(join
.lift
) -- :: IO ( t3 IO (t2 (t3 IO) (t1 (t2 (t3 IO)) a))) -> IO ( t2 (t3 IO) (t1 (t2 (t3 IO)) a)) -- Identity conversion .liftM
(join
.lift
) -- :: IO (IO (t3 IO (t2 (t3 IO) (t1 (t2 (t3 IO)) a)))) -> IO ( t3 IO (t2 (t3 IO) (t1 (t2 (t3 IO)) a))) .liftM
return
-- :: IO ( t3 IO (t2 (t3 IO) (t1 (t2 (t3 IO)) a))) -> IO (IO (t3 IO (t2 (t3 IO) (t1 (t2 (t3 IO)) a)))) -- Run (computation to run:) (inner monad:) (restore computation:) . run3 -- :: t3 IO (t2 (t3 IO) (t1 (t2 (t3 IO)) a)) -> IO (t3 IO (t2 (t3 IO) (t1 (t2 (t3 IO)) a))) . run2 -- :: t2 (t3 IO) (t1 (t2 (t3 IO)) a) -> t3 IO (t2 (t3 IO) (t1 (t2 (t3 IO)) a)) . run1 -- :: t1 (t2 (t3 IO)) a -> t2 (t3 IO) (t1 (t2 (t3 IO)) a) in f run