Safe Haskell | Safe |
---|---|
Language | Haskell2010 |
This module exports functions, types, and typeclasses necessary for implementing a custom effect and/or effect handler.
Synopsis
- data Eff r a
- run :: Eff '[] w -> w
- eff :: (a -> b) -> (forall v. Arrs r v a -> Union r v -> b) -> Eff r a -> b
- impurePrj :: Member t r => (Arrs r v a -> t v -> b) -> (Arrs r v a -> Union r v -> b) -> Arrs r v a -> Union r v -> b
- impureDecomp :: (Arrs (t ': r) v a -> t v -> b) -> (Arrs (t ': r) v a -> Union r v -> b) -> Arrs (t ': r) v a -> Union (t ': r) v -> b
- newtype Lift m a = Lift {
- unLift :: m a
- type Lifted m r = SetMember Lift (Lift m) r
- type LiftedBase m r = (SetMember Lift (Lift m) r, MonadBaseControl m (Eff r))
- lift :: Lifted m r => m a -> Eff r a
- runLift :: Monad m => Eff '[Lift m] w -> m w
- catchDynE :: forall e a r. (Lifted IO r, Exception e) => Eff r a -> (e -> Eff r a) -> Eff r a
- data HandlerDynE r a = (Exception e, Lifted IO r) => HandlerDynE (e -> Eff r a)
- catchesDynE :: Lifted IO r => Eff r a -> [HandlerDynE r a] -> Eff r a
- data Union (r :: [* -> *]) v
- class FindElem t r => Member (t :: * -> *) r
- inj :: Member t r => t v -> Union r v
- prj :: Member t r => Union r v -> Maybe (t v)
- decomp :: Union (t ': r) v -> Either (Union r v) (t v)
- class Member t r => SetMember (tag :: k -> * -> *) (t :: * -> *) r | tag r -> t
- weaken :: Union r w -> Union (any ': r) w
- class Handle t k
- handle :: Handle t k => (v -> k) -> t v -> k
- class Relay k r
- relay :: Relay k r => (v -> k) -> Union r v -> k
- handle_relay :: forall t k r a. Handle t k => Relay k r => (a -> k) -> Eff (t ': r) a -> k
- handle_relay' :: forall t k r a. Relay k r => (a -> k) -> (forall v. (v -> k) -> t v -> k) -> Eff (t ': r) a -> k
- respond_relay :: Member t r => Relay k r => (a -> k) -> (forall v. (v -> k) -> t v -> k) -> Eff r a -> k
- respond_relay' :: forall t k r a. (Member t r, Handle t k, Relay k r) => (a -> k) -> Eff r a -> k
- raise :: Eff r a -> Eff (e ': r) a
- send :: Member t r => t v -> Eff r v
- type Arr r a b = a -> Eff r b
- data Arrs r a b
- first :: Arr r a b -> Arr r (a, c) (b, c)
- singleK :: Arr r a b -> Arrs r a b
- qApp :: forall r b w. Arrs r b w -> Arr r b w
- (^$) :: forall r b w. Arrs r b w -> Arr r b w
- arr :: (a -> b) -> Arrs r a b
- ident :: Arrs r a a
- comp :: Arrs r a b -> Arrs r b c -> Arrs r a c
- (^|>) :: Arrs r a b -> Arr r b c -> Arrs r a c
- qComp :: Arrs r a b -> (Eff r b -> k) -> a -> k
- qComps :: Arrs r a b -> (Eff r b -> Eff r' c) -> Arrs r' a c
- (^|$^) :: Arrs r a b -> (Eff r b -> Eff r' c) -> Arrs r' a c
- (~^) :: Arr r a b -> Arrs r a b
- qThen :: (Eff r b -> k) -> Arrs r a b -> a -> k
- andThen :: ((b -> c) -> t) -> (Eff r w -> c) -> Arrs r b w -> t
The effect monad
The monad that all effects in this library are based on.
An effectful computation is a value of type `Eff r a`.
In this signature, r
is a type-level list of effects that are being
requested and need to be handled inside an effectful computation.
a
is the computation's result similar to other monads.
A computation's result can be retrieved via the run
function.
However, all effects used in the computation need to be handled by the use
of the effects' run*
functions before unwrapping the final result.
For additional details, see the documentation of the effects you are using.
Instances
run :: Eff '[] w -> w Source #
Get the result from a pure computation
A pure computation has type Eff '[] a
. The empty effect-list indicates that
no further effects need to be handled.
impurePrj :: Member t r => (Arrs r v a -> t v -> b) -> (Arrs r v a -> Union r v -> b) -> Arrs r v a -> Union r v -> b Source #
impureDecomp :: (Arrs (t ': r) v a -> t v -> b) -> (Arrs (t ': r) v a -> Union r v -> b) -> Arrs (t ': r) v a -> Union (t ': r) v -> b Source #
Lifting operations
Lifting: emulating monad transformers
type Lifted m r = SetMember Lift (Lift m) r Source #
A convenient alias to 'SetMember Lift (Lift m) r', which allows us to assert that the lifted type occurs ony once in the effect list.
type LiftedBase m r = (SetMember Lift (Lift m) r, MonadBaseControl m (Eff r)) Source #
Same as Lifted
but with additional MonadBaseControl
constraint
lift :: Lifted m r => m a -> Eff r a Source #
embed an operation of type `m a` into the Eff
monad when Lift m
is in
a part of the effect-list.
runLift :: Monad m => Eff '[Lift m] w -> m w Source #
The handler of Lift requests. It is meant to be terminal: we only allow a single Lifted Monad. Note, too, how this is different from other handlers.
catchDynE :: forall e a r. (Lifted IO r, Exception e) => Eff r a -> (e -> Eff r a) -> Eff r a Source #
Catching of dynamic exceptions See the problem in http://okmij.org/ftp/Haskell/misc.html#catch-MonadIO
data HandlerDynE r a Source #
You need this when using catches
.
(Exception e, Lifted IO r) => HandlerDynE (e -> Eff r a) |
catchesDynE :: Lifted IO r => Eff r a -> [HandlerDynE r a] -> Eff r a Source #
Catch multiple dynamic exceptions. The implementation follows that in Control.Exception almost exactly. Not yet tested. Could this be useful for control with cut?
Open Unions
data Union (r :: [* -> *]) v Source #
The data constructors of Union are not exported
Strong Sum (Existential with the evidence) is an open union t is can be a GADT and hence not necessarily a Functor. Int is the index of t in the list r; that is, the index of t in the universe r
class FindElem t r => Member (t :: * -> *) r Source #
Typeclass that asserts that effect t
is contained inside the effect-list
r
.
The FindElem
typeclass is an implementation detail and not required for
using the effect list or implementing custom effects.
Instances
FindElem t r => Member t r Source # | |
t ~ s => Member t (s ': ([] :: [Type -> Type])) Source # | Explicit type-level equality condition is a dirty
hack to eliminate the type annotation in the trivial case,
such as There is no ambiguity when finding instances for
The only case we have to concerned about is |
class Member t r => SetMember (tag :: k -> * -> *) (t :: * -> *) r | tag r -> t Source #
This class is used for emulating monad transformers
Helper functions that are used for implementing effect-handlers
Respond to requests of type t
.
Instances
Handle Trace (IO k) Source # | Given a callback and request, respond to it |
(Alternative f, Monad m) => Handle NdetEff (m (f a)) Source # | Given a callback and NdetEff requests respond to them |
Defined in Control.Eff.NdetEff | |
Monad m => Handle Choose (m [a]) Source # | Given a continuation and a Choose request, respond to it. |
Defined in Control.Eff.Choose | |
Handle Fresh (Int -> r) Source # | Given a continuation and requests, respond to them |
Monad m => Handle (Writer w) (b -> (w -> b -> b) -> m (a, b)) Source # | Given a value to write, and a callback (which includes empty and append), respond to requests. |
Defined in Control.Eff.Writer.Strict | |
Monad m => Handle (Writer w) (b -> (w -> b -> b) -> m (a, b)) Source # | Given a value to write, and a callback (which includes empty and append), respond to requests. |
Defined in Control.Eff.Writer.Lazy | |
Handle (State s) (s -> r) Source # | Handle 'State s' requests |
Defined in Control.Eff.State.Strict | |
Handle (State s) (s -> r) Source # | Handle 'State s' requests |
Defined in Control.Eff.State.Lazy | |
Handle (OnDemandState s) (s -> r) Source # | Given a continuation, respond to requests |
Defined in Control.Eff.State.OnDemand handle :: (v -> s -> r) -> OnDemandState s v -> s -> r Source # | |
Monad m => Handle (Lift m) (m k) Source # | Handle lifted requests by running them sequentially |
Defined in Control.Eff.Internal | |
Monad m => Handle (Exc e :: Type -> Type) (m (Either e a)) Source # | Given a callback, and an |
Handle (Reader e) (e -> r) Source # | Given a value to read, and a callback, how to respond to requests. |
Defined in Control.Eff.Reader.Strict | |
Handle (Reader e) (e -> r) Source # | Given a value to read, and a callback, how to respond to requests. |
Defined in Control.Eff.Reader.Lazy | |
Handle (Program f) (Intrprtr f r -> Eff r a) Source # | Given a continuation and a program, interpret it |
Handle (Yield a b) (Eff r (Y r b a)) Source # | Given a continuation and a request, respond to it |
Abstract the recursive relay
pattern, i.e., "somebody else's
problem".
A convenient pattern: given a request (in an open union), either handle it (using default Handler) or relay it.
Handle implies that all requests of type t
are dealt with,
i.e., k
(the response type) doesn't have t
as part of its
effect list. The Relay k r
constraint ensures that k
is an
effectful computation (with effectlist r
).
Note that we can only handle the leftmost effect type (a
consequence of the OpenUnion
implementation.
A less commonly needed variant with an explicit handler (instead
of Handle t k
constraint).
respond_relay :: Member t r => Relay k r => (a -> k) -> (forall v. (v -> k) -> t v -> k) -> Eff r a -> k Source #
Intercept the request and possibly respond to it, but leave it
unhandled. The Relay k r
constraint ensures that k
is an
effectful computation (with effectlist r
). As such, the effect
type t
will show up in the response type k
.
respond_relay' :: forall t k r a. (Member t r, Handle t k, Relay k r) => (a -> k) -> Eff r a -> k Source #
A less common variant which uses the default handle
from the
Handle t k
instance (in general, we may need to define new
datatypes to call respond_relay with the default handler).
send :: Member t r => t v -> Eff r v Source #
Send a request and wait for a reply (resulting in an effectful computation).
Arrow types and compositions
type Arr r a b = a -> Eff r b Source #
Effectful arrow type: a function from a to b that also does effects denoted by r
An effectful function from a
to b
that is a composition of one or more
effectful functions. The paremeter r describes the overall effect.
The composition members are accumulated in a type-aligned queue.
Using a newtype here enables us to define Category
and Arrow
instances.
qComp :: Arrs r a b -> (Eff r b -> k) -> a -> k Source #
Compose effectful arrows (and possibly change the effect!)