monad-control-0.1: Lift control operations, like exception catching, through monad transformers

PortabilityRequires RankNTypes
MaintainerBas van Dijk <>




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 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, Monad n, Monad o) => (Run t n o -> m a) -> t m aSource

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 b.

More precisely, liftControl captures the monadic state of t at the point where it is bound (in t n), yielding a function of type Run t n o = t n a -> n (t o a) this function runs a transformed monadic action t n a in the base monad n using the captured state, and leaves the result t o a 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)

liftControl is typically used with m == n == o, but is required to be polymorphic for greater type safety: for example, this type ensures that the result of running the action in m has no remaining side effects in m.

type Run t n o = forall b. t n b -> n (t o b)Source

control :: (Monad n, Monad m, Monad o, Monad (t m), MonadTransControl t) => (Run t n o -> m (t m a)) -> t m aSource

An often used composition: control = join . liftControl


idLiftControl :: Monad m => ((forall b. m b -> m (m b)) -> m a) -> m aSource

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

type RunInBase m base = forall b. m b -> base (m b)Source



:: (MonadTransControl t, Monad base, Monad m, Monad (t m)) 
=> ((RunInBase m base -> base a) -> m a)

liftControlBase operation

-> (RunInBase (t m) base -> base a) -> t m a 

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.