-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | An Alternative to Monad Transformers -- -- This package introduces datatypes for typeclass-constrained effects, -- as an alternative to monad-transformer based (datatype-constrained) -- approach of multi-layered effects. Any help is appreciated! @package extensible-effects @version 3.1.0.0 -- | Open unions (type-indexed co-products) for extensible effects All -- operations are constant-time, and there is no Typeable constraint -- -- This is a variation of OpenUion5.hs, which relies on overlapping -- instances instead of closed type families. Closed type families have -- their problems: overlapping instances can resolve even for unground -- types, but closed type families are subject to a strict apartness -- condition. -- -- This implementation is very similar to OpenUnion1.hs, but without the -- annoying Typeable constraint. We sort of emulate it: -- -- Our list r of open union components is a small Universe. Therefore, we -- can use the Typeable-like evidence in that universe. We hence can -- define -- --
--   data Union r v where
--     Union :: t v -> TRep t r -> Union r v -- t is existential
--   
-- -- where -- --
--   data TRep t r where
--     T0 :: TRep t (t ': r)
--     TS :: TRep t r -> TRep (any ': r)
--   
-- -- Then Member is a type class that produces TRep Taken literally it -- doesn't seem much better than OpenUinion41.hs. However, we can cheat -- and use the index of the type t in the list r as the TRep. (We will -- need UnsafeCoerce then). -- -- The interface is the same as of other OpenUnion*.hs module Data.OpenUnion -- | 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 data Union (r :: [* -> *]) v 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) -- | 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. class (FindElem t r) => Member (t :: * -> *) r -- | This class is used for emulating monad transformers class Member t r => SetMember (tag :: k -> * -> *) (t :: * -> *) r | tag r -> t -- | A useful operator for reducing boilerplate in signatures. -- -- The following lines are equivalent. -- --
--   (Member (Exc e) r, Member (State s) r) => ...
--   [ Exc e, State s ] r = ...
--   
weaken :: Union r w -> Union (any : r) w instance forall k (t1 :: * -> *) (t2 :: * -> *) (p :: GHC.Types.Bool) (tag :: k -> * -> *) (r :: [* -> *]). (Data.OpenUnion.EQU t1 t2 p, Data.OpenUnion.MemberU' p tag t1 (t2 : r)) => Data.OpenUnion.SetMember tag t1 (t2 : r) instance forall k (tag :: k -> * -> *) (e :: k) (r :: [* -> *]). Data.OpenUnion.MemberU' 'GHC.Types.True tag (tag e) (tag e : r) instance forall k (t :: * -> *) (t' :: * -> *) (r :: [* -> *]) (tag :: k -> * -> *). (Data.OpenUnion.Member t (t' : r), Data.OpenUnion.SetMember tag t r) => Data.OpenUnion.MemberU' 'GHC.Types.False tag t (t' : r) instance forall k (a :: k). Data.OpenUnion.EQU a a 'GHC.Types.True instance forall k (p :: GHC.Types.Bool) (a :: k) (b :: k). (p ~ 'GHC.Types.False) => Data.OpenUnion.EQU a b p instance (t ~ s) => Data.OpenUnion.Member t '[s] instance Data.OpenUnion.FindElem t r => Data.OpenUnion.Member t r instance Data.OpenUnion.FindElem t (t : r) instance forall a (t :: * -> *) (r :: [a]) (t' :: a). Data.OpenUnion.FindElem t r => Data.OpenUnion.FindElem t (t' : r) instance (TypeError ...) => Data.OpenUnion.FindElem t '[] -- | Lifting primitive Monad types to effectful computations. We only allow -- a single Lifted Monad because Monads aren't commutative (e.g. Maybe -- (IO a) is functionally distinct from IO (Maybe a)). module Control.Eff.Lift -- | Lifting: emulating monad transformers newtype Lift m a Lift :: (m a) -> Lift m a -- | A convenient alias to 'SetMember Lift (Lift m) r' type Lifted m r = SetMember Lift (Lift m) r -- | Same as Lifted but with additional MonadBaseControl -- constraint type LiftedBase m r = (SetMember Lift (Lift m) r, MonadBaseControl m (Eff r)) -- | embed an operation of type `m a` into the Eff monad when -- Lift m is in a part of the effect-list. -- -- By using SetMember, it is possible to assert that the lifted type -- occurs only once in the effect list lift :: (SetMember Lift (Lift m) r) => m a -> Eff r a -- | The handler of Lift requests. It is meant to be terminal: we only -- allow a single Lifted Monad. runLift :: Monad m => Eff '[Lift m] w -> m w -- | Catching of dynamic exceptions See the problem in -- http://okmij.org/ftp/Haskell/misc.html#catch-MonadIO catchDynE :: forall e a r. (Lifted IO r, Exception e) => Eff r a -> (e -> Eff r a) -> Eff r a -- | This module exports functions, types, and typeclasses necessary for -- implementing a custom effect and/or effect handler. module Control.Eff.Extend -- | 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. data Eff r a Val :: a -> Eff r a E :: (Union r b) -> (Arrs r b a) -> Eff r a -- | 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. run :: Eff '[] w -> w -- | 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 data Union (r :: [* -> *]) v -- | 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. 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) -- | This class is used for emulating monad transformers class Member t r => SetMember (tag :: k -> * -> *) (t :: * -> *) r | tag r -> t weaken :: Union r w -> Union (any : r) w -- | A convenient pattern: given a request (open union), either handle it -- or relay it. handle_relay :: (a -> Eff r w) -> (forall v. t v -> Arr r v w -> Eff r w) -> Eff (t : r) a -> Eff r w -- | Parameterized handle_relay 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 -- | Intercept the request and possibly reply to it, but leave it unhandled -- (that's why the same r is used all throuout) 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 -- | Embeds a less-constrained Eff into a more-constrained one. -- Analogous to MTL's lift. raise :: Eff r a -> Eff (e : r) a -- | Send a request and wait for a reply (resulting in an effectful -- computation). send :: Member t r => t v -> Eff r v -- | Effectful arrow type: a function from a to b that also does effects -- denoted by r type Arr r a b = a -> Eff r b -- | 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. data Arrs r a b first :: Arr r a b -> Arr r (a, c) (b, c) -- | convert single effectful arrow into composable type. i.e., convert -- Arr to Arrs singleK :: Arr r a b -> Arrs r a b -- | Application to the `generalized effectful function' Arrs r b w, i.e., -- convert Arrs to Arr qApp :: forall r b w. Arrs r b w -> Arr r b w -- | Syntactic sugar for qApp (^$) :: forall r b w. Arrs r b w -> Arr r b w -- | Lift a function to an arrow arr :: (a -> b) -> Arrs r a b -- | The identity arrow ident :: Arrs r a a -- | Arrow composition comp :: Arrs r a b -> Arrs r b c -> Arrs r a c -- | Common pattern: append Arr to Arrs (^|>) :: Arrs r a b -> Arr r b c -> Arrs r a c -- | Compose effectful arrows (and possibly change the effect!) qComp :: Arrs r a b -> (Eff r b -> Eff r' c) -> Arr r' a c -- | Compose effectful arrows (and possibly change the effect!) qComps :: Arrs r a b -> (Eff r b -> Eff r' c) -> Arrs r' a c -- | A monadic library for implementing effectful computation in a modular -- way. -- -- This module provides the Eff monad - the base type for all -- effectful computation. The Member typeclass is the main -- interface for describing which effects are necessary for a given -- function. -- -- Consult the Control.Eff.QuickStart module and the readme for -- gentle introductions. -- -- To use extensible effects effectively some language extensions are -- necessary/recommended. -- --
--   {-# LANGUAGE ScopedTypeVariables #-}
--   {-# LANGUAGE FlexibleContexts #-}
--   {-# LANGUAGE MonoLocalBinds #-}
--   
module Control.Eff -- | 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. run :: Eff '[] w -> w -- | 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. data Eff r a -- | 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. class (FindElem t r) => Member (t :: * -> *) r -- | This class is used for emulating monad transformers class Member t r => SetMember (tag :: k -> * -> *) (t :: * -> *) r | tag r -> t -- | A useful operator for reducing boilerplate in signatures. -- -- The following lines are equivalent. -- --
--   (Member (Exc e) r, Member (State s) r) => ...
--   [ Exc e, State s ] r = ...
--   
-- | Strict write-only state module Control.Eff.Writer.Strict -- | The Writer monad -- -- In MTL's Writer monad, the told value must have a |Monoid| type. Our -- writer has no such constraints. If we write a |Writer|-like -- interpreter to accumulate the told values in a monoid, it will have -- the |Monoid w| constraint then data Writer w v [Tell] :: !w -> Writer w () -- | Write a new value. tell :: Member (Writer w) r => w -> Eff r () -- | Transform the state being produced. censor :: forall w a r. Member (Writer w) r => (w -> w) -> Eff r a -> Eff r a -- | Handle Writer requests, using a user-provided function to accumulate -- values, hence no Monoid constraints. runWriter :: (w -> b -> b) -> b -> Eff (Writer w : r) a -> Eff r (a, b) -- | Handle Writer requests by taking the first value provided. runFirstWriter :: Eff (Writer w : r) a -> Eff r (a, Maybe w) -- | Handle Writer requests by overwriting previous values. runLastWriter :: Eff (Writer w : r) a -> Eff r (a, Maybe w) -- | Handle Writer requests, using a List to accumulate values. runListWriter :: Eff (Writer w : r) a -> Eff r (a, [w]) -- | Handle Writer requests, using a Monoid instance to accumulate values. runMonoidWriter :: (Monoid w) => Eff (Writer w : r) a -> Eff r (a, w) -- | Handle Writer requests, using a user-provided function to accumulate -- values and returning the final accumulated values. execWriter :: (w -> b -> b) -> b -> Eff (Writer w : r) a -> Eff r b -- | Handle Writer requests by taking the first value provided and and -- returning the final accumulated values. execFirstWriter :: Eff (Writer w : r) a -> Eff r (Maybe w) -- | Handle Writer requests by overwriting previous values and returning -- the final accumulated values. execLastWriter :: Eff (Writer w : r) a -> Eff r (Maybe w) -- | Handle Writer requests, using a List to accumulate values and -- returning the final accumulated values. execListWriter :: Eff (Writer w : r) a -> Eff r [w] -- | Handle Writer requests, using a Monoid instance to accumulate values -- and returning the final accumulated values. execMonoidWriter :: (Monoid w) => Eff (Writer w : r) a -> Eff r w instance (Control.Monad.Base.MonadBase m m, Data.OpenUnion.SetMember Control.Eff.Internal.Lift (Control.Eff.Internal.Lift m) r, Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff r)) => Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff (Control.Eff.Writer.Strict.Writer w : r)) -- | Lazy write-only state module Control.Eff.Writer.Lazy -- | The Writer monad -- -- In MTL's Writer monad, the told value must have a |Monoid| type. Our -- writer has no such constraints. If we write a |Writer|-like -- interpreter to accumulate the told values in a monoid, it will have -- the |Monoid w| constraint then data Writer w v [Tell] :: w -> Writer w () -- | Write a new value. tell :: Member (Writer w) r => w -> Eff r () -- | Transform the state being produced. censor :: forall w a r. Member (Writer w) r => (w -> w) -> Eff r a -> Eff r a -- | Handle Writer requests, using a user-provided function to accumulate -- values, hence no Monoid constraints. runWriter :: (w -> b -> b) -> b -> Eff (Writer w : r) a -> Eff r (a, b) -- | Handle Writer requests by taking the first value provided. runFirstWriter :: Eff (Writer w : r) a -> Eff r (a, Maybe w) -- | Handle Writer requests by overwriting previous values. runLastWriter :: Eff (Writer w : r) a -> Eff r (a, Maybe w) -- | Handle Writer requests, using a List to accumulate values. runListWriter :: Eff (Writer w : r) a -> Eff r (a, [w]) -- | Handle Writer requests, using a Monoid instance to accumulate values. runMonoidWriter :: (Monoid w) => Eff (Writer w : r) a -> Eff r (a, w) -- | Handle Writer requests, using a user-provided function to accumulate -- values and returning the final accumulated values. execWriter :: (w -> b -> b) -> b -> Eff (Writer w : r) a -> Eff r b -- | Handle Writer requests by taking the first value provided and and -- returning the final accumulated values. execFirstWriter :: Eff (Writer w : r) a -> Eff r (Maybe w) -- | Handle Writer requests by overwriting previous values and returning -- the final accumulated values. execLastWriter :: Eff (Writer w : r) a -> Eff r (Maybe w) -- | Handle Writer requests, using a List to accumulate values and -- returning the final accumulated values. execListWriter :: Eff (Writer w : r) a -> Eff r [w] -- | Handle Writer requests, using a Monoid instance to accumulate values -- and returning the final accumulated values. execMonoidWriter :: (Monoid w) => Eff (Writer w : r) a -> Eff r w instance (Control.Monad.Base.MonadBase m m, Data.OpenUnion.SetMember Control.Eff.Internal.Lift (Control.Eff.Internal.Lift m) r, Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff r)) => Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff (Control.Eff.Writer.Lazy.Writer w : r)) -- | A Trace effect for debugging module Control.Eff.Trace -- | Trace effect for debugging data Trace v [Trace] :: String -> Trace () -- | Print a string as a trace. trace :: Member Trace r => String -> Eff r () -- | Run a computation producing Traces. The handler for IO request: a -- terminal handler runTrace :: Eff '[Trace] w -> IO w -- | Strict read-only state module Control.Eff.Reader.Strict -- | The Reader monad -- -- The request for a value of type e from the current environment This -- can be expressed as a GADT because the type of values returned in -- response to a (Reader e a) request is not any a; we expect in reply -- the value of type e, the value from the environment. So, the -- return type is restricted: 'a ~ e' -- -- One can also define this as -- --
--   data Reader e v = (e ~ v) => Reader
--   
-- -- ^ without GADTs, using explicit coercion as is done here. -- --
--   newtype Reader e v = Reader (e->v)
--   
-- -- ^ In the latter case, when we make the request, we make it as Reader -- id. So, strictly speaking, GADTs are not really necessary. data Reader e v [Ask] :: Reader e e -- | Get the current value from a Reader. The signature is inferred (when -- using NoMonomorphismRestriction). ask :: (Member (Reader e) r) => Eff r e -- | Locally rebind the value in the dynamic environment This function is -- like a relay; it is both an admin for Reader requests, and a requestor -- of them local :: forall e a r. Member (Reader e) r => (e -> e) -> Eff r a -> Eff r a -- | Request the environment value using a transformation function. reader :: (Member (Reader e) r) => (e -> a) -> Eff r a -- | The handler of Reader requests. The return type shows that all Reader -- requests are fully handled. runReader :: e -> Eff (Reader e : r) w -> Eff r w instance (Control.Monad.Base.MonadBase m m, Data.OpenUnion.SetMember Control.Eff.Internal.Lift (Control.Eff.Internal.Lift m) s, Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff s)) => Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff (Control.Eff.Reader.Strict.Reader e : s)) -- | Strict state effect module Control.Eff.State.Strict -- | State, strict -- -- Initial design: The state request carries with it the state mutator -- function We can use this request both for mutating and getting the -- state. But see below for a better design! -- --
--   data State s v where
--     State :: (s->s) -> State s s
--   
-- -- In this old design, we have assumed that the dominant operation is -- modify. Perhaps this is not wise. Often, the reader is most nominant. -- -- See also below, for decomposing the State into Reader and Writer! -- -- The conventional design of State data State s v [Get] :: State s s [Put] :: !s -> State s () -- | Return the current value of the state. The signatures are inferred get :: Member (State s) r => Eff r s -- | Write a new value of the state. put :: Member (State s) r => s -> Eff r () runState' :: s -> Eff (State s : r) a -> Eff r (a, s) -- | Run a State effect runState :: s -> Eff (State s : r) a -> Eff r (a, s) -- | Transform the state with a function. modify :: (Member (State s) r) => (s -> s) -> Eff r () -- | Run a State effect, discarding the final state. evalState :: s -> Eff (State s : r) a -> Eff r a -- | Run a State effect and return the final state. execState :: s -> Eff (State s : r) a -> Eff r s -- | An encapsulated State handler, for transactional semantics The global -- state is updated only if the transactionState finished successfully data TxState s TxState :: TxState s transactionState :: forall s r a. Member (State s) r => TxState s -> Eff r a -> Eff r a -- | A different representation of State: decomposing State into mutation -- (Writer) and Reading. We don't define any new effects: we just handle -- the existing ones. Thus we define a handler for two effects together. runStateR :: s -> Eff (Writer s : Reader s : r) a -> Eff r (a, s) instance (Control.Monad.Base.MonadBase m m, Data.OpenUnion.SetMember Control.Eff.Internal.Lift (Control.Eff.Internal.Lift m) r, Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff r)) => Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff (Control.Eff.State.Strict.State s : r)) -- | Lazy read-only state module Control.Eff.Reader.Lazy -- | The Reader monad -- -- The request for a value of type e from the current environment This -- can be expressed as a GADT because the type of values returned in -- response to a (Reader e a) request is not any a; we expect in reply -- the value of type e, the value from the environment. So, the -- return type is restricted: 'a ~ e' -- -- One can also define this as -- --
--   data Reader e v = (e ~ v) => Reader
--   
-- -- ^ without GADTs, using explicit coercion as is done here. -- --
--   newtype Reader e v = Reader (e->v)
--   
-- -- ^ In the latter case, when we make the request, we make it as Reader -- id. So, strictly speaking, GADTs are not really necessary. data Reader e v [Ask] :: Reader e e -- | Get the current value from a Reader. The signature is inferred (when -- using NoMonomorphismRestriction). ask :: (Member (Reader e) r) => Eff r e -- | Locally rebind the value in the dynamic environment This function is -- like a relay; it is both an admin for Reader requests, and a requestor -- of them. local :: forall e a r. Member (Reader e) r => (e -> e) -> Eff r a -> Eff r a -- | Request the environment value using a transformation function. reader :: (Member (Reader e) r) => (e -> a) -> Eff r a -- | The handler of Reader requests. The return type shows that all Reader -- requests are fully handled. runReader :: e -> Eff (Reader e : r) w -> Eff r w instance (Control.Monad.Base.MonadBase m m, Data.OpenUnion.SetMember Control.Eff.Internal.Lift (Control.Eff.Internal.Lift m) s, Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff s)) => Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff (Control.Eff.Reader.Lazy.Reader e : s)) -- | Lazy state effect module Control.Eff.State.OnDemand -- | State, lazy (i.e., on-demand) -- -- Extensible effects make it clear that where the computation is delayed -- (which I take as an advantage) and they do maintain the degree of -- extensibility (the delayed computation must be effect-closed, but the -- whole computation does not have to be). data OnDemandState s v [Get] :: OnDemandState s s [Put] :: s -> OnDemandState s () [Delay] :: Eff '[OnDemandState s] a -> OnDemandState s a -- | Return the current value of the state. The signatures are inferred get :: Member (OnDemandState s) r => Eff r s -- | Write a new value of the state. put :: Member (OnDemandState s) r => s -> Eff r () onDemand :: Member (OnDemandState s) r => Eff '[OnDemandState s] v -> Eff r v runState' :: s -> Eff (OnDemandState s : r) w -> Eff r (w, s) -- | Run a State effect runState :: s -> Eff (OnDemandState s : r) w -> Eff r (w, s) -- | Transform the state with a function. modify :: (Member (OnDemandState s) r) => (s -> s) -> Eff r () -- | Run a State effect, discarding the final state. evalState :: s -> Eff (OnDemandState s : r) w -> Eff r w -- | Run a State effect and return the final state. execState :: s -> Eff (OnDemandState s : r) w -> Eff r s -- | A different representation of State: decomposing State into mutation -- (Writer) and Reading. We don't define any new effects: we just handle -- the existing ones. Thus we define a handler for two effects together. runStateR :: s -> Eff (Writer s : Reader s : r) w -> Eff r (w, s) -- | Backwards state The overall state is represented with two attributes: -- the inherited getAttr and the synthesized putAttr. At the root node, -- putAttr becomes getAttr, tying the knot. As usual, the inherited -- attribute is the argument (i.e., the environment) and the -- synthesized is the result of the handler |go| below. runStateBack0 :: Eff '[OnDemandState s] a -> (a, s) -- | A different notion of backwards is realized if we change the -- Put handler slightly. How? -- -- Another implementation, exploring Haskell's laziness to make putAttr -- also technically inherited, to accumulate the sequence of updates. -- This implementation is compatible with deep handlers, and lets us play -- with different notions of backwardness runStateBack :: Eff '[OnDemandState s] a -> (a, s) instance (Control.Monad.Base.MonadBase m m, Data.OpenUnion.SetMember Control.Eff.Internal.Lift (Control.Eff.Internal.Lift m) r, Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff r)) => Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff (Control.Eff.State.OnDemand.OnDemandState s : r)) -- | Lazy state effect module Control.Eff.State.Lazy -- | State, lazy -- -- Initial design: The state request carries with it the state mutator -- function We can use this request both for mutating and getting the -- state. But see below for a better design! -- --
--   data State s v where
--     State :: (s->s) -> State s s
--   
-- -- In this old design, we have assumed that the dominant operation is -- modify. Perhaps this is not wise. Often, the reader is most nominant. -- -- See also below, for decomposing the State into Reader and Writer! -- -- The conventional design of State data State s v [Get] :: State s s [Put] :: s -> State s () -- | Return the current value of the state. The signatures are inferred get :: Member (State s) r => Eff r s -- | Write a new value of the state. put :: Member (State s) r => s -> Eff r () -- | Run a state effect. compared to the runState function, this -- is implemented naively and is expected to perform slower. runState' :: s -> Eff (State s : r) a -> Eff r (a, s) -- | Run a State effect. This variant is a bit optimized compared to -- runState'. runState :: s -> Eff (State s : r) a -> Eff r (a, s) -- | Transform the state with a function. modify :: (Member (State s) r) => (s -> s) -> Eff r () -- | Run a State effect, discarding the final state. evalState :: s -> Eff (State s : r) a -> Eff r a -- | Run a State effect and return the final state. execState :: s -> Eff (State s : r) a -> Eff r s -- | An encapsulated State handler, for transactional semantics The global -- state is updated only if the transactionState finished successfully data TxState s TxState :: TxState s transactionState :: forall s r a. Member (State s) r => TxState s -> Eff r a -> Eff r a -- | A different representation of State: decomposing State into mutation -- (Writer) and Reading. We don't define any new effects: we just handle -- the existing ones. Thus we define a handler for two effects together. runStateR :: s -> Eff (Writer s : Reader s : r) a -> Eff r (a, s) instance (Control.Monad.Base.MonadBase m m, Data.OpenUnion.SetMember Control.Eff.Internal.Lift (Control.Eff.Internal.Lift m) r, Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff r)) => Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff (Control.Eff.State.Lazy.State s : r)) -- | Operational Monad (https://wiki.haskell.org/Operational) -- implemented with extensible effects. module Control.Eff.Operational -- | Lift values to an effect. You can think this is a generalization of -- Lift. data Program instr v [Singleton] :: instr a -> Program instr a -- | Lift a value to a monad. singleton :: (Member (Program instr) r) => instr a -> Eff r a -- | Convert values using given interpreter to effects. runProgram :: forall f r a. (forall x. f x -> Eff r x) -> Eff (Program f : r) a -> Eff r a -- | Example usage of Control.Eff.Operational. module Control.Eff.Operational.Example -- | Define data using GADTs. data Jail a [Print] :: String -> Jail () [Scan] :: Jail String prog :: Member (Program Jail) r => Eff r () -- | Then, implements interpreters from the data to effects. adventIO :: (SetMember Lift (Lift IO) r) => Jail a -> Eff r a adventPure :: (Member (Writer String) r, Member (State [String]) r) => Jail a -> Eff r a -- | Another implementation of nondeterministic choice effect module Control.Eff.NdetEff -- | A different implementation, more directly mapping to MonadPlus -- interface data NdetEff a [MZero] :: NdetEff a [MPlus] :: NdetEff Bool -- | An interpreter The following is very simple, but leaks a lot of memory -- The cause probably is mapping every failure to empty It takes then a -- lot of timne and space to store those empty makeChoiceA0 :: Alternative f => Eff (NdetEff : r) a -> Eff r (f a) -- | A different implementation, more involved but faster and taking much -- less (100 times) less memory. The benefit of the effect framework is -- that we can have many interpreters. makeChoiceA :: Alternative f => Eff (NdetEff : r) a -> Eff r (f a) -- | Same as makeChoiceA, except it has the type hardcoded. Required for -- MonadBaseControl instance. makeChoiceLst :: Eff (NdetEff : r) a -> Eff r [a] msplit :: Member NdetEff r => Eff r a -> Eff r (Maybe (a, Eff r a)) ifte :: Member NdetEff r => Eff r a -> (a -> Eff r b) -> Eff r b -> Eff r b once :: Member NdetEff r => Eff r a -> Eff r a instance Data.OpenUnion.Member Control.Eff.NdetEff.NdetEff r => GHC.Base.Alternative (Control.Eff.Internal.Eff r) instance Data.OpenUnion.Member Control.Eff.NdetEff.NdetEff r => GHC.Base.MonadPlus (Control.Eff.Internal.Eff r) instance (Control.Monad.Base.MonadBase m m, Data.OpenUnion.SetMember Control.Eff.Internal.Lift (Control.Eff.Internal.Lift m) r, Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff r)) => Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff (Control.Eff.NdetEff.NdetEff : r)) -- | Create unique Enumerable values. module Control.Eff.Fresh -- | Create unique Enumerable values. data Fresh v [Fresh] :: Fresh Int -- | Produce a value that has not been previously produced. fresh :: Member Fresh r => Eff r Int -- | Run an effect requiring unique values. runFresh' :: Eff (Fresh : r) w -> Int -> Eff r w instance (Control.Monad.Base.MonadBase m m, Data.OpenUnion.SetMember Control.Eff.Internal.Lift (Control.Eff.Internal.Lift m) r, Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff r)) => Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff (Control.Eff.Fresh.Fresh : r)) -- | Exception-producing and exception-handling effects module Control.Eff.Exception -- | Exceptions -- -- exceptions of the type e; no resumption newtype Exc e v Exc :: e -> Exc e v type Fail = Exc () -- | Throw an exception in an effectful computation. The type is inferred. throwError :: (Member (Exc e) r) => e -> Eff r a -- | Throw an exception in an effectful computation. The type is unit, -- which suppresses the ghc-mod warning "A do-notation statement -- discarded a result of type" throwError_ :: (Member (Exc e) r) => e -> Eff r () -- | Makes an effect fail, preventing future effects from happening. die :: Member Fail r => Eff r a -- | Run a computation that might produce an exception. runError :: Eff (Exc e : r) a -> Eff r (Either e a) -- | Runs a failable effect, such that failed computation return -- Nothing, and Just the return value on success. runFail :: Eff (Fail : r) a -> Eff r (Maybe a) -- | Run a computation that might produce exceptions, and give it a way to -- deal with the exceptions that come up. The handler is allowed to -- rethrow the exception catchError :: Member (Exc e) r => Eff r a -> (e -> Eff r a) -> Eff r a -- | Add a default value (i.e. failure handler) to a fallible computation. -- This hides the fact that a failure happened. onFail :: Eff (Fail : r) a -> Eff r a -> Eff r a -- | Run a computation until it produces an exception, and convert and -- throw that exception in a new context. rethrowError :: (Member (Exc e') r) => (e -> e') -> Eff (Exc e : r) a -> Eff r a -- | Treat Lefts as exceptions and Rights as return values. liftEither :: (Member (Exc e) r) => Either e a -> Eff r a -- | liftEither in a lifted Monad liftEitherM :: (Member (Exc e) r, SetMember Lift (Lift m) r) => m (Either e a) -> Eff r a -- | Lift a maybe into the Fail effect, causing failure if it's -- Nothing. liftMaybe :: Member Fail r => Maybe a -> Eff r a -- | liftMaybe in a lifted Monad liftMaybeM :: (Member Fail r, SetMember Lift (Lift m) r) => m (Maybe a) -> Eff r a -- | Ignores a failure event. Since the event can fail, you cannot inspect -- its return type, because it has none on failure. To inspect it, use -- runFail. ignoreFail :: Eff (Fail : r) a -> Eff r () instance (Control.Monad.Base.MonadBase m m, Data.OpenUnion.SetMember Control.Eff.Internal.Lift (Control.Eff.Internal.Lift m) r, Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff r)) => Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff (Control.Eff.Exception.Exc e : r)) -- | This module contains several tiny examples of how to use effects. For -- technical details, see the documentation in the effect-modules. -- -- Note that most examples given here are very small. For them, using -- Eff monad is more complicated compared to a standard functional -- approach. The power of extensible effects lie in the fact that these -- computations can be used to construct much more complicated programs -- by composing the little pieces shown here. -- -- This module imports and reexports modules from this library and -- requires some language extensions: -- --
--   {-# LANGUAGE ScopedTypeVariables #-}
--   {-# LANGUAGE FlexibleContexts #-}
--   {-# LANGUAGE MonoLocalBinds #-}
--   
--   import Control.Eff
--   import Control.Eff.Reader.Lazy
--   import Control.Eff.Writer.Lazy
--   import Control.Eff.State.Lazy
--   import Control.Eff.Exception
--   
-- -- If you want to see what each extension is good for, you can disable it -- and see what GHC will complain about. module Control.Eff.QuickStart -- | an effectful function that can throw an error -- --
--   tooBig i = do
--     when (i > 100) $ throwError $ show i
--     return i
--   
tooBig :: Member (Exc String) r => Int -> Eff r Int -- | run the tooBig effect based on a provided Int. -- --
--   runTooBig i = run . runError $ tooBig i
--   
-- --
--   >>> runTooBig 1
--   Right 1
--   
-- --
--   >>> runTooBig 200
--   Left "200"
--   
runTooBig :: Int -> Either String Int -- | an effectul computation using state. The state is of type -- [Int]. This function takes the head off the list, if it is -- there and return it. If state is the empty list, then it stays the -- same and returns Nothing. -- --
--   popState = do
--    stack <- get
--    case stack of
--      []       -> return Nothing
--      (x : xs) -> do
--        put xs
--        return $ Just x
--   
popState :: Member (State [Int]) r => Eff r (Maybe Int) -- | run the popState effectful computation based on initial state. The -- result-type is the result of the computation Maybe Int -- together with the state at the end of the computation [Int] -- --
--   runPopState xs = run . runState xs $ popState
--   
-- --
--   >>> runPopState  [1, 2, 3]
--   (Just 1,[2,3])
--   
-- --
--   >>> runPopState []
--   (Nothing,[])
--   
runPopState :: [Int] -> (Maybe Int, [Int]) -- | an effect that returns a number one more than the given -- --
--   oneMore = do
--     x <- ask -- query the environment
--     return $ x + 1 -- add one to the asked value and return it
--   
oneMore :: Member (Reader Int) r => Eff r Int -- | Run the oneMore effectful function by giving it a value to -- read. -- --
--   runOneMore i = run . runReader i $ oneMore
--   
-- --
--   >>> runOneMore 1
--   2
--   
runOneMore :: Int -> Int -- | An effectful computation with multiple effects: -- -- -- -- All these effects are composed using the Eff monad using the -- corresponding Effect types. -- --
--   something = do
--     readValue :: Float <- ask -- read a value from the environment
--     when (readValue < 0) $ throwError readValue  -- if the value is negative, throw an error
--     modify (l -> (round readValue :: Integer) : l) -- add the rounded read element to the list
--     currentState :: [Integer] <- get -- get the state after the modification
--     return $ sum currentState -- sum the elements in the list and return that
--   
something :: (Member (Reader Float) r, Member (State [Integer]) r, Member (Exc Float) r) => Eff r Integer -- | Run the someting effectful computation given in the previous -- function. The handlers apply from bottom to top - so this is the -- reading direction. -- --
--   runSomething1 initialState newValue =
--     run . -- run the Eff-monad with no effects left
--     runError . -- run the error part of the effect. This introduces the Either in the result.
--     runState initialState . -- handle the state-effect providing an initial state giving back a pair.
--     runReader newValue $ -- provide the computation with the dynamic value to read/ask for
--     something -- the computation - function
--   
-- --
--   >>> runSomething1 [] (-0.5)
--   Left (-0.5)
--   
-- --
--   >>> runSomething1 [2] 1.3
--   Right (3,[1,2])
--   
runSomething1 :: [Integer] -> Float -> Either Float (Integer, [Integer]) -- | Run the something effectful computation given above. This has -- an alternative ordering of the effect-handlers. -- -- The used effect-handlers are the same are used in slightly different -- order: The runState and runError methods are -- swapped, which results in a different output type and run-semantics. -- --
--   runSomething1 initialState newValue =
--     run .
--     runState initialState .
--     runError .
--     runReader newValue $
--     something -- the computation - function
--   
-- --
--   >>> runSomething2 [4] (-2.4)
--   (Left (-2.4),[4])
--   
-- --
--   >>> runSomething2 [4] 5.9
--   (Right 10,[6,4])
--   
runSomething2 :: [Integer] -> Float -> (Either Float Integer, [Integer]) -- | Example usage of Control.Eff module Control.Eff.Example -- | The datatype for the example from the paper. See the tests for the -- example newtype TooBig TooBig :: Int -> TooBig -- | specialization to tell the type of the exception runErrBig :: Eff (Exc TooBig : r) a -> Eff r (Either TooBig a) -- | Multiple Reader effects sum2 :: ([Reader Int, Reader Float] <:: r) => Eff r Float -- | Write the elements of a list of numbers, in order. writeAll :: (Member (Writer a) e) => [a] -> Eff e () -- | Add a list of numbers to the current state. sumAll :: (Num a, Member (State a) e) => [a] -> Eff e () -- | Write a list of numbers and add them to the current state. writeAndAdd :: ([Writer a, State a] <:: e, Num a) => [a] -> Eff e () -- | Sum a list of numbers. sumEff :: (Num a) => [a] -> a -- | Safely get the last element of a list. Nothing for empty lists; Just -- the last element otherwise. lastEff :: [a] -> Maybe a -- | Get the last element and sum of a list lastAndSum :: (Num a) => [a] -> (Maybe a, a) data Move x [Move] :: Move () handUp :: Eff (Move : r) a -> Eff r a handDown :: Eff (Move : r) a -> Eff r a instance GHC.Show.Show Control.Eff.Example.TooBig instance GHC.Classes.Eq Control.Eff.Example.TooBig -- | Coroutines implemented with extensible effects module Control.Eff.Coroutine -- | Co-routines The interface is intentionally chosen to be the same as in -- transf.hs -- -- | The yield request: reporting a value of type e and suspending the -- coroutine. Resuming with the value of type b data Yield a b v [Yield] :: a -> Yield a b b -- | Yield a value of type a and suspend the coroutine. yield :: (Member (Yield a b) r) => a -> Eff r b -- | Launch a thread and report its status runC :: Eff (Yield a b : r) w -> Eff r (Y r a b) -- | Status of a thread: done or reporting the value of the type a (For -- simplicity, a co-routine reports a value but accepts unit) -- -- Type parameter r is the effect we're yielding from. -- -- Type parameter a is the type that is yielded. -- -- Type parameter w is the type of the value returned from the -- coroutine when it has completed. data Y r a w Y :: a -> (w -> Eff r (Y r a w)) -> Y r a w Done :: Y r a w -- | Nondeterministic choice effect module Control.Eff.Choose -- | Non-determinism (choice) -- -- choose lst non-deterministically chooses one value from the lst choose -- [] thus corresponds to failure Unlike Reader, Choose is not a GADT -- because the type of values returned in response to a (Choose a) -- request is just a, without any constraints. newtype Choose a Choose :: [a] -> Choose a -- | choose lst non-deterministically chooses one value from the lst choose -- [] thus corresponds to failure choose :: Member Choose r => [a] -> Eff r a -- | Run a nondeterministic effect, returning all values. makeChoice :: forall a r. Eff (Choose : r) a -> Eff r [a] -- | MonadPlus-like operators are expressible via choose mzero' :: Member Choose r => Eff r a -- | MonadPlus-like operators are expressible via choose mplus' :: Member Choose r => Eff r a -> Eff r a -> Eff r a instance (Control.Monad.Base.MonadBase m m, Data.OpenUnion.SetMember Control.Eff.Internal.Lift (Control.Eff.Internal.Lift m) r, Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff r)) => Control.Monad.Trans.Control.MonadBaseControl m (Control.Eff.Internal.Eff (Control.Eff.Choose.Choose : r)) instance Data.OpenUnion.Member Control.Eff.Choose.Choose r => GHC.Base.Alternative (Control.Eff.Internal.Eff r) instance Data.OpenUnion.Member Control.Eff.Choose.Choose r => GHC.Base.MonadPlus (Control.Eff.Internal.Eff r) -- | An example of non-trivial interaction of effects, handling of two -- effects together Non-determinism with control (cut) For the -- explanation of cut, see Section 5 of Hinze ICFP 2000 paper. Hinze -- suggests expressing cut in terms of cutfalse: -- --
--   = return () `mplus` cutfalse
--   where
--    cutfalse :: m a
--   
-- -- satisfies the following laws: -- --
--   cutfalse >>= k  = cutfalse              (F1)
--   cutfalse | m    = cutfalse              (F2)
--   
-- -- (note: m `mplus` cutfalse is different from -- cutfalse `mplus` m). In other words, cutfalse is the -- left zero of both bind and mplus. -- -- Hinze also introduces the operation call :: m a -> m -- a that delimits the effect of cut: call m -- executes m. If the cut is invoked in m, it discards only the choices -- made since m was called. Hinze postulates the axioms of call: -- --
--   call false = false                          (C1)
--   call (return a | m) = return a | call m     (C2)
--   call (m | cutfalse) = call m                (C3)
--   call (lift m >>= k) = lift m >>= (call . k) (C4)
--   
-- -- call m behaves like m except any cut inside -- m has only a local effect, he says. -- -- Hinze noted a problem with the "mechanical" derivation of backtracing -- monad transformer with cut: no axiom specifying the interaction of -- call with bind; no way to simplify nested invocations of call. -- -- We use exceptions for cutfalse Therefore, the law cutfalse -- >>= k = cutfalse is satisfied automatically since all -- exceptions have the above property. module Control.Eff.Cut data CutFalse CutFalse :: CutFalse cutfalse :: Member (Exc CutFalse) r => Eff r a -- | The interpreter -- it is like reify . reflect with a twist. Compare -- this implementation with the huge implementation of call in Hinze 2000 -- (Figure 9). Each clause corresponds to the axiom of call or cutfalse. -- All axioms are covered. -- -- The code clearly expresses the intuition that call watches the choice -- points of its argument computation. When it encounteres a cutfalse -- request, it discards the remaining choicepoints. It completely handles -- CutFalse effects but not non-determinism call :: forall a r. Member Choose r => Eff (Exc CutFalse : r) a -> Eff r a