-- 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. For more information, see the -- original paper at -- http://okmij.org/ftp/Haskell/extensible/exteff.pdf. Any help is -- appreciated! @package extensible-effects @version 2.5.1.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) 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) -- | 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 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 '[] -- | 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) 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) 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)) -- | 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 :: Eff (Reader e : r) w -> e -> 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' :: Eff (State s : r) w -> s -> Eff r (w, s) -- | Run a State effect runState :: Eff (State s : r) w -> s -> Eff r (w, 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 :: Eff (State s : r) w -> s -> Eff r w -- | Run a State effect and return the final state. execState :: Eff (State s : r) w -> s -> 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 w. Member (State s) r => TxState s -> Eff r w -> Eff r w -- | 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 :: Eff (Writer s : (Reader s : r)) w -> s -> Eff r (w, 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 :: Eff (Reader e : r) w -> e -> 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' :: Eff (OnDemandState s : r) w -> s -> Eff r (w, s) -- | Run a State effect runState :: Eff (OnDemandState s : r) w -> s -> 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 :: Eff (OnDemandState s : r) w -> s -> Eff r w -- | Run a State effect and return the final state. execState :: Eff (OnDemandState s : r) w -> s -> 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 :: Eff (Writer s : (Reader s : r)) w -> s -> 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 () runState' :: Eff (State s : r) w -> s -> Eff r (w, s) -- | Run a State effect runState :: Eff (State s : r) w -> s -> Eff r (w, 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 :: Eff (State s : r) w -> s -> Eff r w -- | Run a State effect and return the final state. execState :: Eff (State s : r) w -> s -> 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 w. Member (State s) r => TxState s -> Eff r w -> Eff r w -- | 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 :: Eff (Writer s : (Reader s : r)) w -> s -> Eff r (w, 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)) -- | 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)) -- | 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 -- | We make the Lift layer to be unique, using SetMember 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 -- | 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 -- | 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)) -- | 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) module Control.Eff -- | 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 -- | 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 -- | 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 :: Member (Reader Int) r => Member (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 :: (Member (Writer a) e, Member (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 -- | 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 -- | 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