Safe Haskell | Safe |
---|---|
Language | Haskell2010 |
This module exports functions, types, and typeclasses necessary for implementing a custom effect and/or effect handler.
- data Eff r a
- run :: Eff '[] w -> w
- data Union (r :: [* -> *]) v
- class FindElem t r => Member (t :: * -> *) r where
- 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
- handle_relay :: (a -> Eff r w) -> (forall v. t v -> Arr r v w -> Eff r w) -> Eff (t ': r) a -> Eff r w
- handle_relay_s :: s -> (s -> a -> Eff r w) -> (forall v. s -> t v -> (s -> Arr r v w) -> Eff r w) -> Eff (t ': r) a -> Eff r w
- interpose :: Member t r => (a -> Eff r w) -> (forall v. t v -> Arr r v w -> Eff r w) -> Eff r a -> Eff r w
- 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 -> Eff r' c) -> Arr r' a c
- qComps :: Arrs r a b -> (Eff r b -> Eff r' c) -> Arrs r' a c
The effect monad
The Eff monad (not a transformer!). It is a fairly standard coroutine monad
where the type r
is the type of effects that can be handled, and the
missing type a
(from the type application) is the type of value that is
returned. It is NOT a Free monad! There are no Functor constraints.
The two constructors denote the status of a coroutine (client): done with the
value of type a, or sending a request of type Union r with the continuation
Arrs r b a. Expressed another way: an Eff
can either be a value (i.e.,
Val
case), or an effect of type
producing another Union
rEff
(i.e.,
E
case). The result is that an Eff
can produce an arbitrarily long chain
of
effects, terminated with a pure value.Union
r
Potentially, inline Union into E
(MonadBase b m, SetMember (* -> *) (Lift *) (Lift * m) r) => MonadBase b (Eff r) Source # | |
MonadBase m m => MonadBaseControl m (Eff ((:) (* -> *) (Lift * m) ([] (* -> *)))) Source # | |
(MonadBase m m, SetMember (* -> *) (Lift *) (Lift * m) r, MonadBaseControl m (Eff r)) => MonadBaseControl m (Eff ((:) (* -> *) (Writer w) r)) # | |
(MonadBase m m, SetMember (* -> *) (Lift *) (Lift * m) r, MonadBaseControl m (Eff r)) => MonadBaseControl m (Eff ((:) (* -> *) (Writer w) r)) # | |
(MonadBase m m, SetMember (* -> *) (Lift *) (Lift * m) s, MonadBaseControl m (Eff s)) => MonadBaseControl m (Eff ((:) (* -> *) (Reader * e) s)) # | |
(MonadBase m m, SetMember (* -> *) (Lift *) (Lift * m) r, MonadBaseControl m (Eff r)) => MonadBaseControl m (Eff ((:) (* -> *) (State s) r)) # | |
(MonadBase m m, SetMember (* -> *) (Lift *) (Lift * m) s, MonadBaseControl m (Eff s)) => MonadBaseControl m (Eff ((:) (* -> *) (Reader * e) s)) # | |
(MonadBase m m, SetMember (* -> *) (Lift *) (Lift * m) r, MonadBaseControl m (Eff r)) => MonadBaseControl m (Eff ((:) (* -> *) (OnDemandState s) r)) # | |
(MonadBase m m, SetMember (* -> *) (Lift *) (Lift * m) r, MonadBaseControl m (Eff r)) => MonadBaseControl m (Eff ((:) (* -> *) (State s) r)) # | |
(MonadBase m m, SetMember (* -> *) (Lift *) (Lift * m) r, MonadBaseControl m (Eff r)) => MonadBaseControl m (Eff ((:) (* -> *) NdetEff r)) # | |
(MonadBase m m, SetMember (* -> *) (Lift *) (Lift * m) r, MonadBaseControl m (Eff r)) => MonadBaseControl m (Eff ((:) (* -> *) Fresh r)) # | |
(MonadBase m m, SetMember (* -> *) (Lift *) (Lift * m) r, MonadBaseControl m (Eff r)) => MonadBaseControl m (Eff ((:) (* -> *) (Exc * e) r)) # | |
(MonadBase m m, SetMember (* -> *) (Lift *) (Lift * m) r, MonadBaseControl m (Eff r)) => MonadBaseControl m (Eff ((:) (* -> *) Choose r)) # | |
Monad (Eff r) Source # | |
Functor (Eff r) Source # | Eff is still a monad and a functor (and Applicative) (despite the lack of the Functor constraint) |
Applicative (Eff r) Source # | |
(MonadIO m, SetMember (* -> *) (Lift *) (Lift * m) r) => MonadIO (Eff r) Source # | |
type StM (Eff ((:) (* -> *) (Lift * m) ([] (* -> *)))) a Source # | |
type StM (Eff ((:) (* -> *) (Writer w) r)) a # | |
type StM (Eff ((:) (* -> *) (Writer w) r)) a # | |
type StM (Eff ((:) (* -> *) (State s) r)) a # | |
type StM (Eff ((:) (* -> *) (OnDemandState s) r)) a # | |
type StM (Eff ((:) (* -> *) (State s) r)) a # | |
type StM (Eff ((:) (* -> *) NdetEff r)) a # | |
type StM (Eff ((:) (* -> *) Fresh r)) a # | |
type StM (Eff ((:) (* -> *) Choose r)) a # | |
type StM (Eff ((:) (* -> *) (Reader * e) s)) a # | |
type StM (Eff ((:) (* -> *) (Reader * e) s)) a # | |
type StM (Eff ((:) (* -> *) (Exc * e) r)) a # | |
run :: Eff '[] w -> w Source #
Get the result from a pure (i.e. no effects) computation.
The type of run ensures that all effects must be handled: only pure computations can be run.
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 where Source #
Typeclass that asserts that effect t
is contained inside the effect-list
r
.
The FindElem
typeclass is necessary for implementation reasons and is not
required for using the effect list.
FindElem [* -> *] t r => Member t r Source # | |
(~) (* -> *) t s => Member t ((:) (* -> *) s ([] (* -> *))) 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
handle_relay :: (a -> Eff r w) -> (forall v. t v -> Arr r v w -> Eff r w) -> Eff (t ': r) a -> Eff r w Source #
A convenient pattern: given a request (open union), either handle it or relay it.
handle_relay_s :: s -> (s -> a -> Eff r w) -> (forall v. s -> t v -> (s -> Arr r v w) -> Eff r w) -> Eff (t ': r) a -> Eff r w Source #
Parameterized handle_relay
interpose :: Member t r => (a -> Eff r w) -> (forall v. t v -> Arr r v w -> Eff r w) -> Eff r a -> Eff r w Source #
Add something like Control.Exception.catches? It could be useful for control with cut.
Intercept the request and possibly reply to it, but leave it unhandled (that's why we use the same r all throuout)
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.