cleff-0.3.4.0: Fast and concise extensible effects
Copyright(c) 2021 Xy Ren
LicenseBSD3
Maintainerxy.r@outlook.com
Stabilityunstable
Portabilitynon-portable (GHC only)
Safe HaskellNone
LanguageHaskell2010

Cleff.Internal.Base

Description

This module contains the IOE effect together with a few primitives for using it, as well as interpretation combinators for IO-related effects. It is not usually needed because safe functionalities are re-exported in the Cleff module.

This is an internal module and its API may change even between minor versions. Therefore you should be extra careful if you're to depend on this module.

Synopsis

The IOE Effect

data IOE :: Effect Source #

The effect capable of lifting and unlifting the IO monad, allowing you to use MonadIO, MonadUnliftIO, PrimMonad, MonadCatch, MonadThrow and MonadMask functionalities. This is the "final" effect that most effects eventually are interpreted into. For example, you can do:

log :: IOE :> es => Eff es ()
log = liftIO (putStrLn "Test logging")

It is not recommended to use this effect directly in application code, as it is too liberal and allows arbitrary IO, therefore making it harder to do proper effect management. Ideally, this is only used in interpreting more fine-grained effects.

Technical details

Note that this is not a real effect and cannot be interpreted in any way besides thisIsPureTrustMe and runIOE. This is mainly for performance concern, but also that there doesn't really exist reasonable interpretations other than the current one, given the underlying implementation of the Eff monad.

IOE can be a real effect though, and you can enable the dynamic-ioe build flag to have that. However it is only for reference purposes and should not be used in production code.

Primitive IO functions

primLiftIO :: IO a -> Eff es a Source #

Lift an IO computation into Eff. This function is highly unsafe and should not be used directly; use liftIO instead, or if you're interpreting higher-order effects, use fromIO.

primUnliftIO :: ((Eff es ~> IO) -> IO a) -> Eff es a Source #

Give a runner function a way to run Eff actions as an IO computation. This function is highly unsafe and should not be used directly; use withRunInIO instead, or if you're interpreting higher-order effects, use withToIO.

Related classes

class Monad m => MonadIO (m :: Type -> Type) where #

Monads in which IO computations may be embedded. Any monad built by applying a sequence of monad transformers to the IO monad will be an instance of this class.

Instances should satisfy the following laws, which state that liftIO is a transformer of monads:

Methods

liftIO :: IO a -> m a #

Lift a computation from the IO monad.

Instances

Instances details
MonadIO IO

Since: base-4.9.0.0

Instance details

Defined in Control.Monad.IO.Class

Methods

liftIO :: IO a -> IO a #

MonadIO Q 
Instance details

Defined in Language.Haskell.TH.Syntax

Methods

liftIO :: IO a -> Q a #

MonadIO m => MonadIO (MaybeT m) 
Instance details

Defined in Control.Monad.Trans.Maybe

Methods

liftIO :: IO a -> MaybeT m a #

MonadIO m => MonadIO (ListT m) 
Instance details

Defined in Control.Monad.Trans.List

Methods

liftIO :: IO a -> ListT m a #

IOE :> es => MonadIO (Eff es) Source # 
Instance details

Defined in Cleff.Internal.Base

Methods

liftIO :: IO a -> Eff es a #

MonadIO m => MonadIO (ExceptT e m) 
Instance details

Defined in Control.Monad.Trans.Except

Methods

liftIO :: IO a -> ExceptT e m a #

(Monoid w, MonadIO m) => MonadIO (WriterT w m) 
Instance details

Defined in Control.Monad.Trans.Writer.Lazy

Methods

liftIO :: IO a -> WriterT w m a #

MonadIO m => MonadIO (StateT s m) 
Instance details

Defined in Control.Monad.Trans.State.Lazy

Methods

liftIO :: IO a -> StateT s m a #

MonadIO m => MonadIO (ReaderT r m) 
Instance details

Defined in Control.Monad.Trans.Reader

Methods

liftIO :: IO a -> ReaderT r m a #

(Error e, MonadIO m) => MonadIO (ErrorT e m) 
Instance details

Defined in Control.Monad.Trans.Error

Methods

liftIO :: IO a -> ErrorT e m a #

MonadIO m => MonadIO (IdentityT m) 
Instance details

Defined in Control.Monad.Trans.Identity

Methods

liftIO :: IO a -> IdentityT m a #

MonadIO m => MonadIO (StateT s m) 
Instance details

Defined in Control.Monad.Trans.State.Strict

Methods

liftIO :: IO a -> StateT s m a #

(Monoid w, MonadIO m) => MonadIO (WriterT w m) 
Instance details

Defined in Control.Monad.Trans.Writer.Strict

Methods

liftIO :: IO a -> WriterT w m a #

(Monoid w, Functor m, MonadIO m) => MonadIO (AccumT w m) 
Instance details

Defined in Control.Monad.Trans.Accum

Methods

liftIO :: IO a -> AccumT w m a #

MonadIO m => MonadIO (WriterT w m) 
Instance details

Defined in Control.Monad.Trans.Writer.CPS

Methods

liftIO :: IO a -> WriterT w m a #

MonadIO m => MonadIO (SelectT r m) 
Instance details

Defined in Control.Monad.Trans.Select

Methods

liftIO :: IO a -> SelectT r m a #

MonadIO m => MonadIO (ContT r m) 
Instance details

Defined in Control.Monad.Trans.Cont

Methods

liftIO :: IO a -> ContT r m a #

(Monoid w, MonadIO m) => MonadIO (RWST r w s m) 
Instance details

Defined in Control.Monad.Trans.RWS.Lazy

Methods

liftIO :: IO a -> RWST r w s m a #

(Monoid w, MonadIO m) => MonadIO (RWST r w s m) 
Instance details

Defined in Control.Monad.Trans.RWS.Strict

Methods

liftIO :: IO a -> RWST r w s m a #

MonadIO m => MonadIO (RWST r w s m) 
Instance details

Defined in Control.Monad.Trans.RWS.CPS

Methods

liftIO :: IO a -> RWST r w s m a #

class MonadIO m => MonadUnliftIO (m :: Type -> Type) where #

Monads which allow their actions to be run in IO.

While MonadIO allows an IO action to be lifted into another monad, this class captures the opposite concept: allowing you to capture the monadic context. Note that, in order to meet the laws given below, the intuition is that a monad must have no monadic state, but may have monadic context. This essentially limits MonadUnliftIO to ReaderT and IdentityT transformers on top of IO.

Laws. For any value u returned by askUnliftIO, it must meet the monad transformer laws as reformulated for MonadUnliftIO:

  • unliftIO u . return = return
  • unliftIO u (m >>= f) = unliftIO u m >>= unliftIO u . f

Instances of MonadUnliftIO must also satisfy the idempotency law:

  • askUnliftIO >>= \u -> (liftIO . unliftIO u) m = m

This law showcases two properties. First, askUnliftIO doesn't change the monadic context, and second, liftIO . unliftIO u is equivalent to id IF called in the same monadic context as askUnliftIO.

Since: unliftio-core-0.1.0.0

Methods

withRunInIO :: ((forall a. m a -> IO a) -> IO b) -> m b #

Convenience function for capturing the monadic context and running an IO action with a runner function. The runner function is used to run a monadic action m in IO.

Since: unliftio-core-0.1.0.0

Instances

Instances details
MonadUnliftIO IO 
Instance details

Defined in Control.Monad.IO.Unlift

Methods

withRunInIO :: ((forall a. IO a -> IO a) -> IO b) -> IO b #

IOE :> es => MonadUnliftIO (Eff es) Source # 
Instance details

Defined in Cleff.Internal.Base

Methods

withRunInIO :: ((forall a. Eff es a -> IO a) -> IO b) -> Eff es b #

MonadUnliftIO m => MonadUnliftIO (ReaderT r m) 
Instance details

Defined in Control.Monad.IO.Unlift

Methods

withRunInIO :: ((forall a. ReaderT r m a -> IO a) -> IO b) -> ReaderT r m b #

MonadUnliftIO m => MonadUnliftIO (IdentityT m) 
Instance details

Defined in Control.Monad.IO.Unlift

Methods

withRunInIO :: ((forall a. IdentityT m a -> IO a) -> IO b) -> IdentityT m b #

Unwrapping Eff

thisIsPureTrustMe :: Eff (IOE ': es) ~> Eff es Source #

Unsafely eliminate an IOE effect from the top of the effect stack. This is mainly for implementing effects that uses IO but does not do anything really impure (i.e. can be safely used unsafeDupablePerformIO on), such as a State effect.

runIOE :: Eff '[IOE] ~> IO Source #

Unwrap an Eff computation with side effects into an IO computation, given that all effects other than IOE are interpreted.

runPure :: Eff '[] a -> a Source #

Unwrap a pure Eff computation into a pure value, given that all effects are interpreted.

runPureIO :: Eff '[] ~> IO Source #

Unwrap a pure Eff computation into an IO computation. You may occasionally need this.

Effect interpretation

type HandlerIO e es = forall esSend. Handling esSend e es => e (Eff esSend) ~> IO Source #

The type of an IO effect handler, which is a function that transforms an effect e into IO computations. This is used for interpretIO.

interpretIO :: IOE :> es => HandlerIO e es -> Eff (e ': es) ~> Eff es Source #

Interpret an effect in terms of IO, by transforming an effect into IO computations.

interpretIO f = interpret (liftIO . f)

Combinators for interpreting higher-order effects

withToIO :: (Handling esSend e es, IOE :> es) => ((Eff esSend ~> IO) -> IO a) -> Eff es a Source #

Temporarily gain the ability to unlift an Eff esSend computation into IO. This is analogous to withRunInIO, and is useful in dealing with higher-order effects that involves IO. For example, the Resource effect that supports bracketing:

data Resource m a where
  Bracket :: m a -> (a -> m ()) -> (a -> m b) -> Resource m b

can be interpreted into bracket actions in IO, by converting all effect computations into IO computations via withToIO:

runResource :: IOE :> es => Eff (Resource : es) a -> Eff es a
runResource = interpret \case
  Bracket alloc dealloc use -> withToIO $ \toIO ->
    bracket (toIO alloc) (toIO . dealloc) (toIO . use)

fromIO :: (Handling esSend e es, IOE :> es) => IO ~> Eff esSend Source #

Lift an IO computation into Eff esSend. This is analogous to liftIO, and is only useful in dealing with effect operations with the monad type in the negative position, for example masking:

data Mask :: Effect where
  Mask :: ((m ~> m) -> m a) -> Mask m a
                 ^ this "m" is in negative position

See how the restore :: IO a -> IO a from mask is "wrapped" into Eff esSend a -> Eff esSend a:

runMask :: IOE :> es => Eff (Mask : es) a -> Eff es a
runMask = interpret \case
  Mask f -> withToIO $ \toIO -> mask $
    \restore -> f (fromIO . restore . toIO)

Here, toIO from withToIO takes an Eff esSend to IO, where it can be passed into the restore function, and the returned IO computation is recovered into Eff with fromIO.

Orphan instances

IOE :> es => MonadBase IO (Eff es) Source #

Compatibility instance; use MonadIO if possible.

Instance details

Methods

liftBase :: IO α -> Eff es α #

IOE :> es => MonadBaseControl IO (Eff es) Source #

Compatibility instance; use MonadUnliftIO if possible.

Instance details

Associated Types

type StM (Eff es) a #

Methods

liftBaseWith :: (RunInBase (Eff es) IO -> IO a) -> Eff es a #

restoreM :: StM (Eff es) a -> Eff es a #

IOE :> es => MonadIO (Eff es) Source # 
Instance details

Methods

liftIO :: IO a -> Eff es a #

IOE :> es => MonadThrow (Eff es) Source # 
Instance details

Methods

throwM :: Exception e => e -> Eff es a #

IOE :> es => MonadCatch (Eff es) Source # 
Instance details

Methods

catch :: Exception e => Eff es a -> (e -> Eff es a) -> Eff es a #

IOE :> es => MonadMask (Eff es) Source # 
Instance details

Methods

mask :: ((forall a. Eff es a -> Eff es a) -> Eff es b) -> Eff es b #

uninterruptibleMask :: ((forall a. Eff es a -> Eff es a) -> Eff es b) -> Eff es b #

generalBracket :: Eff es a -> (a -> ExitCase b -> Eff es c) -> (a -> Eff es b) -> Eff es (b, c) #

IOE :> es => PrimMonad (Eff es) Source # 
Instance details

Associated Types

type PrimState (Eff es) #

Methods

primitive :: (State# (PrimState (Eff es)) -> (# State# (PrimState (Eff es)), a #)) -> Eff es a #

IOE :> es => MonadUnliftIO (Eff es) Source # 
Instance details

Methods

withRunInIO :: ((forall a. Eff es a -> IO a) -> IO b) -> Eff es b #