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`

.

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 transformers`MonadTransControl`

T`T`

, using the

and`defaultLiftWith`

functions on the constructor and deconstructor of`defaultRestoreT`

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

know how to `MonadTrans`

actions in the base monad to
the transformed monad. These lifted actions, however, are completely unaware
of the monadic state added by the transformer.`lift`

instances are aware of the monadic state of the
transformer and allow to save and restore this state.`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

instances can only lift the return type of the `MonadTrans`

`withFile`

function:

withFileLifted :: MonadTrans t => FilePath -> IOMode -> (Handle -> IO r) -> t IO r withFileLifted file mode action = lift (withFile file mode action)

However,

is not powerful enough to make `MonadTrans`

`withFileLifted`

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

.
`withFile`

allows us to do this:`MonadTransControl`

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

Monadic state of `t`

.

The monadic state of a monad transformer is the result type of its `run`

function, e.g.:

`runReaderT`

::`ReaderT`

r m a -> r -> m a`StT`

(`ReaderT`

r) a ~ a`runStateT`

::`StateT`

s m a -> s -> m (a, s)`StT`

(`StateT`

s) a ~ (a, s)`runMaybeT`

::`MaybeT`

m a -> m (`Maybe`

a)`StT`

`MaybeT`

a ~`Maybe`

a

Provided type instances:

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 (\_ -> 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

function associated with a transformer:`Run`

liftWith ::`Monad`

m => ((`Monad`

n =>`ReaderT`

r n b -> n b) -> m a) ->`ReaderT`

r m a liftWith f =`ReaderT`

(\r -> f (\action ->`runReaderT`

action r)) liftWith ::`Monad`

m => ((`Monad`

n =>`StateT`

s n b -> n (b, s)) -> m a) ->`StateT`

s m a liftWith f =`StateT`

(\s ->`liftM`

(\x -> (x, s)) (f (\action ->`runStateT`

action s))) liftWith ::`Monad`

m => ((`Monad`

n =>`MaybeT`

n b -> n (`Maybe`

b)) -> m a) ->`MaybeT`

m a liftWith f =`MaybeT`

(`liftM`

`Just`

(f`runMaybeT`

))

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) ->`ReaderT`

r m a restoreT :: m a ->`ReaderT`

r m a restoreT action =`ReaderT`

{ runReaderT =`const`

action }`StateT`

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

s m a restoreT :: m (a, s) ->`StateT`

s m a restoreT action =`StateT`

{ runStateT =`const`

action }`MaybeT`

:: m (`Maybe`

a) ->`MaybeT`

m a restoreT :: m (`Maybe`

a) ->`MaybeT`

m a restoreT action =`MaybeT`

action

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

#### Instances

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 (ReaderT r) Source # | |

MonadTransControl (IdentityT :: (Type -> Type) -> Type -> Type) Source # | |

MonadTransControl (ExceptT e) Source # | |

Error e => MonadTransControl (ErrorT e) 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)

This type is usually satisfied by the `run`

function of a transformer:

`flip`

`runReaderT`

:: r -> Run (`ReaderT`

r)`flip`

`runStateT`

:: s -> Run (`StateT`

s)`runMaybeT`

:: Run`MaybeT`

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

.

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

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

.

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

## Writing instances

The usual way to write a

instance for a transformer
stack over a base monad `MonadBaseControl`

`B`

is to write an instance `MonadBaseControl B B`

for the base monad, and `MonadTransControl T`

instances for every transformer
`T`

. Instances for

are then simply implemented using
`MonadBaseControl`

, `ComposeSt`

, `defaultLiftBaseWith`

.`defaultRestoreM`

Monadic state that `m`

adds to the base monad `b`

.

For all base (non-transformed) 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

If `m`

is a transformed monad, `m ~ t b`

,

is the monadic state of
the transformer `StM`

`t`

(given by its `StT`

from `MonadTransControl`

). For a
transformer stack,

is defined recursively:`StM`

StM (`IdentityT`

m) a ~`ComposeSt`

`IdentityT`

m a ~ StM m a StM (`MaybeT`

m) a ~`ComposeSt`

`MaybeT`

m a ~ StM m (`Maybe`

a) StM (`ErrorT`

e m) a ~`ComposeSt`

`ErrorT`

m a ~`Error`

e => StM m (`Either`

e a) StM (`ExceptT`

e m) a ~`ComposeSt`

`ExceptT`

m a ~ StM m (`Either`

e a) StM (`ListT`

m) a ~`ComposeSt`

`ListT`

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

r m) a ~`ComposeSt`

`ReaderT`

m a ~ StM m a StM (`StateT`

s m) a ~`ComposeSt`

`StateT`

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

w m) a ~`ComposeSt`

`WriterT`

m a ~`Monoid`

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

r w s m) a ~`ComposeSt`

`RWST`

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 (\_ -> 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

is usually not implemented directly, but using
`liftBaseWith`

.`defaultLiftBaseWith`

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

is usually not implemented directly, but using
`restoreM`

.`defaultRestoreM`

#### 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 (`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))

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