Copyright | Bas van Dijk Anders Kaseorg |
---|---|

License | BSD3 |

Maintainer | Bas van Dijk <v.dijk.bas@gmail.com> |

Safe Haskell | Safe |

Language | Haskell98 |

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:

- 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 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
- 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 #

Monadic state of `t`

.

For clarity, because haddock does not display associated types, below are
the elaborated `StT`

definitions provided by this library:

StT`IdentityT`

a ~ a StT`MaybeT`

a ~`Maybe`

a StT (`ErrorT`

e) a ~`Error`

e =>`Either`

e a StT (`ExceptT`

e) a ~`Either`

e a StT`ListT`

a ~ [a] StT (`ReaderT`

r) a ~ a StT (`StateT`

s) a ~ (a, s) StT (`WriterT`

w) a ~`Monoid`

w => (a, w) StT (`RWST`

r w s) a ~`Monoid`

w => (a, s, w)

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 . const . return = return

liftWith (const (m >>= f)) = liftWith (const m) >>= liftWith . const . f

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

Example type signatures:

restoreT ::`Monad`

m => m a ->`IdentityT`

m a restoreT ::`Monad`

m => m (`Maybe`

a) ->`MaybeT`

m a restoreT :: (`Monad`

m,`Error`

e) => m (`Either`

e a) ->`ErrorT`

e m a restoreT ::`Monad`

m => m (`Either`

e a) ->`ExceptT`

e m a restoreT ::`Monad`

m => m [a] ->`ListT`

m a restoreT ::`Monad`

m => m a ->`ReaderT`

r m a restoreT ::`Monad`

m => m (a, s) ->`StateT`

s m a restoreT :: (`Monad`

m,`Monoid`

w) => m (a, w) ->`WriterT`

w m a restoreT :: (`Monad`

m,`Monoid`

w) => m (a, s, w) ->`RWST`

r w s m a

MonadTransControl MaybeT Source # | |

MonadTransControl ListT Source # | |

Monoid w => MonadTransControl (WriterT w) Source # | |

Monoid w => MonadTransControl (WriterT w) Source # | |

MonadTransControl (StateT s) Source # | |

MonadTransControl (StateT s) Source # | |

MonadTransControl (IdentityT *) Source # | |

MonadTransControl (ExceptT e) Source # | |

Error e => MonadTransControl (ErrorT e) Source # | |

MonadTransControl (ReaderT * r) 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:

Run`IdentityT`

~ forall n b.`Monad`

n =>`IdentityT`

n b -> n b Run`MaybeT`

~ forall n b.`Monad`

n =>`MaybeT`

n b -> n (`Maybe`

b) Run (`ErrorT`

e) ~ forall n b. (`Monad`

n,`Error`

e) =>`ErrorT`

e n b -> n (`Either`

e b) Run (`ExceptT`

e) ~ forall n b.`Monad`

n =>`ExceptT`

e n b -> n (`Either`

e b) Run`ListT`

~ forall n b.`Monad`

n =>`ListT`

n b -> n [b] Run (`ReaderT`

r) ~ forall n b.`Monad`

n =>`ReaderT`

r n b -> n b Run (`StateT`

s) ~ forall n b.`Monad`

n =>`StateT`

s n b -> n (a, s) Run (`WriterT`

w) ~ forall n b. (`Monad`

n,`Monoid`

w) =>`WriterT`

w n b -> n (a, w) Run (`RWST`

r w s) ~ forall n b. (`Monad`

n,`Monoid`

w) =>`RWST`

r w s n b -> n (a, s, w)

## Defaults

The following functions can be used to define a `MonadTransControl`

instance
for a monad transformer which simply wraps 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`

.

:: (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.

:: (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.

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`

.

:: (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.

:: (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 #

Monadic state of `m`

.

For all non-transformer monads, `StM m a ~ a`

:

StM`IO`

a ~ a StM`Maybe`

a ~ a StM (`Either`

e) a ~ a StM [] a ~ a StM ((->) r) a ~ a StM`Identity`

a ~ a StM`STM`

a ~ a StM (`ST`

s) a ~ a

All transformer monads' `StM`

depends on both the monadic state of the
transformer (given by its `StT`

from `MonadTransControl`

), as well as its
inner monad's monadic state, given by its `StM`

from `MonadBaseControl`

:

StM (`IdentityT`

m) a ~ StM m a StM (`MaybeT`

m) a ~ StM m (`Maybe`

a) StM (`ErrorT`

e m) a ~`Error`

e => StM m (`Either`

e a) StM (`ExceptT`

e m) a ~ StM m (`Either`

e a) StM (`ListT`

m) a ~ StM m [a] StM (`ReaderT`

r m) a ~ StM m a StM (`StateT`

s m) a ~ StM m (a, s) StM (`WriterT`

w m) a ~`Monoid`

w => StM m (a, w) StM (`RWST`

r w s m) a ~`Monoid`

w => StM m (a, s, w)

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 . const . return = return

liftBaseWith (const (m >>= f)) = liftBaseWith (const m) >>= liftBaseWith . const . f

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

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 (`IdentityT`

m) b ~ forall a.`IdentityT`

m a -> b (`StM`

m a) RunInBase (`MaybeT`

m) b ~ forall a.`MaybeT`

m a -> b (`StM`

m (`Maybe`

a)) RunInBase (`ErrorT`

e m) b ~ forall a.`Error`

e =>`ErrorT`

e m a -> b (`StM`

m (`Either`

e a)) RunInBase (`ExceptT`

e m) b ~ forall a.`ExceptT`

e m a -> b (`StM`

m (`Either`

e a)) RunInBase (`ListT`

m) b ~ forall a.`ListT`

m a -> b (`StM`

m [a]) RunInBase (`ReaderT`

r m) b ~ forall a.`ReaderT`

m a -> b (`StM`

m a) RunInBase (`StateT`

s m) b ~ forall a.`StateT`

s m a -> b (`StM`

m (a, s)) RunInBase (`WriterT`

w m) b ~ forall a.`Monoid`

w =>`WriterT`

w m a -> b (`StM`

m (a, w)) RunInBase (`RWST`

r w s m) b ~ forall a.`Monoid`

w =>`RWST`

r w s m a -> b (`StM`

m (a, s, w))

## 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 defintion 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`

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 ::`MonadBaseControl`

`IO`

m => (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_ ::`MonadBaseControl`

`IO`

m => 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 ::`MonadBaseControl`

`IO`

m => 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) ::`MonadBaseControl`

`IO`

m => m () -> m ()

:: (MonadTransControl t, Monad (t m), Monad m) | |

=> (m (StT t a) -> m (StT t b)) | |

-> t m a | |

-> t m b |

Transform an action in `t m`

using a transformer that operates on the underlying monad `m`