Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Effectful
Synopsis
- data Eff (es :: [Effect]) a
- type Effect = (Type -> Type) -> Type -> Type
- data Dispatch
- type family DispatchOf (e :: Effect) :: Dispatch
- class (e :: Effect) :> (es :: [Effect])
- type family xs :>> es :: Constraint where ...
- runPureEff :: Eff '[] a -> a
- runEff :: Eff '[IOE] a -> IO a
- data IOE :: Effect
- raise :: Eff es a -> Eff (e ': es) a
- subsume :: e :> es => Eff (e ': es) a -> Eff es a
- inject :: Subset xs es => Eff xs a -> Eff es a
- class Subset (xs :: [Effect]) (es :: [Effect])
- data UnliftStrategy
- data Persistence
- data Limit
- unliftStrategy :: IOE :> es => Eff es UnliftStrategy
- withUnliftStrategy :: IOE :> es => UnliftStrategy -> Eff es a -> Eff es a
- withEffToIO :: (HasCallStack, IOE :> es) => ((forall r. Eff es r -> IO r) -> IO a) -> Eff es a
- class Monad m => MonadIO (m :: Type -> Type) where
- class MonadIO m => MonadUnliftIO (m :: Type -> Type) where
- withRunInIO :: ((forall a. m a -> IO a) -> IO b) -> m b
Introduction
Haskell is one of the few programming languages that distinguishes between pure functions and functions that might perform side effects. For example, a function
f ::Int
->String
can't perform side effects at all, but a function
f ::Int
->IO
String
can perform any side effect. This "all or nothing" approach isn't very satisfactory though, because the vast majority of time we would like to signify that a function can perform some side effects, e.g. only be able to log messages.
This library provides support for expressing exactly that with its Eff
monad:
f :: Log:>
es =>Int
->Eff
esString
It implements support for extensible effects with both dynamic and static dispatch (for more information about each type consult the documentation in Effectful.Dispatch.Dynamic and Effectful.Dispatch.Static).
It provides:
The Eff
monad
data Eff (es :: [Effect]) a Source #
The Eff
monad provides the implementation of a computation that performs
an arbitrary set of effects. In
, Eff
es aes
is a type-level list that
contains all the effects that the computation may perform. For example, a
computation that produces an Integer
by consuming a String
from the
global environment and acting upon a single mutable value of type Bool
would have the following type:
(Reader
String
:>
es,State
Bool
:>
es) =>Eff
esInteger
Abstracting over the list of effects with (:>)
:
- Allows the computation to be used in functions that may perform other effects.
- Allows the effects to be handled in any order.
Instances
IOE :> es => MonadBaseControl IO (Eff es) Source # | Instance included for compatibility with existing code, usage of
|
Defined in Effectful.Internal.Monad Associated Types type StM (Eff es) a | |
IOE :> es => MonadBase IO (Eff es) Source # | Instance included for compatibility with existing code, usage of |
Defined in Effectful.Internal.Monad | |
Fail :> es => MonadFail (Eff es) Source # | |
Defined in Effectful.Internal.Monad | |
MonadFix (Eff es) Source # | |
Defined in Effectful.Internal.Monad | |
IOE :> es => MonadIO (Eff es) Source # | |
Defined in Effectful.Internal.Monad | |
Applicative (Eff es) Source # | |
Functor (Eff es) Source # | |
Monad (Eff es) Source # | |
MonadCatch (Eff es) Source # | |
MonadMask (Eff es) Source # | |
MonadThrow (Eff es) Source # | |
Defined in Effectful.Internal.Monad | |
Prim :> es => PrimMonad (Eff es) Source # | |
IOE :> es => MonadUnliftIO (Eff es) Source # | Use |
Defined in Effectful.Internal.Monad | |
Monoid a => Monoid (Eff es a) Source # | |
Semigroup a => Semigroup (Eff es a) Source # | |
type PrimState (Eff es) Source # | |
Defined in Effectful.Internal.Monad | |
type StM (Eff es) a Source # | |
Defined in Effectful.Internal.Monad type StM (Eff es) a = a |
Effect constraints
A type of dispatch. For more information consult the documentation in Effectful.Dispatch.Dynamic and Effectful.Dispatch.Static.
Constructors
Dynamic | |
Static SideEffects |
type family DispatchOf (e :: Effect) :: Dispatch Source #
Dispatch types of effects.
Instances
type DispatchOf Fail Source # | |
Defined in Effectful.Internal.Monad | |
type DispatchOf IOE Source # | |
Defined in Effectful.Internal.Monad | |
type DispatchOf Prim Source # | |
Defined in Effectful.Internal.Monad | |
type DispatchOf (Error e) Source # | |
Defined in Effectful.Error.Dynamic | |
type DispatchOf (Error e) Source # | |
Defined in Effectful.Error.Static | |
type DispatchOf (Reader r) Source # | |
Defined in Effectful.Reader.Dynamic | |
type DispatchOf (Reader r) Source # | |
Defined in Effectful.Reader.Static | |
type DispatchOf (State s) Source # | |
Defined in Effectful.State.Dynamic | |
type DispatchOf (State s) Source # | |
Defined in Effectful.State.Static.Local | |
type DispatchOf (State s) Source # | |
Defined in Effectful.State.Static.Shared | |
type DispatchOf (Writer w) Source # | |
Defined in Effectful.Writer.Dynamic | |
type DispatchOf (Writer w) Source # | |
Defined in Effectful.Writer.Static.Local | |
type DispatchOf (Writer w) Source # | |
Defined in Effectful.Writer.Static.Shared |
class (e :: Effect) :> (es :: [Effect]) Source #
A constraint that requires that a particular effect e
is a member of the
type-level list es
. This is used to parameterize an Eff
computation over an arbitrary list of effects, so long as e
is somewhere
in the list.
For example, a computation that only needs access to a mutable value of type
Integer
would have the following type:
State
Integer
:>
es =>Eff
es ()
Instances
(TypeError (('Text "There is no handler for '" :<>: 'ShowType e) :<>: 'Text "' in the context") :: Constraint) => e :> ('[] :: [Effect]) Source # | |
Defined in Effectful.Internal.Effect Methods reifyIndex :: Int Source # | |
e :> (e ': es) Source # | |
Defined in Effectful.Internal.Effect Methods reifyIndex :: Int Source # | |
e :> es => e :> (x ': es) Source # | |
Defined in Effectful.Internal.Effect Methods reifyIndex :: Int Source # |
type family xs :>> es :: Constraint where ... Source #
Running the Eff
monad
Pure computations
runPureEff :: Eff '[] a -> a Source #
Computations with side effects
runEff :: Eff '[IOE] a -> IO a Source #
Run an Eff
computation with side effects.
For running pure computations see runPureEff
.
Run arbitrary IO
computations via MonadIO
or MonadUnliftIO
.
Note: it is not recommended to use this effect in application code as it is too liberal. Ideally, this is only used in handlers of more fine-grained effects.
Instances
type DispatchOf IOE Source # | |
Defined in Effectful.Internal.Monad | |
newtype StaticRep IOE Source # | |
Defined in Effectful.Internal.Monad |
Lifting
raise :: Eff es a -> Eff (e ': es) a Source #
Lift an Eff
computation into an effect stack with one more effect.
subsume :: e :> es => Eff (e ': es) a -> Eff es a Source #
Eliminate a duplicate effect from the top of the effect stack.
inject :: Subset xs es => Eff xs a -> Eff es a Source #
Allow for running an effect stack xs
within es
as long as xs
is a
permutation (with possible duplicates) of a subset of es
.
Generalizes raise
and subsume
.
Note: this function should be needed rarely, usually when you have to cross
API boundaries and monomorphic effect stacks are involved. Using monomorphic
stacks is discouraged (see Eff
), but sometimes might be necessary due to
external constraints.
class Subset (xs :: [Effect]) (es :: [Effect]) Source #
Provide evidence that xs
is a subset of es
.
Instances
Subset ('[] :: [Effect]) es Source # | |
Defined in Effectful.Internal.Effect Methods reifyIndices :: [Int] Source # | |
(e :> es, Subset xs es) => Subset (e ': xs) es Source # | |
Defined in Effectful.Internal.Effect Methods reifyIndices :: [Int] Source # |
Unlifting
data UnliftStrategy Source #
The strategy to use when unlifting Eff
computations via
withEffToIO
, withRunInIO
or the
localUnlift
family.
Warning: unlifting functions should not be used outside of continuations that brought them into scope. The behavior when doing so is undefined.
Constructors
SeqUnlift | The fastest strategy and a default setting for |
ConcUnlift !Persistence !Limit | A strategy that makes it possible for the unlifting function to be called
in threads distinct from its creator. See |
Instances
data Persistence Source #
Persistence setting for the ConcUnlift
strategy.
Different functions require different persistence strategies. Examples:
- Lifting
pooledMapConcurrentlyN
from theunliftio
library requires theEphemeral
strategy as we don't want jobs to share environment changes made by previous jobs run in the same worker thread. - Lifting
forkIOWithUnmask
requires thePersistent
strategy, otherwise the unmasking function would start with a fresh environment each time it's called.
Constructors
Ephemeral | Don't persist the environment between calls to the unlifting function in threads distinct from its creator. |
Persistent | Persist the environment between calls to the unlifting function within a particular thread. |
Instances
Generic Persistence Source # | |
Defined in Effectful.Internal.Unlift Associated Types type Rep Persistence :: Type -> Type # | |
Show Persistence Source # | |
Defined in Effectful.Internal.Unlift Methods showsPrec :: Int -> Persistence -> ShowS # show :: Persistence -> String # showList :: [Persistence] -> ShowS # | |
Eq Persistence Source # | |
Defined in Effectful.Internal.Unlift | |
Ord Persistence Source # | |
Defined in Effectful.Internal.Unlift Methods compare :: Persistence -> Persistence -> Ordering # (<) :: Persistence -> Persistence -> Bool # (<=) :: Persistence -> Persistence -> Bool # (>) :: Persistence -> Persistence -> Bool # (>=) :: Persistence -> Persistence -> Bool # max :: Persistence -> Persistence -> Persistence # min :: Persistence -> Persistence -> Persistence # | |
type Rep Persistence Source # | |
Limit setting for the ConcUnlift
strategy.
Constructors
Limited !Int | Behavior dependent on the For For |
Unlimited | Unlimited use of the unlifting function. |
Instances
Generic Limit Source # | |
Show Limit Source # | |
Eq Limit Source # | |
Ord Limit Source # | |
type Rep Limit Source # | |
Defined in Effectful.Internal.Unlift type Rep Limit = D1 ('MetaData "Limit" "Effectful.Internal.Unlift" "effectful-core-0.1-inplace" 'False) (C1 ('MetaCons "Limited" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Int)) :+: C1 ('MetaCons "Unlimited" 'PrefixI 'False) (U1 :: Type -> Type)) |
unliftStrategy :: IOE :> es => Eff es UnliftStrategy Source #
Get the current UnliftStrategy
.
withUnliftStrategy :: IOE :> es => UnliftStrategy -> Eff es a -> Eff es a Source #
Locally override the UnliftStrategy
with the given value.
Arguments
:: (HasCallStack, IOE :> es) | |
=> ((forall r. Eff es r -> IO r) -> IO a) | Continuation with the unlifting function in scope. Note: the strategy is reset to |
-> Eff es a |
Create an unlifting function with the current UnliftStrategy
.
This function is equivalent to withRunInIO
, but has a
HasCallStack
constraint for accurate stack traces in case an insufficiently
powerful UnliftStrategy
is used and the unlifting function fails.
Re-exports
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
Lift a computation from the IO
monad.
This allows us to run IO computations in any monadic stack, so long as it supports these kinds of operations
(i.e. IO
is the base monad for the stack).
Example
import Control.Monad.Trans.State -- from the "transformers" library printState :: Show s => StateT s IO () printState = do state <- get liftIO $ print state
Had we omitted
, we would have ended up with this error:liftIO
• Couldn't match type ‘IO’ with ‘StateT s IO’ Expected type: StateT s IO () Actual type: IO ()
The important part here is the mismatch between StateT s IO ()
and
.IO
()
Luckily, we know of a function that takes an
and returns an IO
a(m a)
:
,
enabling us to run the program and see the expected results:liftIO
> evalStateT printState "hello" "hello" > evalStateT printState 3 3
Instances
class MonadIO m => MonadUnliftIO (m :: Type -> Type) where #
Methods
withRunInIO :: ((forall a. m a -> IO a) -> IO b) -> m b #
Instances
MonadUnliftIO IO | |
Defined in Control.Monad.IO.Unlift | |
IOE :> es => MonadUnliftIO (Eff es) Source # | Use |
Defined in Effectful.Internal.Monad | |
MonadUnliftIO m => MonadUnliftIO (IdentityT m) | |
Defined in Control.Monad.IO.Unlift | |
MonadUnliftIO m => MonadUnliftIO (ReaderT r m) | |
Defined in Control.Monad.IO.Unlift |