-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Fast and concise extensible effects -- -- Please see the README on GitHub at -- https://github.com/re-xyr/cleff#readme @package cleff @version 0.3.2.0 -- | This module contains common definitions for the cleff -- internals. -- -- This is an internal module and its API may change even -- between minor versions. Therefore you should be extra careful if -- you're to depend on this module. module Cleff.Internal -- | The type of effects. An effect e m a takes an effect monad -- type m :: Type -> Type and a result type -- a :: Type. type Effect = (Type -> Type) -> Type -> Type -- | A natural transformation from f to g. With this, -- instead of writing -- --
-- runSomeEffect :: Eff (SomeEffect : es) a -> Eff es a ---- -- you can write: -- --
-- runSomeEffect :: Eff (SomeEffect : es) ~> Eff es --type f ~> g = forall a. f a -> g a -- | Type level list concatenation. type family xs ++ ys infixr 5 ++ -- | The type constructor Any is type to which you can unsafely -- coerce any lifted type, and back. More concretely, for a lifted type -- t and value x :: t, -- unsafeCoerce -- (unsafeCoerce x :: Any) :: t is equivalent to x. type family Any :: k -- | Coerce Any to a boxed value. This is generally unsafe -- and it is your responsibility to ensure that the type you're coercing -- into is the original type that the Any is coerced from. fromAny :: Any -> a -- | Coerce any boxed value into Any. toAny :: a -> Any -- | This module defines an immutable extensible record type, similar to -- vinyl and data-diverse. However this implementation -- focuses on fast reads, hence has very different performance -- characteristics from other libraries: -- --
-- (Reader String :> es, State Bool :> es) => Eff es Integer ---- -- means you can perform operations of the Reader -- String effect and the State Bool -- effect in a computation returning an Integer. The reason why -- you should always use a polymorphic effect stack as opposed to a -- concrete list of effects are that -- --
-- send = sendVia id --sendVia :: e :> es' => (Eff es ~> Eff es') -> e (Eff es) ~> Eff es' instance GHC.Base.Functor (Cleff.Internal.Monad.Eff es) instance GHC.Base.Applicative (Cleff.Internal.Monad.Eff es) instance GHC.Base.Monad (Cleff.Internal.Monad.Eff es) instance Control.Monad.Fix.MonadFix (Cleff.Internal.Monad.Eff es) -- | This module contains lifted instances of some typeclasses for -- Eff for convenience. They are all exported in the Cleff -- module so you shouldn't need to import this module. -- -- This is an internal module and its API may change even -- between minor versions. Therefore you should be extra careful if -- you're to depend on this module. module Cleff.Internal.Instances instance GHC.Enum.Bounded a => GHC.Enum.Bounded (Cleff.Internal.Monad.Eff es a) instance GHC.Base.Semigroup a => GHC.Base.Semigroup (Cleff.Internal.Monad.Eff es a) instance GHC.Base.Monoid a => GHC.Base.Monoid (Cleff.Internal.Monad.Eff es a) instance GHC.Num.Num a => GHC.Num.Num (Cleff.Internal.Monad.Eff es a) instance GHC.Real.Fractional a => GHC.Real.Fractional (Cleff.Internal.Monad.Eff es a) instance GHC.Float.Floating a => GHC.Float.Floating (Cleff.Internal.Monad.Eff es a) instance Data.String.IsString a => Data.String.IsString (Cleff.Internal.Monad.Eff es a) instance Control.Monad.Zip.MonadZip (Cleff.Internal.Monad.Eff es) -- | This module contains functions for interpreting effects. Most of the -- times you won't need to import this directly; the module Cleff -- reexports most of the functionalities. -- -- This is an internal module and its API may change even -- between minor versions. Therefore you should be extra careful if -- you're to depend on this module. module Cleff.Internal.Interpret -- | Adjust the effect stack by a contravariant transformation function -- over the stack. This function reveals the profunctorial nature of -- Eff; in particular, Eff is a profunctor -- [Effect] -> Type, lmap is -- adjust, and rmap is fmap. adjust :: forall es es'. (Rec es' -> Rec es) -> Eff es ~> Eff es' -- | Lift a computation into a bigger effect stack with one more effect. -- For a more general version see raiseN. raise :: forall e es. Eff es ~> Eff (e : es) -- | Lift a computation into a bigger effect stack with arbitrarily more -- effects. This function requires TypeApplications. raiseN :: forall es' es. KnownList es' => Eff es ~> Eff (es' ++ es) -- | Lift a computation with a fixed, known effect stack into some superset -- of the stack. inject :: forall es' es. Subset es' es => Eff es' ~> Eff es -- | Eliminate a duplicate effect from the top of the effect stack. For a -- more general version see subsumeN. subsume :: forall e es. e :> es => Eff (e : es) ~> Eff es -- | Eliminate several duplicate effects from the top of the effect stack. -- This function requires TypeApplications. subsumeN :: forall es' es. Subset es' es => Eff (es' ++ es) ~> Eff es -- | Like raise, but adds the new effect under the top effect. This -- is useful for transforming an interpreter e' :> es => -- Eff (e : es) ~> Eff es into a -- reinterpreter Eff (e : es) ~> Eff (e' : -- es): -- --
-- myInterpreter :: Bar :> es => Eff (Foo : es) ~> Eff es -- myInterpreter = ... -- -- myReinterpreter :: Eff (Foo : es) ~> Eff (Bar : es) -- myReinterpreter = myInterpreter . raiseUnder ---- -- In other words, -- --
-- reinterpret h == interpret h . raiseUnder ---- -- However, note that this function is suited for transforming an -- existing interpreter into a reinterpreter; if you want to define a -- reinterpreter from scratch, you should still prefer -- reinterpret, which is both easier to use and more efficient. raiseUnder :: forall e' e es. Eff (e : es) ~> Eff (e : (e' : es)) -- | Like raiseUnder, but allows introducing multiple effects. This -- function requires TypeApplications. raiseNUnder :: forall es' e es. KnownList es' => Eff (e : es) ~> Eff (e : (es' ++ es)) -- | Like raiseUnder, but allows introducing the effect under -- multiple effects. This function requires TypeApplications. raiseUnderN :: forall e es' es. KnownList es' => Eff (es' ++ es) ~> Eff (es' ++ (e : es)) -- | A generalization of both raiseUnderN and raiseNUnder, -- allowing introducing multiple effects under multiple effects. This -- function requires TypeApplications and is subject to serious -- type ambiguity; you most likely will need to supply all three type -- variables explicitly. raiseNUnderN :: forall es'' es' es. (KnownList es', KnownList es'') => Eff (es' ++ es) ~> Eff (es' ++ (es'' ++ es)) -- | The typeclass that denotes a handler scope, handling effect e -- sent from the effect stack esSend in the effect stack -- es. -- -- You should not define instances for this typeclass whatsoever. class Handling esSend e es | esSend -> e es -- | Get the send-site Env. esSend :: Handling esSend e es => Env esSend -- | The type of an effect handler, which is a function that -- transforms an effect e from an arbitrary effect stack into -- computations in the effect stack es. type Handler e es = forall esSend. Handling esSend e es => e (Eff esSend) ~> Eff es -- | The type of a simple transformation function from effect e to -- e'. type Translator e e' = forall esSend. e (Eff esSend) ~> e' (Eff esSend) -- | Interpret an effect e in terms of effects in the effect stack -- es with an effect handler. interpret :: forall e es. Handler e es -> Eff (e : es) ~> Eff es -- | Like interpret, but adds a new effect e' to the stack -- that can be used in the handler. reinterpret :: forall e' e es. Handler e (e' : es) -> Eff (e : es) ~> Eff (e' : es) -- | Like reinterpret, but adds two new effects. reinterpret2 :: forall e' e'' e es. Handler e (e' : (e'' : es)) -> Eff (e : es) ~> Eff (e' : (e'' : es)) -- | Like reinterpret, but adds three new effects. reinterpret3 :: forall e' e'' e''' e es. Handler e (e' : (e'' : (e''' : es))) -> Eff (e : es) ~> Eff (e' : (e'' : (e''' : es))) -- | Like reinterpret, but adds arbitrarily many new effects. This -- function requires TypeApplications. reinterpretN :: forall es' e es. KnownList es' => Handler e (es' ++ es) -> Eff (e : es) ~> Eff (es' ++ es) -- | Respond to an effect, but does not eliminate it from the stack. This -- means you can re-send the operations in the effect handler; it is -- often useful when you need to "intercept" operations so you can add -- extra behaviors like logging. interpose :: forall e es. e :> es => Handler e es -> Eff es ~> Eff es -- | Like interpose, but allows to introduce one new effect to use -- in the handler. impose :: forall e' e es. e :> es => Handler e (e' : es) -> Eff es ~> Eff (e' : es) -- | Like impose, but allows introducing arbitrarily many effects. -- This requires TypeApplications. imposeN :: forall es' e es. (KnownList es', e :> es) => Handler e (es' ++ es) -> Eff es ~> Eff (es' ++ es) -- | Interpret an effect in terms of another effect in the stack via a -- simple Translator. -- --
-- transform trans = interpret (sendVia toEff . trans) --transform :: forall e e' es. e' :> es => Translator e e' -> Eff (e : es) ~> Eff es -- | Like transform, but instead of using an effect in stack, add a -- new one to the top of it. -- --
-- translate trans = reinterpret (sendVia toEff . trans) --translate :: forall e e' es. Translator e e' -> Eff (e : es) ~> Eff (e' : es) -- | Run a computation in the current effect stack; this is useful for -- interpreting higher-order effects. For example, if you want to -- interpret a bracketing effects in terms of IO: -- --
-- data Resource m a where -- Bracket :: m a -> (a -> m ()) -> (a -> m b) -> Resource m b ---- -- You will not be able to simply write this for the effect: -- --
-- runBracket :: IOE :> es => Eff (Resource : es) a -> Eff es a -- runBracket = interpret \case -- Bracket alloc dealloc use -> UnliftIO.bracket alloc dealloc use ---- -- This is because effects are sended from all kinds of stacks that has -- Resource in it, so effect handlers received the effect as -- Resource esSend a, where esSend is an arbitrary -- stack with Resource, instead of Resource es a. This -- means alloc, dealloc and use are of type -- Eff esSend a, while bracket can only take and -- return Eff es a. So we need to use toEff, which -- converts an Eff esSend a into an Eff es -- a: -- --
-- runBracket :: IOE :> es => Eff (Resource : es) a -> Eff es a -- runBracket = interpret \case -- Bracket alloc dealloc use -> UnliftIO.bracket -- (toEff alloc) -- (toEff . dealloc) -- (toEff . use) --toEff :: Handling esSend e es => Eff esSend ~> Eff es -- | Run a computation in the current effect stack, just like toEff, -- but takes a Handler of the current effect being interpreted, so -- that inside the computation being ran, the effect is interpreted -- differently. This is useful for interpreting effects with local -- contexts, like Local: -- --
-- runReader :: r -> Eff (Reader r : es) ~> Eff es -- runReader x = interpret (handle x) -- where -- handle :: r -> Handler (Reader r) es -- handle r = \case -- Ask -> pure r -- Local f m -> toEffWith (handle $ f r) m --toEffWith :: forall esSend e es. Handling esSend e es => Handler e es -> Eff esSend ~> Eff es -- | Temporarily gain the ability to lift some Eff es -- actions into Eff esSend. This is only useful for -- dealing with effect operations with the monad type in the negative -- position, which means it's unlikely that you need to use this function -- in implementing your effects. withFromEff :: Handling esSend e es => ((Eff es ~> Eff esSend) -> Eff esSend a) -> Eff es a -- | This module contains the IOE effect together with a few -- primitives for using it, as well as interpretation combinators for -- IO-related effects. It is not usually needed because safe -- functionalities are re-exported in the Cleff module. -- -- This is an internal module and its API may change even -- between minor versions. Therefore you should be extra careful if -- you're to depend on this module. module Cleff.Internal.Base -- | The effect capable of lifting and unlifting the IO monad, -- allowing you to use MonadIO, MonadUnliftIO, -- PrimMonad, MonadCatch, MonadThrow and -- MonadMask functionalities. This is the "final" effect that most -- effects eventually are interpreted into. For example, you can do: -- --
-- log :: IOE :> es => Eff es () -- log = liftIO (putStrLn "Test logging") ---- -- It is not recommended to use this effect directly in application code, -- as it is too liberal and allows arbitrary IO, therefore making it -- harder to do proper effect management. Ideally, this is only used in -- interpreting more fine-grained effects. -- --
-- interpretIO f = interpret (liftIO . f) --interpretIO :: IOE :> es => HandlerIO e es -> Eff (e : es) ~> Eff es -- | Temporarily gain the ability to unlift an Eff esSend -- computation into IO. This is analogous to withRunInIO, -- and is useful in dealing with higher-order effects that involves -- IO. For example, the Resource effect that supports -- bracketing: -- --
-- data Resource m a where -- Bracket :: m a -> (a -> m ()) -> (a -> m b) -> Resource m b ---- -- can be interpreted into bracket actions in IO, by -- converting all effect computations into IO computations via -- withToIO: -- --
-- runResource :: IOE :> es => Eff (Resource : es) a -> Eff es a -- runResource = interpret \case -- Bracket alloc dealloc use -> withToIO $ \toIO -> -- bracket (toIO alloc) (toIO . dealloc) (toIO . use) --withToIO :: (Handling esSend e es, IOE :> es) => ((Eff esSend ~> IO) -> IO a) -> Eff es a -- | Lift an IO computation into Eff esSend. This is -- analogous to liftIO, and is only useful in dealing with effect -- operations with the monad type in the negative position, for example -- masking: -- --
-- data Mask :: Effect where -- Mask :: ((m ~> m) -> m a) -> Mask m a -- ^ this "m" is in negative position ---- -- See how the restore :: IO a -> IO a from mask is -- "wrapped" into Eff esSend a -> Eff esSend a: -- --
-- runMask :: IOE :> es => Eff (Mask : es) a -> Eff es a -- runMask = interpret \case -- Mask f -> withToIO $ \toIO -> mask $ -- \restore -> f (fromIO . restore . toIO) ---- -- Here, toIO from withToIO takes an Eff -- esSend to IO, where it can be passed into the -- restore function, and the returned IO computation is -- recovered into Eff with fromIO. fromIO :: (Handling esSend e es, IOE :> es) => IO ~> Eff esSend instance (Cleff.Internal.Base.IOE Cleff.Internal.Rec.:> es) => Control.Monad.IO.Class.MonadIO (Cleff.Internal.Monad.Eff es) instance (Cleff.Internal.Base.IOE Cleff.Internal.Rec.:> es) => Control.Monad.IO.Unlift.MonadUnliftIO (Cleff.Internal.Monad.Eff es) instance (Cleff.Internal.Base.IOE Cleff.Internal.Rec.:> es) => Control.Monad.Catch.MonadThrow (Cleff.Internal.Monad.Eff es) instance (Cleff.Internal.Base.IOE Cleff.Internal.Rec.:> es) => Control.Monad.Catch.MonadCatch (Cleff.Internal.Monad.Eff es) instance (Cleff.Internal.Base.IOE Cleff.Internal.Rec.:> es) => Control.Monad.Catch.MonadMask (Cleff.Internal.Monad.Eff es) instance (Cleff.Internal.Base.IOE Cleff.Internal.Rec.:> es) => Control.Monad.Base.MonadBase GHC.Types.IO (Cleff.Internal.Monad.Eff es) instance (Cleff.Internal.Base.IOE Cleff.Internal.Rec.:> es) => Control.Monad.Trans.Control.MonadBaseControl GHC.Types.IO (Cleff.Internal.Monad.Eff es) instance (Cleff.Internal.Base.IOE Cleff.Internal.Rec.:> es) => Control.Monad.Primitive.PrimMonad (Cleff.Internal.Monad.Eff es) -- | This module contains Template Haskell functions for generating -- definitions of functions that send effect operations. You mostly won't -- want to import this module directly; The Cleff module reexports -- the main functionalities of this module. -- -- This is an internal module and its API may change even -- between minor versions. Therefore you should be extra careful if -- you're to depend on this module. module Cleff.Internal.TH -- | For a datatype T representing an effect, -- makeEffect T generates function defintions for -- performing the operations of T via send. For example, -- --
-- makeEffect ''Filesystem ---- -- generates the following definitions: -- --
-- readFile :: Filesystem :> es => FilePath -> Eff es String -- readFile x = send (ReadFile x) -- writeFile :: Filesystem :> es => FilePath -> String -> Eff es () -- writeFile x y = send (WriteFile x y) ---- -- The naming rule is changing the first uppercase letter in the -- constructor name to lowercase or removing the : symbol in the -- case of operator constructors. Also, this function will preserve any -- fixity declarations defined on the constructors. -- --
-- data Identity :: Effect where -- Noop :: Identity m () -- makeEffect_ ''Identity -- -- -- | Perform nothing at all. -- noop :: Identity :> es => Eff es () ---- -- Be careful that the function signatures must be added after the -- makeEffect_ call. makeEffect_ :: Name -> Q [Dec] -- | This library implements an extensible effects system, where -- sets of monadic actions ("effects") are encoded as datatypes, tracked -- at the type level and can have multiple different implementations. -- This means you can swap out implementations of certain monadic actions -- in mock tests or in different environments. The notion of "effect" is -- general here: it can be an IO-performing side effect, or just -- reading the value of a static global environment. -- -- In particular, this library consists of -- --
-- (Reader String :> es, State Bool :> es) => Eff es Integer ---- -- means you can perform operations of the Reader -- String effect and the State Bool -- effect in a computation returning an Integer. The reason why -- you should always use a polymorphic effect stack as opposed to a -- concrete list of effects are that -- --
-- log :: IOE :> es => Eff es () -- log = liftIO (putStrLn "Test logging") ---- -- It is not recommended to use this effect directly in application code, -- as it is too liberal and allows arbitrary IO, therefore making it -- harder to do proper effect management. Ideally, this is only used in -- interpreting more fine-grained effects. -- --
-- send = sendVia id --sendVia :: e :> es' => (Eff es ~> Eff es') -> e (Eff es) ~> Eff es' -- | For a datatype T representing an effect, -- makeEffect T generates function defintions for -- performing the operations of T via send. For example, -- --
-- makeEffect ''Filesystem ---- -- generates the following definitions: -- --
-- readFile :: Filesystem :> es => FilePath -> Eff es String -- readFile x = send (ReadFile x) -- writeFile :: Filesystem :> es => FilePath -> String -> Eff es () -- writeFile x y = send (WriteFile x y) ---- -- The naming rule is changing the first uppercase letter in the -- constructor name to lowercase or removing the : symbol in the -- case of operator constructors. Also, this function will preserve any -- fixity declarations defined on the constructors. -- --
-- data Identity :: Effect where -- Noop :: Identity m () -- makeEffect_ ''Identity -- -- -- | Perform nothing at all. -- noop :: Identity :> es => Eff es () ---- -- Be careful that the function signatures must be added after the -- makeEffect_ call. makeEffect_ :: Name -> Q [Dec] -- | Lift a computation into a bigger effect stack with one more effect. -- For a more general version see raiseN. raise :: forall e es. Eff es ~> Eff (e : es) -- | Lift a computation into a bigger effect stack with arbitrarily more -- effects. This function requires TypeApplications. raiseN :: forall es' es. KnownList es' => Eff es ~> Eff (es' ++ es) -- | Lift a computation with a fixed, known effect stack into some superset -- of the stack. inject :: forall es' es. Subset es' es => Eff es' ~> Eff es -- | Eliminate a duplicate effect from the top of the effect stack. For a -- more general version see subsumeN. subsume :: forall e es. e :> es => Eff (e : es) ~> Eff es -- | Eliminate several duplicate effects from the top of the effect stack. -- This function requires TypeApplications. subsumeN :: forall es' es. Subset es' es => Eff (es' ++ es) ~> Eff es -- | KnownList es means the list es is concrete, -- i.e. is of the form '[a1, a2, ..., an] instead of a -- type variable. class KnownList (es :: [Effect]) -- | es is a subset of es', i.e. all elements of -- es are in es'. class KnownList es => Subset (es :: [Effect]) (es' :: [Effect]) -- | The type of an effect handler, which is a function that -- transforms an effect e from an arbitrary effect stack into -- computations in the effect stack es. type Handler e es = forall esSend. Handling esSend e es => e (Eff esSend) ~> Eff es -- | Interpret an effect e in terms of effects in the effect stack -- es with an effect handler. interpret :: forall e es. Handler e es -> Eff (e : es) ~> Eff es -- | Like interpret, but adds a new effect e' to the stack -- that can be used in the handler. reinterpret :: forall e' e es. Handler e (e' : es) -> Eff (e : es) ~> Eff (e' : es) -- | Like reinterpret, but adds two new effects. reinterpret2 :: forall e' e'' e es. Handler e (e' : (e'' : es)) -> Eff (e : es) ~> Eff (e' : (e'' : es)) -- | Like reinterpret, but adds three new effects. reinterpret3 :: forall e' e'' e''' e es. Handler e (e' : (e'' : (e''' : es))) -> Eff (e : es) ~> Eff (e' : (e'' : (e''' : es))) -- | Like reinterpret, but adds arbitrarily many new effects. This -- function requires TypeApplications. reinterpretN :: forall es' e es. KnownList es' => Handler e (es' ++ es) -> Eff (e : es) ~> Eff (es' ++ es) -- | Respond to an effect, but does not eliminate it from the stack. This -- means you can re-send the operations in the effect handler; it is -- often useful when you need to "intercept" operations so you can add -- extra behaviors like logging. interpose :: forall e es. e :> es => Handler e es -> Eff es ~> Eff es -- | Like interpose, but allows to introduce one new effect to use -- in the handler. impose :: forall e' e es. e :> es => Handler e (e' : es) -> Eff es ~> Eff (e' : es) -- | Like impose, but allows introducing arbitrarily many effects. -- This requires TypeApplications. imposeN :: forall es' e es. (KnownList es', e :> es) => Handler e (es' ++ es) -> Eff es ~> Eff (es' ++ es) -- | The type of an IO effect handler, which is a function -- that transforms an effect e into IO computations. This -- is used for interpretIO. type HandlerIO e es = forall esSend. Handling esSend e es => e (Eff esSend) ~> IO -- | Interpret an effect in terms of IO, by transforming an effect -- into IO computations. -- --
-- interpretIO f = interpret (liftIO . f) --interpretIO :: IOE :> es => HandlerIO e es -> Eff (e : es) ~> Eff es -- | The type of a simple transformation function from effect e to -- e'. type Translator e e' = forall esSend. e (Eff esSend) ~> e' (Eff esSend) -- | Interpret an effect in terms of another effect in the stack via a -- simple Translator. -- --
-- transform trans = interpret (sendVia toEff . trans) --transform :: forall e e' es. e' :> es => Translator e e' -> Eff (e : es) ~> Eff es -- | Like transform, but instead of using an effect in stack, add a -- new one to the top of it. -- --
-- translate trans = reinterpret (sendVia toEff . trans) --translate :: forall e e' es. Translator e e' -> Eff (e : es) ~> Eff (e' : es) -- | Like raise, but adds the new effect under the top effect. This -- is useful for transforming an interpreter e' :> es => -- Eff (e : es) ~> Eff es into a -- reinterpreter Eff (e : es) ~> Eff (e' : -- es): -- --
-- myInterpreter :: Bar :> es => Eff (Foo : es) ~> Eff es -- myInterpreter = ... -- -- myReinterpreter :: Eff (Foo : es) ~> Eff (Bar : es) -- myReinterpreter = myInterpreter . raiseUnder ---- -- In other words, -- --
-- reinterpret h == interpret h . raiseUnder ---- -- However, note that this function is suited for transforming an -- existing interpreter into a reinterpreter; if you want to define a -- reinterpreter from scratch, you should still prefer -- reinterpret, which is both easier to use and more efficient. raiseUnder :: forall e' e es. Eff (e : es) ~> Eff (e : (e' : es)) -- | Like raiseUnder, but allows introducing multiple effects. This -- function requires TypeApplications. raiseNUnder :: forall es' e es. KnownList es' => Eff (e : es) ~> Eff (e : (es' ++ es)) -- | Like raiseUnder, but allows introducing the effect under -- multiple effects. This function requires TypeApplications. raiseUnderN :: forall e es' es. KnownList es' => Eff (es' ++ es) ~> Eff (es' ++ (e : es)) -- | A generalization of both raiseUnderN and raiseNUnder, -- allowing introducing multiple effects under multiple effects. This -- function requires TypeApplications and is subject to serious -- type ambiguity; you most likely will need to supply all three type -- variables explicitly. raiseNUnderN :: forall es'' es' es. (KnownList es', KnownList es'') => Eff (es' ++ es) ~> Eff (es' ++ (es'' ++ es)) -- | The typeclass that denotes a handler scope, handling effect e -- sent from the effect stack esSend in the effect stack -- es. -- -- You should not define instances for this typeclass whatsoever. class Handling esSend e es | esSend -> e es -- | Run a computation in the current effect stack; this is useful for -- interpreting higher-order effects. For example, if you want to -- interpret a bracketing effects in terms of IO: -- --
-- data Resource m a where -- Bracket :: m a -> (a -> m ()) -> (a -> m b) -> Resource m b ---- -- You will not be able to simply write this for the effect: -- --
-- runBracket :: IOE :> es => Eff (Resource : es) a -> Eff es a -- runBracket = interpret \case -- Bracket alloc dealloc use -> UnliftIO.bracket alloc dealloc use ---- -- This is because effects are sended from all kinds of stacks that has -- Resource in it, so effect handlers received the effect as -- Resource esSend a, where esSend is an arbitrary -- stack with Resource, instead of Resource es a. This -- means alloc, dealloc and use are of type -- Eff esSend a, while bracket can only take and -- return Eff es a. So we need to use toEff, which -- converts an Eff esSend a into an Eff es -- a: -- --
-- runBracket :: IOE :> es => Eff (Resource : es) a -> Eff es a -- runBracket = interpret \case -- Bracket alloc dealloc use -> UnliftIO.bracket -- (toEff alloc) -- (toEff . dealloc) -- (toEff . use) --toEff :: Handling esSend e es => Eff esSend ~> Eff es -- | Run a computation in the current effect stack, just like toEff, -- but takes a Handler of the current effect being interpreted, so -- that inside the computation being ran, the effect is interpreted -- differently. This is useful for interpreting effects with local -- contexts, like Local: -- --
-- runReader :: r -> Eff (Reader r : es) ~> Eff es -- runReader x = interpret (handle x) -- where -- handle :: r -> Handler (Reader r) es -- handle r = \case -- Ask -> pure r -- Local f m -> toEffWith (handle $ f r) m --toEffWith :: forall esSend e es. Handling esSend e es => Handler e es -> Eff esSend ~> Eff es -- | Temporarily gain the ability to lift some Eff es -- actions into Eff esSend. This is only useful for -- dealing with effect operations with the monad type in the negative -- position, which means it's unlikely that you need to use this function -- in implementing your effects. withFromEff :: Handling esSend e es => ((Eff es ~> Eff esSend) -> Eff esSend a) -> Eff es a -- | Temporarily gain the ability to unlift an Eff esSend -- computation into IO. This is analogous to withRunInIO, -- and is useful in dealing with higher-order effects that involves -- IO. For example, the Resource effect that supports -- bracketing: -- --
-- data Resource m a where -- Bracket :: m a -> (a -> m ()) -> (a -> m b) -> Resource m b ---- -- can be interpreted into bracket actions in IO, by -- converting all effect computations into IO computations via -- withToIO: -- --
-- runResource :: IOE :> es => Eff (Resource : es) a -> Eff es a -- runResource = interpret \case -- Bracket alloc dealloc use -> withToIO $ \toIO -> -- bracket (toIO alloc) (toIO . dealloc) (toIO . use) --withToIO :: (Handling esSend e es, IOE :> es) => ((Eff esSend ~> IO) -> IO a) -> Eff es a -- | Lift an IO computation into Eff esSend. This is -- analogous to liftIO, and is only useful in dealing with effect -- operations with the monad type in the negative position, for example -- masking: -- --
-- data Mask :: Effect where -- Mask :: ((m ~> m) -> m a) -> Mask m a -- ^ this "m" is in negative position ---- -- See how the restore :: IO a -> IO a from mask is -- "wrapped" into Eff esSend a -> Eff esSend a: -- --
-- runMask :: IOE :> es => Eff (Mask : es) a -> Eff es a -- runMask = interpret \case -- Mask f -> withToIO $ \toIO -> mask $ -- \restore -> f (fromIO . restore . toIO) ---- -- Here, toIO from withToIO takes an Eff -- esSend to IO, where it can be passed into the -- restore function, and the returned IO computation is -- recovered into Eff with fromIO. fromIO :: (Handling esSend e es, IOE :> es) => IO ~> Eff esSend -- | A natural transformation from f to g. With this, -- instead of writing -- --
-- runSomeEffect :: Eff (SomeEffect : es) a -> Eff es a ---- -- you can write: -- --
-- runSomeEffect :: Eff (SomeEffect : es) ~> Eff es --type f ~> g = forall a. f a -> g a -- | Type level list concatenation. type family xs ++ ys infixr 5 ++ -- | 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: -- -- class Monad m => MonadIO (m :: Type -> Type) -- | Lift a computation from the IO monad. liftIO :: MonadIO m => IO a -> m a -- | Monads which allow their actions to be run in IO. -- -- While MonadIO allows an IO action to be lifted into -- another monad, this class captures the opposite concept: allowing you -- to capture the monadic context. Note that, in order to meet the laws -- given below, the intuition is that a monad must have no monadic state, -- but may have monadic context. This essentially limits -- MonadUnliftIO to ReaderT and IdentityT -- transformers on top of IO. -- -- Laws. For any value u returned by askUnliftIO, it must -- meet the monad transformer laws as reformulated for -- MonadUnliftIO: -- --
unliftIO u . return = return
unliftIO u (m >>= f) = unliftIO u m >>= unliftIO -- u . f
askUnliftIO >>= \u -> (liftIO . unliftIO u) m = -- m
-- concurrently_ -- (listen $ tell "1" >> tell "2" >> tell "3") -- (listen $ tell "4" >> tell "5" >> tell "6") ---- -- will produce either "123456" or "456123" with -- runWriterBatch, but may produce these digits in any order with -- runWriter. -- -- This version of interpreter can be faster than runWriter in -- listen-intense code. It is subject to all caveats of -- runWriter. runWriterBatch :: forall w es a. Monoid w => Eff (Writer w : es) a -> Eff es (a, w) module Cleff.Output -- | An effect that is capable of producing outputs, for example writing to -- a log file or an output stream. data Output o :: Effect [Output] :: o -> Output o m () -- | Produce an output value. output :: Output o :> es => o -> Eff es () -- | Run an Output effect by accumulating a list. Note that outputs -- are being prepended to the head of the list, so in many cases you -- would want to reverse the result. outputToListState :: Eff (Output o : es) ~> Eff (State [o] : es) -- | Run an Output effect by translating it into a Writer. outputToWriter :: (o -> o') -> Eff (Output o : es) ~> Eff (Writer o' : es) -- | Ignore outputs of an Output effect altogether. ignoreOutput :: Eff (Output o : es) ~> Eff es -- | Run an Output effect by performing a computation for each -- output. runOutputEff :: (o -> Eff es ()) -> Eff (Output o : es) ~> Eff es -- | Transform an Output effect into another one already in the -- effect stack, by a pure function. mapOutput :: Output o' :> es => (o -> o') -> Eff (Output o : es) ~> Eff es -- | Transform an Output effect into another one already in the -- effect stack, by an effectful computation. bindOutput :: Output o' :> es => (o -> Eff es o') -> Eff (Output o : es) ~> Eff es module Cleff.Trace -- | An effect capable of logging messages, mostly for debugging purposes. data Trace :: Effect [Trace] :: String -> Trace m () -- | Output a trace message. trace :: Trace :> es => String -> Eff es () -- | Run the Trace effect by writing to a Handle. runTraceHandle :: IOE :> es => Handle -> Eff (Trace : es) a -> Eff es a -- | Run the Trace effect by writing to stdout. runTraceStdout :: IOE :> es => Eff (Trace : es) ~> Eff es -- | Run the Trace effect by writing to stderr. runTraceStderr :: IOE :> es => Eff (Trace : es) ~> Eff es -- | Run the Trace effect by ignoring all outputs altogether. ignoreTrace :: Eff (Trace : es) ~> Eff es -- | Transform the Trace effect into an Output -- String effect. traceToOutput :: Eff (Trace : es) ~> Eff (Output String : es)