| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Control.Effect.BaseControl
Synopsis
- data BaseControl b m a
- withLowerToBase :: forall b m a. Eff (BaseControl b) m => (forall f. (forall x. m x -> b (f x)) -> b (f a)) -> m a
- gainBaseControl :: forall b m a. Eff (BaseControl b) m => (forall z. (MonadBaseControl b z, Coercible z m) => GainBaseControlC b z m a) -> m a
- runBaseControl :: Carrier m => BaseControlC m a -> m a
- baseControlToFinal :: (MonadBaseControl b m, Carrier m) => BaseControlToFinalC b m a -> m a
- class MonadBase b m => MonadBaseControl (b :: Type -> Type) (m :: Type -> Type) | m -> b where
- control :: MonadBaseControl b m => (RunInBase m b -> b (StM m a)) -> m a
- threadBaseControlViaClass :: forall b t m a. (MonadTrans t, Monad m, forall z. MonadBaseControl b z => MonadBaseControl b (t z), forall z. Coercible z m => Coercible (t z) (t m)) => (forall x. BaseControl b m x -> m x) -> BaseControl b (t m) a -> t m a
- powerAlgBaseControl :: forall m p a. Monad m => Algebra' p m a -> Algebra' (BaseControl m ': p) m a
- powerAlgBaseControlFinal :: forall b m p a. MonadBaseControl b m => Algebra' p m a -> Algebra' (BaseControl b ': p) m a
- newtype GainBaseControlC b z m a = GainBaseControlC {
- unGainBaseControlC :: m a
- data BaseControlC m a
- type BaseControlToFinalC b = InterpretPrimC BaseControlToFinalH (BaseControl b)
Effects
data BaseControl b m a Source #
A helper primitive effect that allows for lowering computations to a base monad.
Helper primitive effects are effects that allow you to avoid interpreting one
of your own effects as a primitive if the power needed from direct access to
the underlying monad can instead be provided by the relevant helper primitive
effect. The reason why you'd want to do this is that helper primitive effects
already have ThreadsEff instances defined for them; so you don't have to
define any for your own effect.
The helper primitive effects offered in this library are -- in order of
ascending power -- Regional,
Optional, BaseControl
and Unlift.
BaseControl is typically used as a primitive effect.
If you define a Carrier that relies on a novel
non-trivial monad transformer t, then you need to make a
a instance (if possible).
ThreadsEff t (BaseControl b)threadBaseControlViaClass can help you with that.
The following threading constraints accept BaseControl:
Instances
Actions
withLowerToBase :: forall b m a. Eff (BaseControl b) m => (forall f. (forall x. m x -> b (f x)) -> b (f a)) -> m a Source #
Gain access to a function that allows for lowering m to the
base monad b.
This is less versatile, but easier to use than gainBaseControl.
gainBaseControl :: forall b m a. Eff (BaseControl b) m => (forall z. (MonadBaseControl b z, Coercible z m) => GainBaseControlC b z m a) -> m a Source #
Locally gain access to a instance
within a region.MonadBaseControl b
You'll need to use lift if you want to use the MonadBaseControl instance
with computations outside of the region.
This is common with effect handlers. For example:
import System.IO (FilePath, IOMode, Handle) import qualified System.IO as SysIO data WithFile m a where WithFile :: FilePath -> IOMode -> (Handle -> m a) -> WithFile m a runWithFile ::Eff(BaseControlIO) m =>SimpleInterpreterForWithFile m runWithFile =interpretSimple$ \case WithFile fp mode c ->gainBaseControl$control$ \lower -> SysIO.withFile fp mode (\hdl -> lower (lift (c hdl)))
Interpretations
runBaseControl :: Carrier m => BaseControlC m a -> m a Source #
Run a effect, where the base BaseControl mm is the current monad.
Derivs(BaseControlCm) =BaseControlm ':Derivsm
Prims(BaseControlCm) =BaseControlm ':Primsm
baseControlToFinal :: (MonadBaseControl b m, Carrier m) => BaseControlToFinalC b m a -> m a Source #
Run a effect, where the base BaseControl bb is the final base monad.
Derivs(BaseControlToFinalCb m) =BaseControlb ':Derivsm
Prims(BaseControlToFinalCb m) =BaseControlb ':Primsm
MonadBaseControl
class MonadBase b m => MonadBaseControl (b :: Type -> Type) (m :: Type -> Type) | m -> b where #
Writing instances
The usual way to write a instance for a transformer
stack over a base monad MonadBaseControlB 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
Associated Types
type StM (m :: Type -> Type) a #
Monadic state that m adds to the base monad b.
For all base (non-transformed) monads, StM m a ~ a:
StMIOa ~ a StMMaybea ~ a StM (Eithere) a ~ a StM [] a ~ a StM ((->) r) a ~ a StMIdentitya ~ a StMSTMa ~ a StM (STs) a ~ a
If m is a transformed monad, m ~ t b, is the monadic state of
the transformer StMt (given by its StT from MonadTransControl). For a
transformer stack, is defined recursively:StM
StM (IdentityTm) a ~ComposeStIdentityTm a ~ StM m a StM (MaybeTm) a ~ComposeStMaybeTm a ~ StM m (Maybea) StM (ErrorTe m) a ~ComposeStErrorTm a ~Errore => StM m (Eithere a) StM (ExceptTe m) a ~ComposeStExceptTm a ~ StM m (Eithere a) StM (ListTm) a ~ComposeStListTm a ~ StM m [a] StM (ReaderTr m) a ~ComposeStReaderTm a ~ StM m a StM (StateTs m) a ~ComposeStStateTm a ~ StM m (a, s) StM (WriterTw m) a ~ComposeStWriterTm a ~Monoidw => StM m (a, w) StM (RWSTr w s m) a ~ComposeStRWSTm a ~Monoidw => StM m (a, s, w)
Methods
liftBaseWith :: (RunInBase m b -> b a) -> m a #
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:
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
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
control :: MonadBaseControl b m => (RunInBase m b -> b (StM m a)) -> m a #
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))
Threading utilities
threadBaseControlViaClass :: forall b t m a. (MonadTrans t, Monad m, forall z. MonadBaseControl b z => MonadBaseControl b (t z), forall z. Coercible z m => Coercible (t z) (t m)) => (forall x. BaseControl b m x -> m x) -> BaseControl b (t m) a -> t m a Source #
A valid definition of threadEff for a
instance, given that ThreadsEff t (BaseControl b)t lifts for any MonadBaseControl bb.
Combinators for Algebras
powerAlgBaseControl :: forall m p a. Monad m => Algebra' p m a -> Algebra' (BaseControl m ': p) m a Source #
Strengthen an by adding a Algebra p m handlerBaseControl m
powerAlgBaseControlFinal :: forall b m p a. MonadBaseControl b m => Algebra' p m a -> Algebra' (BaseControl b ': p) m a Source #
Strengthen an by adding a Algebra p m handler,
where BaseControl bb is the final base monad.
Carriers
newtype GainBaseControlC b z m a Source #
Constructors
| GainBaseControlC | |
Fields
| |
Instances
data BaseControlC m a Source #
Instances
type BaseControlToFinalC b = InterpretPrimC BaseControlToFinalH (BaseControl b) Source #