-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | An easy to use, performant extensible effects library. -- -- An easy to use, performant extensible effects library with seamless -- integration with the existing Haskell ecosystem. . This library -- provides core definitions with a minimal dependency footprint. See the -- effectful package for the "batteries-included" -- variant. @package effectful-core @version 2.5.0.0 -- | Type-safe indexing for Env. -- -- This module is intended for internal use only, and may change without -- warning in subsequent releases. module Effectful.Internal.Effect -- | The kind of effects. type Effect = (Type -> Type) -> Type -> Type -- | A constraint that requires that a particular effect e is a -- member of the type-level list es. This is used to -- parameterize an Eff computation over an arbitrary list of -- effects, so long as e is somewhere in the list. -- -- For example, a computation that only needs access to a mutable value -- of type Integer would have the following type: -- --
-- State Integer :> es => Eff es () --class (e :: Effect) :> (es :: [Effect]) -- | Get the position of e in es. -- -- Note: GHC is kind enough to cache these values as they're top -- level CAFs, so the lookup is amortized O(1) without any -- language level tricks. reifyIndex :: (:>) e es => Int -- | Convenience operator for expressing that a function uses multiple -- effects in a more concise way than enumerating them all with -- (:>). -- --
-- [E1, E2, ..., En] :>> es ≡ (E1 :> es, E2 :> es, ..., En :> es) ---- | Deprecated: Usage of (:>>) slows down GHC too much. See -- https://github.com/haskell-effectful/effectful/issues/52#issuecomment-1269155485 -- for more information. type family xs :>> es :: Constraint -- | Provide evidence that subEs is a subset of es. class KnownPrefix es => Subset (subEs :: [Effect]) (es :: [Effect]) subsetFullyKnown :: Subset subEs es => Bool reifyIndices :: Subset subEs es => [Int] -- | Provide evidence that subEs is a known subset of es. class Subset subEs es => KnownSubset (subEs :: [Effect]) (es :: [Effect]) -- | Calculate length of a statically known prefix of es. class KnownPrefix (es :: [Effect]) prefixLength :: KnownPrefix es => Int -- | Require that subEs is the unknown suffix of es. class (subEs :: [Effect]) `IsUnknownSuffixOf` (es :: [Effect]) -- | Append two type-level lists together. type family (xs :: [Effect]) ++ (ys :: [Effect]) :: [Effect] infixr 5 ++ -- | Calculate length of a list of known effects. class KnownEffects (es :: [Effect]) knownEffectsLength :: KnownEffects es => Int -- | The kind of types with lifted values. For example Int :: -- Type. type Type = TYPE LiftedRep instance Effectful.Internal.Effect.KnownEffects es => Effectful.Internal.Effect.KnownEffects (e : es) instance Effectful.Internal.Effect.KnownEffects '[] instance (Effectful.Internal.Effect.KnownPrefix es, Effectful.Internal.Effect.IsUnknownSuffixOf subEs es) => Effectful.Internal.Effect.Subset subEs es instance (subEs GHC.Types.~ es) => Effectful.Internal.Effect.IsUnknownSuffixOf subEs es instance Effectful.Internal.Effect.IsUnknownSuffixOf subEs es => Effectful.Internal.Effect.IsUnknownSuffixOf subEs (e : es) instance Effectful.Internal.Effect.KnownSubset '[] es instance (e Effectful.Internal.Effect.:> es, Effectful.Internal.Effect.KnownSubset subEs es) => Effectful.Internal.Effect.KnownSubset (e : subEs) es instance Effectful.Internal.Effect.KnownPrefix es => Effectful.Internal.Effect.Subset '[] es instance (e Effectful.Internal.Effect.:> es, Effectful.Internal.Effect.Subset subEs es) => Effectful.Internal.Effect.Subset (e : subEs) es instance Effectful.Internal.Effect.KnownPrefix es => Effectful.Internal.Effect.KnownPrefix (e : es) instance Effectful.Internal.Effect.KnownPrefix es instance (TypeError ...) => e Effectful.Internal.Effect.:> '[] instance e Effectful.Internal.Effect.:> (e : es) instance (e Effectful.Internal.Effect.:> es) => e Effectful.Internal.Effect.:> (x : es) module Effectful.Internal.Utils -- | Version of bracket with an INLINE pragma to work around -- https://gitlab.haskell.org/ghc/ghc/-/issues/22824. inlineBracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c -- | Get an id of a thread that doesn't prevent its garbage collection. weakThreadId :: ThreadId -> Int eqThreadId :: ThreadId -> ThreadId -> Bool -- | 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 toAny :: a -> Any fromAny :: Any -> a -- | A unique with no possibility for CAS contention. -- -- Credits for this go to Edward Kmett. data Unique newUnique :: IO Unique thawCallStack :: CallStack -> CallStack instance GHC.Classes.Eq Effectful.Internal.Utils.Unique module Effectful.Internal.Env -- | A strict (WHNF), thread local, mutable, extensible record -- indexed by types of kind Effect. -- -- Warning: the environment is a mutable data structure and cannot be -- simultaneously used from multiple threads under any circumstances. -- -- In order to pass it to a different thread, you need to perform a deep -- copy with the cloneEnv funtion. -- -- Offers very good performance characteristics for most often performed -- operations: -- --
-- >>> import Effectful
--
-- >>> import Effectful.State.Dynamic
--
-- >>> :{
-- action :: (IOE :> es, State Int :> es) => Eff es ()
-- action = do
-- modify @Int (+1)
-- withEffToIO SeqForkUnlift $ \unlift -> unlift $ modify @Int (+2)
-- modify @Int (+4)
-- :}
--
--
-- -- >>> runEff . execStateLocal @Int 0 $ action -- 5 ---- --
-- >>> runEff . execStateShared @Int 0 $ action -- 7 ---- -- Because of this it's possible to safely use the unlifting function -- outside of the scope of effects it captures, e.g. by creating an -- IO action that executes effectful operations and running it -- later: -- --
-- >>> :{
-- delayed :: UnliftStrategy -> IO (IO String)
-- delayed strategy = runEff . evalStateLocal "Hey" $ do
-- r <- withEffToIO strategy $ \unlift -> pure $ unlift get
-- modify (++ "!!!")
-- pure r
-- :}
--
--
-- This doesn't work with the SeqUnlift strategy because when the
-- returned action runs, State is no longer in scope:
--
-- -- >>> join $ delayed SeqUnlift -- *** Exception: version (...) /= storageVersion (0) -- ... ---- -- However, it does with the SeqForkUnlift strategy: -- --
-- >>> join $ delayed SeqForkUnlift -- "Hey" --SeqForkUnlift :: UnliftStrategy -- | The concurrent strategy makes it possible for the unlifting function -- to be called in threads distinct from its creator. See -- Persistence and Limit settings for more information. ConcUnlift :: !Persistence -> !Limit -> UnliftStrategy -- | Persistence setting for the ConcUnlift strategy. -- -- Different functions require different persistence strategies. -- Examples: -- --
-- (Reader String :> es, State Bool :> es) => Eff es Integer ---- -- Abstracting over the list of effects with (:>): -- --
-- >>> data E1 :: Effect -- -- >>> data E2 :: Effect -- -- >>> data E3 :: Effect ---- -- It makes it possible to rearrange the effect stack however you like: -- --
-- >>> :{
-- shuffle :: Eff (E3 : E1 : E2 : es) a -> Eff (E1 : E2 : E3 : es) a
-- shuffle = inject
-- :}
--
--
-- It can also turn a monomorphic effect stack into a polymorphic one:
--
--
-- >>> :{
-- toPoly :: (E1 :> es, E2 :> es, E3 :> es) => Eff [E1, E2, E3] a -> Eff es a
-- toPoly = inject
-- :}
--
--
-- Moreover, it allows for hiding specific effects from downstream:
--
--
-- >>> :{
-- onlyE1 :: Eff (E1 : es) a -> Eff (E1 : E2 : E3 : es) a
-- onlyE1 = inject
-- :}
--
--
--
-- >>> :{
-- onlyE2 :: Eff (E2 : es) a -> Eff (E1 : E2 : E3 : es) a
-- onlyE2 = inject
-- :}
--
--
--
-- >>> :{
-- onlyE3 :: Eff (E3 : es) a -> Eff (E1 : E2 : E3 : es) a
-- onlyE3 = inject
-- :}
--
--
-- However, it's not possible to inject a computation into an
-- incompatible effect stack:
--
--
-- >>> :{
-- coerceEs :: Eff es1 a -> Eff es2 a
-- coerceEs = inject
-- :}
-- ...
-- ...Couldn't match type ‘es1’ with ‘es2’
-- ...
--
inject :: Subset subEs es => Eff subEs a -> Eff es a
-- | Provide evidence that subEs is a subset of es.
class KnownPrefix es => Subset (subEs :: [Effect]) (es :: [Effect])
-- | The strategy to use when unlifting Eff computations via
-- withEffToIO or the localUnlift family.
data UnliftStrategy
-- | The sequential strategy is the fastest and a default setting for
-- IOE. Any attempt of calling the unlifting function in threads
-- distinct from its creator will result in a runtime error.
SeqUnlift :: UnliftStrategy
-- | Like SeqUnlift, but all unlifted actions will be executed in a
-- cloned environment.
--
-- The main consequence is that thread local state is forked at the point
-- of creation of the unlifting function and its modifications in
-- unlifted actions will not affect the main thread of execution (and
-- vice versa):
--
--
-- >>> import Effectful
--
-- >>> import Effectful.State.Dynamic
--
-- >>> :{
-- action :: (IOE :> es, State Int :> es) => Eff es ()
-- action = do
-- modify @Int (+1)
-- withEffToIO SeqForkUnlift $ \unlift -> unlift $ modify @Int (+2)
-- modify @Int (+4)
-- :}
--
--
-- -- >>> runEff . execStateLocal @Int 0 $ action -- 5 ---- --
-- >>> runEff . execStateShared @Int 0 $ action -- 7 ---- -- Because of this it's possible to safely use the unlifting function -- outside of the scope of effects it captures, e.g. by creating an -- IO action that executes effectful operations and running it -- later: -- --
-- >>> :{
-- delayed :: UnliftStrategy -> IO (IO String)
-- delayed strategy = runEff . evalStateLocal "Hey" $ do
-- r <- withEffToIO strategy $ \unlift -> pure $ unlift get
-- modify (++ "!!!")
-- pure r
-- :}
--
--
-- This doesn't work with the SeqUnlift strategy because when the
-- returned action runs, State is no longer in scope:
--
-- -- >>> join $ delayed SeqUnlift -- *** Exception: version (...) /= storageVersion (0) -- ... ---- -- However, it does with the SeqForkUnlift strategy: -- --
-- >>> join $ delayed SeqForkUnlift -- "Hey" --SeqForkUnlift :: UnliftStrategy -- | The concurrent strategy makes it possible for the unlifting function -- to be called in threads distinct from its creator. See -- Persistence and Limit settings for more information. ConcUnlift :: !Persistence -> !Limit -> UnliftStrategy -- | Persistence setting for the ConcUnlift strategy. -- -- Different functions require different persistence strategies. -- Examples: -- --
-- IO a -> IO b ---- -- to -- --
-- Eff es a -> Eff es b ---- -- This function is really unsafe because: -- --
-- IO a -> IO b ---- -- to -- --
-- Eff es a -> Eff es b ---- -- Note: the computation must not run its argument in a separate -- thread, attempting to do so will result in a runtime error. -- -- This function is unsafe because it can be used to introduce -- arbitrary IO actions into pure Eff computations. unsafeLiftMapIO :: HasCallStack => (IO a -> IO b) -> Eff es a -> Eff es b -- | Request a CallStack. -- -- NOTE: The implicit parameter ?callStack :: CallStack is an -- implementation detail and should not be considered part of the -- CallStack API, we may decide to change the implementation in -- the future. type HasCallStack = ?callStack :: CallStack module Effectful -- | The Eff monad provides the implementation of a computation that -- performs an arbitrary set of effects. In Eff es a, -- es is a type-level list that contains all the effects that -- the computation may perform. For example, a computation that produces -- an Integer by consuming a String from the global -- environment and acting upon a single mutable value of type Bool -- would have the following type: -- --
-- (Reader String :> es, State Bool :> es) => Eff es Integer ---- -- Abstracting over the list of effects with (:>): -- --
-- State Integer :> es => Eff es () --class (e :: Effect) :> (es :: [Effect]) -- | Convenience operator for expressing that a function uses multiple -- effects in a more concise way than enumerating them all with -- (:>). -- --
-- [E1, E2, ..., En] :>> es ≡ (E1 :> es, E2 :> es, ..., En :> es) ---- | Deprecated: Usage of (:>>) slows down GHC too much. See -- https://github.com/haskell-effectful/effectful/issues/52#issuecomment-1269155485 -- for more information. type family xs :>> es :: Constraint -- | Run a pure Eff computation. -- -- For running computations with side effects see runEff. runPureEff :: HasCallStack => Eff '[] a -> a -- | Run an Eff computation with side effects. -- -- For running pure computations see runPureEff. runEff :: HasCallStack => Eff '[IOE] a -> IO a -- | Run arbitrary IO computations via MonadIO or -- MonadUnliftIO. -- -- Note: it is not recommended to use this effect in application -- code as it is too liberal. Ideally, this is only used in handlers of -- more fine-grained effects. data IOE :: Effect -- | The strategy to use when unlifting Eff computations via -- withEffToIO or the localUnlift family. data UnliftStrategy -- | The sequential strategy is the fastest and a default setting for -- IOE. Any attempt of calling the unlifting function in threads -- distinct from its creator will result in a runtime error. SeqUnlift :: UnliftStrategy -- | Like SeqUnlift, but all unlifted actions will be executed in a -- cloned environment. -- -- The main consequence is that thread local state is forked at the point -- of creation of the unlifting function and its modifications in -- unlifted actions will not affect the main thread of execution (and -- vice versa): -- --
-- >>> import Effectful
--
-- >>> import Effectful.State.Dynamic
--
-- >>> :{
-- action :: (IOE :> es, State Int :> es) => Eff es ()
-- action = do
-- modify @Int (+1)
-- withEffToIO SeqForkUnlift $ \unlift -> unlift $ modify @Int (+2)
-- modify @Int (+4)
-- :}
--
--
-- -- >>> runEff . execStateLocal @Int 0 $ action -- 5 ---- --
-- >>> runEff . execStateShared @Int 0 $ action -- 7 ---- -- Because of this it's possible to safely use the unlifting function -- outside of the scope of effects it captures, e.g. by creating an -- IO action that executes effectful operations and running it -- later: -- --
-- >>> :{
-- delayed :: UnliftStrategy -> IO (IO String)
-- delayed strategy = runEff . evalStateLocal "Hey" $ do
-- r <- withEffToIO strategy $ \unlift -> pure $ unlift get
-- modify (++ "!!!")
-- pure r
-- :}
--
--
-- This doesn't work with the SeqUnlift strategy because when the
-- returned action runs, State is no longer in scope:
--
-- -- >>> join $ delayed SeqUnlift -- *** Exception: version (...) /= storageVersion (0) -- ... ---- -- However, it does with the SeqForkUnlift strategy: -- --
-- >>> join $ delayed SeqForkUnlift -- "Hey" --SeqForkUnlift :: UnliftStrategy -- | The concurrent strategy makes it possible for the unlifting function -- to be called in threads distinct from its creator. See -- Persistence and Limit settings for more information. ConcUnlift :: !Persistence -> !Limit -> UnliftStrategy -- | Persistence setting for the ConcUnlift strategy. -- -- Different functions require different persistence strategies. -- Examples: -- --
-- >>> data E1 :: Effect -- -- >>> data E2 :: Effect -- -- >>> data E3 :: Effect ---- -- It makes it possible to rearrange the effect stack however you like: -- --
-- >>> :{
-- shuffle :: Eff (E3 : E1 : E2 : es) a -> Eff (E1 : E2 : E3 : es) a
-- shuffle = inject
-- :}
--
--
-- It can also turn a monomorphic effect stack into a polymorphic one:
--
--
-- >>> :{
-- toPoly :: (E1 :> es, E2 :> es, E3 :> es) => Eff [E1, E2, E3] a -> Eff es a
-- toPoly = inject
-- :}
--
--
-- Moreover, it allows for hiding specific effects from downstream:
--
--
-- >>> :{
-- onlyE1 :: Eff (E1 : es) a -> Eff (E1 : E2 : E3 : es) a
-- onlyE1 = inject
-- :}
--
--
--
-- >>> :{
-- onlyE2 :: Eff (E2 : es) a -> Eff (E1 : E2 : E3 : es) a
-- onlyE2 = inject
-- :}
--
--
--
-- >>> :{
-- onlyE3 :: Eff (E3 : es) a -> Eff (E1 : E2 : E3 : es) a
-- onlyE3 = inject
-- :}
--
--
-- However, it's not possible to inject a computation into an
-- incompatible effect stack:
--
--
-- >>> :{
-- coerceEs :: Eff es1 a -> Eff es2 a
-- coerceEs = inject
-- :}
-- ...
-- ...Couldn't match type ‘es1’ with ‘es2’
-- ...
--
inject :: Subset subEs es => Eff subEs a -> Eff es a
-- | Provide evidence that subEs is a subset of es.
class KnownPrefix es => Subset (subEs :: [Effect]) (es :: [Effect])
-- | 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. This allows us to run IO
-- computations in any monadic stack, so long as it supports these kinds
-- of operations (i.e. IO is the base monad for the stack).
--
-- -- import Control.Monad.Trans.State -- from the "transformers" library -- -- printState :: Show s => StateT s IO () -- printState = do -- state <- get -- liftIO $ print state ---- -- Had we omitted liftIO, we would have ended up with -- this error: -- --
-- • Couldn't match type ‘IO’ with ‘StateT s IO’ -- Expected type: StateT s IO () -- Actual type: IO () ---- -- The important part here is the mismatch between StateT s IO -- () and IO (). -- -- Luckily, we know of a function that takes an IO a and -- returns an (m a): liftIO, enabling us to run -- the program and see the expected results: -- --
-- > evalStateT printState "hello" -- "hello" -- -- > evalStateT printState 3 -- 3 --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 function run provided by withRunInIO, it -- must meet the monad transformer laws as reformulated for -- MonadUnliftIO: -- --
run . return = return
run (m >>= f) = run m >>= run . f
-- withRunInIO inner = -- StateT $ \s -> -- withRunInIO $ \run -> -- inner (run . flip evalStateT s) ---- -- This breaks the identity law because the inner run m would -- throw away any state changes in m. class MonadIO m => MonadUnliftIO (m :: Type -> Type) -- | Convenience function for capturing the monadic context and running an -- IO action with a runner function. The runner function is used -- to run a monadic action m in IO. withRunInIO :: MonadUnliftIO m => ((forall a. () => m a -> IO a) -> IO b) -> m b -- | Support for runtime exceptions. -- -- This module supplies thin wrappers over functions from -- Control.Exception as well as several utility functions for -- convenience. -- -- Note: the Eff monad provides instances for -- MonadThrow, MonadCatch and MonadMask, so any -- existing code that uses them remains compatible. module Effectful.Exception -- | Lifted throwIO. throwIO :: (HasCallStack, Exception e) => e -> Eff es a -- | Lifted catch. catch :: Exception e => Eff es a -> (e -> Eff es a) -> Eff es a -- | A variant of catch that fully forces evaluation of the result -- value to find all impure exceptions. catchDeep :: (Exception e, NFData a) => Eff es a -> (e -> Eff es a) -> Eff es a -- | Lifted catchJust. catchJust :: Exception e => (e -> Maybe b) -> Eff es a -> (b -> Eff es a) -> Eff es a -- | Catch an exception only if it satisfies a specific predicate. catchIf :: Exception e => (e -> Bool) -> Eff es a -> (e -> Eff es a) -> Eff es a -- | catch specialized to catch IOException. catchIO :: Eff es a -> (IOException -> Eff es a) -> Eff es a -- | catch specialized to catch all exceptions considered to be -- synchronous. -- --
-- catchSync ≡ catchIf @SomeException isSyncException ---- -- See the check exception type section for more information. catchSync :: Eff es a -> (SomeException -> Eff es a) -> Eff es a -- | A variant of catchSync that fully forces evaluation of the -- result value to find all impure exceptions. catchSyncDeep :: NFData a => Eff es a -> (SomeException -> Eff es a) -> Eff es a -- | Flipped version of catch. handle :: Exception e => (e -> Eff es a) -> Eff es a -> Eff es a -- | Flipped version of catchDeep. handleDeep :: (Exception e, NFData a) => (e -> Eff es a) -> Eff es a -> Eff es a -- | Flipped version of catchJust. handleJust :: (HasCallStack, Exception e) => (e -> Maybe b) -> (b -> Eff es a) -> Eff es a -> Eff es a -- | Flipped version of catchIf. handleIf :: Exception e => (e -> Bool) -> (e -> Eff es a) -> Eff es a -> Eff es a -- | Flipped version of catchIO. handleIO :: (IOException -> Eff es a) -> Eff es a -> Eff es a -- | Flipped version of catchSync. handleSync :: (SomeException -> Eff es a) -> Eff es a -> Eff es a -- | Flipped version of catchSyncDeep. handleSyncDeep :: NFData a => (SomeException -> Eff es a) -> Eff es a -> Eff es a -- | Lifted try. try :: Exception e => Eff es a -> Eff es (Either e a) -- | A variant of try that fully forces evaluation of the result -- value to find all impure exceptions. tryDeep :: (Exception e, NFData a) => Eff es a -> Eff es (Either e a) -- | Lifted tryJust. tryJust :: Exception e => (e -> Maybe b) -> Eff es a -> Eff es (Either b a) -- | Catch an exception only if it satisfies a specific predicate. tryIf :: Exception e => (e -> Bool) -> Eff es a -> Eff es (Either e a) -- | try specialized to catch IOException. tryIO :: Eff es a -> Eff es (Either IOException a) -- | try specialized to catch all exceptions considered to be -- synchronous. -- --
-- trySync ≡ tryIf @SomeException isSyncException ---- -- See the check exception type section for more information. trySync :: Eff es a -> Eff es (Either SomeException a) -- | A variant of trySync that fully forces evaluation of the result -- value to find all impure exceptions. trySyncDeep :: NFData a => Eff es a -> Eff es (Either SomeException a) -- | Generalized version of Handler data () => Handler (m :: Type -> Type) a Handler :: (e -> m a) -> Handler (m :: Type -> Type) a -- | Lifted catches. catches :: Eff es a -> [Handler (Eff es) a] -> Eff es a -- | A variant of catches that fully forces evaluation of the result -- value to find all impure exceptions. catchesDeep :: NFData a => Eff es a -> [Handler (Eff es) a] -> Eff es a -- | Lifted bracket. bracket :: Eff es a -> (a -> Eff es b) -> (a -> Eff es c) -> Eff es c -- | Lifted bracket_. bracket_ :: Eff es a -> Eff es b -> Eff es c -> Eff es c -- | Lifted bracketOnError. bracketOnError :: Eff es a -> (a -> Eff es b) -> (a -> Eff es c) -> Eff es c -- | Generalization of bracket. -- -- See generalBracket for more information. generalBracket :: Eff es a -> (a -> ExitCase c -> Eff es b) -> (a -> Eff es c) -> Eff es (c, b) -- | A MonadMask computation may either succeed with a value, abort -- with an exception, or abort for some other reason. For example, in -- ExceptT e IO you can use throwM to abort with an -- exception (ExitCaseException) or throwE to abort with a -- value of type e (ExitCaseAbort). data () => ExitCase a ExitCaseSuccess :: a -> ExitCase a ExitCaseException :: SomeException -> ExitCase a ExitCaseAbort :: ExitCase a -- | Lifted finally. finally :: Eff es a -> Eff es b -> Eff es a -- | Lifted onException. onException :: Eff es a -> Eff es b -> Eff es a -- | Lifted evaluate. evaluate :: a -> Eff es a -- | Deeply evaluate a value using evaluate and NFData. evaluateDeep :: NFData a => a -> Eff es a -- | Check if the given exception is considered synchronous. isSyncException :: Exception e => e -> Bool -- | Check if the given exception is considered asynchronous. isAsyncException :: Exception e => e -> Bool -- | Lifted mask. mask :: ((forall r. Eff es r -> Eff es r) -> Eff es a) -> Eff es a -- | Lifted mask_. mask_ :: Eff es a -> Eff es a -- | Lifted uninterruptibleMask. uninterruptibleMask :: ((forall r. Eff es r -> Eff es r) -> Eff es a) -> Eff es a -- | Lifted uninterruptibleMask_. uninterruptibleMask_ :: Eff es a -> Eff es a -- | Describes the behaviour of a thread when an asynchronous exception is -- received. data () => MaskingState -- | asynchronous exceptions are unmasked (the normal state) Unmasked :: MaskingState -- | the state during mask: asynchronous exceptions are masked, but -- blocking operations may still be interrupted MaskedInterruptible :: MaskingState -- | the state during uninterruptibleMask: asynchronous exceptions -- are masked, and blocking operations may not be interrupted MaskedUninterruptible :: MaskingState -- | Lifted getMaskingState. getMaskingState :: Eff es MaskingState -- | Lifted interruptible. interruptible :: Eff es a -> Eff es a -- | Lifted allowInterrupt. allowInterrupt :: Eff es () -- | The SomeException type is the root of the exception type -- hierarchy. When an exception of type e is thrown, behind the -- scenes it is encapsulated in a SomeException. data () => SomeException SomeException :: e -> SomeException -- | Any type that you wish to throw or catch as an exception must be an -- instance of the Exception class. The simplest case is a new -- exception type directly below the root: -- --
-- data MyException = ThisException | ThatException -- deriving Show -- -- instance Exception MyException ---- -- The default method definitions in the Exception class do what -- we need in this case. You can now throw and catch -- ThisException and ThatException as exceptions: -- --
-- *Main> throw ThisException `catch` \e -> putStrLn ("Caught " ++ show (e :: MyException))
-- Caught ThisException
--
--
-- In more complicated examples, you may wish to define a whole hierarchy
-- of exceptions:
--
-- -- --------------------------------------------------------------------- -- -- Make the root exception type for all the exceptions in a compiler -- -- data SomeCompilerException = forall e . Exception e => SomeCompilerException e -- -- instance Show SomeCompilerException where -- show (SomeCompilerException e) = show e -- -- instance Exception SomeCompilerException -- -- compilerExceptionToException :: Exception e => e -> SomeException -- compilerExceptionToException = toException . SomeCompilerException -- -- compilerExceptionFromException :: Exception e => SomeException -> Maybe e -- compilerExceptionFromException x = do -- SomeCompilerException a <- fromException x -- cast a -- -- --------------------------------------------------------------------- -- -- Make a subhierarchy for exceptions in the frontend of the compiler -- -- data SomeFrontendException = forall e . Exception e => SomeFrontendException e -- -- instance Show SomeFrontendException where -- show (SomeFrontendException e) = show e -- -- instance Exception SomeFrontendException where -- toException = compilerExceptionToException -- fromException = compilerExceptionFromException -- -- frontendExceptionToException :: Exception e => e -> SomeException -- frontendExceptionToException = toException . SomeFrontendException -- -- frontendExceptionFromException :: Exception e => SomeException -> Maybe e -- frontendExceptionFromException x = do -- SomeFrontendException a <- fromException x -- cast a -- -- --------------------------------------------------------------------- -- -- Make an exception type for a particular frontend compiler exception -- -- data MismatchedParentheses = MismatchedParentheses -- deriving Show -- -- instance Exception MismatchedParentheses where -- toException = frontendExceptionToException -- fromException = frontendExceptionFromException ---- -- We can now catch a MismatchedParentheses exception as -- MismatchedParentheses, SomeFrontendException or -- SomeCompilerException, but not other types, e.g. -- IOException: -- --
-- *Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: MismatchedParentheses))
-- Caught MismatchedParentheses
-- *Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: SomeFrontendException))
-- Caught MismatchedParentheses
-- *Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: SomeCompilerException))
-- Caught MismatchedParentheses
-- *Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: IOException))
-- *** Exception: MismatchedParentheses
--
class (Typeable e, Show e) => Exception e
toException :: Exception e => e -> SomeException
fromException :: Exception e => SomeException -> Maybe e
-- | Render this exception value in a human-friendly manner.
--
-- Default implementation: show.
displayException :: Exception e => e -> String
-- | This function maps one exception into another as proposed in the paper
-- "A semantics for imprecise exceptions".
mapException :: (Exception e1, Exception e2) => (e1 -> e2) -> a -> a
-- | Exceptions that occur in the IO monad. An
-- IOException records a more specific error type, a descriptive
-- string and maybe the handle that was used when the error was flagged.
data () => IOException
-- | Arithmetic exceptions.
data () => ArithException
Overflow :: ArithException
Underflow :: ArithException
LossOfPrecision :: ArithException
DivideByZero :: ArithException
Denormal :: ArithException
RatioZeroDenominator :: ArithException
-- | Exceptions generated by array operations
data () => ArrayException
-- | An attempt was made to index an array outside its declared bounds.
IndexOutOfBounds :: String -> ArrayException
-- | An attempt was made to evaluate an element of an array that had not
-- been initialized.
UndefinedElement :: String -> ArrayException
-- | assert was applied to False.
newtype () => AssertionFailed
AssertionFailed :: String -> AssertionFailed
-- | A class method without a definition (neither a default definition, nor
-- a definition in the appropriate instance) was called. The
-- String gives information about which method it was.
newtype () => NoMethodError
NoMethodError :: String -> NoMethodError
-- | A pattern match failed. The String gives information about
-- the source location of the pattern.
newtype () => PatternMatchFail
PatternMatchFail :: String -> PatternMatchFail
-- | An uninitialised record field was used. The String gives
-- information about the source location where the record was
-- constructed.
newtype () => RecConError
RecConError :: String -> RecConError
-- | A record selector was applied to a constructor without the appropriate
-- field. This can only happen with a datatype with multiple
-- constructors, where some fields are in one constructor but not
-- another. The String gives information about the source
-- location of the record selector.
newtype () => RecSelError
RecSelError :: String -> RecSelError
-- | A record update was performed on a constructor without the appropriate
-- field. This can only happen with a datatype with multiple
-- constructors, where some fields are in one constructor but not
-- another. The String gives information about the source
-- location of the record update.
newtype () => RecUpdError
RecUpdError :: String -> RecUpdError
-- | This is thrown when the user calls error. The first
-- String is the argument given to error, second
-- String is the location.
data () => ErrorCall
ErrorCallWithLocation :: String -> String -> ErrorCall
pattern ErrorCall :: String -> ErrorCall
-- | An expression that didn't typecheck during compile time was called.
-- This is only possible with -fdefer-type-errors. The String
-- gives details about the failed type check.
newtype () => TypeError
TypeError :: String -> TypeError
-- | Superclass for asynchronous exceptions.
data () => SomeAsyncException
SomeAsyncException :: e -> SomeAsyncException
-- | Asynchronous exceptions.
data () => AsyncException
-- | The current thread's stack exceeded its limit. Since an exception has
-- been raised, the thread's stack will certainly be below its limit
-- again, but the programmer should take remedial action immediately.
StackOverflow :: AsyncException
-- | The program's heap is reaching its limit, and the program should take
-- action to reduce the amount of live data it has. Notes:
--
-- -- >>> import Effectful.Exception qualified as E ---- --
-- >>> boom = error "BOOM!" ---- --
-- >>> runEff . runError @ErrorCall $ boom `catchError` \_ (_::ErrorCall) -> pure "caught" -- *** Exception: BOOM! -- ... ---- -- If you want to catch regular exceptions, you should use catch -- (or a similar function): -- --
-- >>> runEff $ boom `E.catch` \(_::ErrorCall) -> pure "caught" -- "caught" ---- -- On the other hand, functions for safe finalization and management of -- resources such as finally and bracket work as expected: -- --
-- >>> msg = liftIO . putStrLn ---- --
-- >>> :{
-- runEff . runErrorNoCallStack @String $ do
-- E.bracket_ (msg "Beginning.")
-- (msg "Cleaning up.")
-- (msg "Computing." >> throwError "oops" >> msg "More.")
-- :}
-- Beginning.
-- Computing.
-- Cleaning up.
-- Left "oops"
--
--
-- Note: unlike the ExceptT monad transformer from the
-- transformers library, the order in which you handle the
-- Error effect with regard to other stateful effects does not
-- matter. Consider the following:
--
-- -- >>> import Control.Monad.State.Strict qualified as T -- -- >>> import Control.Monad.Except qualified as T ---- --
-- >>> m1 = (T.modify (++ " there!") >> T.throwError "oops") `T.catchError` \_ -> pure () ---- --
-- >>> (`T.runStateT` "Hi") . T.runExceptT $ m1 -- (Right (),"Hi there!") ---- --
-- >>> T.runExceptT . (`T.runStateT` "Hi") $ m1 -- Right ((),"Hi") ---- -- Here, whether state updates within the catchError block are -- discarded or not depends on the shape of the monad transformer stack, -- which is surprising and can be a source of subtle bugs. On the other -- hand: -- --
-- >>> import Effectful.State.Static.Local ---- --
-- >>> m2 = (modify (++ " there!") >> throwError "oops") `catchError` \_ (_::String) -> pure () ---- --
-- >>> runEff . runState "Hi" . runError @String $ m2 -- (Right (),"Hi there!") ---- --
-- >>> runEff . runError @String . runState "Hi" $ m2 -- Right ((),"Hi there!") ---- -- Here, no matter the order of effects, state updates made within the -- catchError block before the error happens always persist, -- giving predictable behavior. -- -- Hint: if you'd like to reproduce the transactional behavior -- with the State effect, appropriate usage of -- bracketOnError will do the trick. module Effectful.Error.Static -- | Provide the ability to handle errors of type e. data Error (e :: Type) :: Effect -- | Handle errors of type e. runError :: forall e es a. HasCallStack => Eff (Error e : es) a -> Eff es (Either (CallStack, e) a) -- | Handle errors of type e with a specific error handler. runErrorWith :: HasCallStack => (CallStack -> e -> Eff es a) -> Eff (Error e : es) a -> Eff es a -- | Handle errors of type e. In case of an error discard the -- CallStack. runErrorNoCallStack :: forall e es a. HasCallStack => Eff (Error e : es) a -> Eff es (Either e a) -- | Handle errors of type e with a specific error handler. In -- case of an error discard the CallStack. runErrorNoCallStackWith :: HasCallStack => (e -> Eff es a) -> Eff (Error e : es) a -> Eff es a -- | Throw an error of type e and specify a display function in -- case a third-party code catches the internal exception and -- shows it. throwErrorWith :: forall e es a. (HasCallStack, Error e :> es) => (e -> String) -> e -> Eff es a -- | Throw an error of type e with show as a display -- function. throwError :: forall e es a. (HasCallStack, Error e :> es, Show e) => e -> Eff es a -- | Throw an error of type e with no display function. throwError_ :: forall e es a. (HasCallStack, Error e :> es) => e -> Eff es a -- | Handle an error of type e. catchError :: forall e es a. (HasCallStack, Error e :> es) => Eff es a -> (CallStack -> e -> Eff es a) -> Eff es a -- | The same as flip catchError, which is useful in -- situations where the code for the handler is shorter. handleError :: forall e es a. (HasCallStack, Error e :> es) => (CallStack -> e -> Eff es a) -> Eff es a -> Eff es a -- | Similar to catchError, but returns an Either result -- which is a Right if no error was thrown and a Left -- otherwise. tryError :: forall e es a. (HasCallStack, Error e :> es) => Eff es a -> Eff es (Either (CallStack, e) a) -- | Request a CallStack. -- -- NOTE: The implicit parameter ?callStack :: CallStack is an -- implementation detail and should not be considered part of the -- CallStack API, we may decide to change the implementation in -- the future. type HasCallStack = ?callStack :: CallStack -- | CallStacks are a lightweight method of obtaining a partial -- call-stack at any point in the program. -- -- A function can request its call-site with the HasCallStack -- constraint. For example, we can define -- --
-- putStrLnWithCallStack :: HasCallStack => String -> IO () ---- -- as a variant of putStrLn that will get its call-site and -- print it, along with the string given as argument. We can access the -- call-stack inside putStrLnWithCallStack with -- callStack. -- --
-- >>> :{
-- putStrLnWithCallStack :: HasCallStack => String -> IO ()
-- putStrLnWithCallStack msg = do
-- putStrLn msg
-- putStrLn (prettyCallStack callStack)
-- :}
--
--
-- Thus, if we call putStrLnWithCallStack we will get a
-- formatted call-stack alongside our string.
--
-- -- >>> putStrLnWithCallStack "hello" -- hello -- CallStack (from HasCallStack): -- putStrLnWithCallStack, called at <interactive>:... in interactive:Ghci... ---- -- GHC solves HasCallStack constraints in three steps: -- --
-- interpret ≡ reinterpret id --reinterpret :: (HasCallStack, DispatchOf e ~ Dynamic) => (Eff handlerEs a -> Eff es b) -> EffectHandler e handlerEs -> Eff (e : es) a -> Eff es b -- | reinterpret with the effect handler as the last argument. reinterpretWith :: (HasCallStack, DispatchOf e ~ Dynamic) => (Eff handlerEs a -> Eff es b) -> Eff (e : es) a -> EffectHandler e handlerEs -> Eff es b -- | Replace the handler of an existing effect with a new one. -- -- Note: this function allows for augmenting handlers with a new -- functionality as the new handler can send operations to the old one. -- --
-- >>> :{
-- data E :: Effect where
-- Op1 :: E m ()
-- Op2 :: E m ()
-- type instance DispatchOf E = Dynamic
-- :}
--
--
--
-- >>> :{
-- runE :: IOE :> es => Eff (E : es) a -> Eff es a
-- runE = interpret_ $ \case
-- Op1 -> liftIO (putStrLn "op1")
-- Op2 -> liftIO (putStrLn "op2")
-- :}
--
--
-- -- >>> runEff . runE $ send Op1 >> send Op2 -- op1 -- op2 ---- --
-- >>> :{
-- augmentOp2 :: (E :> es, IOE :> es) => Eff es a -> Eff es a
-- augmentOp2 = interpose_ $ \case
-- Op1 -> send Op1
-- Op2 -> liftIO (putStrLn "augmented op2") >> send Op2
-- :}
--
--
-- -- >>> runEff . runE . augmentOp2 $ send Op1 >> send Op2 -- op1 -- augmented op2 -- op2 ---- -- Note: when using interpose to modify only specific -- operations of the effect, your first instinct might be to match on -- them, then handle the rest with a generic match. Unfortunately, this -- doesn't work out of the box: -- --
-- >>> :{
-- genericAugmentOp2 :: (E :> es, IOE :> es) => Eff es a -> Eff es a
-- genericAugmentOp2 = interpose_ $ \case
-- Op2 -> liftIO (putStrLn "augmented op2") >> send Op2
-- op -> send op
-- :}
-- ...
-- ...Couldn't match type ‘localEs’ with ‘es’
-- ...
--
--
-- This is because within the generic match, send expects Op
-- (Eff es) a, but op has a type Op (Eff localEs)
-- a. If the effect in question is first order (i.e. its m
-- type parameter is phantom), you can use coerce:
--
--
-- >>> import Data.Coerce
--
-- >>> :{
-- genericAugmentOp2 :: (E :> es, IOE :> es) => Eff es a -> Eff es a
-- genericAugmentOp2 = interpose_ $ \case
-- Op2 -> liftIO (putStrLn "augmented op2") >> send Op2
-- op -> send @E (coerce op)
-- :}
--
--
-- -- >>> runEff . runE . genericAugmentOp2 $ send Op1 >> send Op2 -- op1 -- augmented op2 -- op2 ---- -- On the other hand, when dealing with higher order effects you need to -- pattern match on each operation and unlift where necessary. interpose :: forall e es a. (HasCallStack, DispatchOf e ~ Dynamic, e :> es) => EffectHandler e es -> Eff es a -> Eff es a -- | interpose with the effect handler as the last argument. interposeWith :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es) => Eff es a -> EffectHandler e es -> Eff es a -- | Replace the handler of an existing effect with a new one that uses -- other, private effects. -- --
-- interpose ≡ impose id --impose :: forall e es handlerEs a b. (HasCallStack, DispatchOf e ~ Dynamic, e :> es) => (Eff handlerEs a -> Eff es b) -> EffectHandler e handlerEs -> Eff es a -> Eff es b -- | impose with the effect handler as the last argument. imposeWith :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es) => (Eff handlerEs a -> Eff es b) -> Eff es a -> EffectHandler e handlerEs -> Eff es b -- | Opaque representation of the Eff environment at the point of -- calling the send function, i.e. right before the control is -- passed to the effect handler. -- -- The second type variable represents effects of a handler and is needed -- for technical reasons to guarantee soundness (see SharedSuffix -- for more information). data LocalEnv (localEs :: [Effect]) (handlerEs :: [Effect]) -- | Create a local unlifting function with the SeqUnlift strategy. -- For the general version see localUnlift. localSeqUnlift :: (HasCallStack, SharedSuffix es handlerEs) => LocalEnv localEs handlerEs -> ((forall r. Eff localEs r -> Eff es r) -> Eff es a) -> Eff es a -- | Create a local unlifting function with the SeqUnlift strategy. -- For the general version see localUnliftIO. localSeqUnliftIO :: (HasCallStack, SharedSuffix es handlerEs, IOE :> es) => LocalEnv localEs handlerEs -> ((forall r. Eff localEs r -> IO r) -> IO a) -> Eff es a -- | Create a local unlifting function with the given strategy. localUnlift :: (HasCallStack, SharedSuffix es handlerEs) => LocalEnv localEs handlerEs -> UnliftStrategy -> ((forall r. Eff localEs r -> Eff es r) -> Eff es a) -> Eff es a -- | Create a local unlifting function with the given strategy. localUnliftIO :: (HasCallStack, SharedSuffix es handlerEs, IOE :> es) => LocalEnv localEs handlerEs -> UnliftStrategy -> ((forall r. Eff localEs r -> IO r) -> IO a) -> Eff es a -- | Create a local lifting function with the SeqUnlift strategy. -- For the general version see localLift. localSeqLift :: (HasCallStack, SharedSuffix es handlerEs) => LocalEnv localEs handlerEs -> ((forall r. Eff es r -> Eff localEs r) -> Eff es a) -> Eff es a -- | Create a local lifting function with the given strategy. localLift :: (HasCallStack, SharedSuffix es handlerEs) => LocalEnv localEs handlerEs -> UnliftStrategy -> ((forall r. Eff es r -> Eff localEs r) -> Eff es a) -> Eff es a -- | Utility for lifting Eff computations of type -- --
-- Eff es a -> Eff es b ---- -- to -- --
-- Eff localEs a -> Eff localEs b ---- -- Note: the computation must not run its argument in a different -- thread, attempting to do so will result in a runtime error. withLiftMap :: (HasCallStack, SharedSuffix es handlerEs) => LocalEnv localEs handlerEs -> ((forall a b. (Eff es a -> Eff es b) -> Eff localEs a -> Eff localEs b) -> Eff es r) -> Eff es r -- | Utility for lifting IO computations of type -- --
-- IO a -> IO b ---- -- to -- --
-- Eff localEs a -> Eff localEs b ---- -- Note: the computation must not run its argument in a different -- thread, attempting to do so will result in a runtime error. -- -- Useful e.g. for lifting the unmasking function in mask-like -- computations: -- --
-- >>> :{
-- data Fork :: Effect where
-- ForkWithUnmask :: ((forall a. m a -> m a) -> m ()) -> Fork m ThreadId
-- type instance DispatchOf Fork = Dynamic
-- :}
--
--
--
-- >>> :{
-- runFork :: IOE :> es => Eff (Fork : es) a -> Eff es a
-- runFork = interpret $ \env (ForkWithUnmask m) -> withLiftMapIO env $ \liftMap -> do
-- localUnliftIO env (ConcUnlift Ephemeral $ Limited 1) $ \unlift -> do
-- forkIOWithUnmask $ \unmask -> unlift $ m $ liftMap unmask
-- :}
--
withLiftMapIO :: (HasCallStack, SharedSuffix es handlerEs, IOE :> es) => LocalEnv localEs handlerEs -> ((forall a b. (IO a -> IO b) -> Eff localEs a -> Eff localEs b) -> Eff es r) -> Eff es r
-- | Create a local lifting and unlifting function with the given strategy.
--
-- Useful for lifting complicated Eff computations where the
-- monadic action shows in both positive (as a result) and negative (as
-- an argument) position.
--
-- Note: depending on the computation you're lifting
-- localUnlift along with withLiftMap might be enough and
-- is more efficient.
localLiftUnlift :: (HasCallStack, SharedSuffix es handlerEs) => LocalEnv localEs handlerEs -> UnliftStrategy -> ((forall r. Eff es r -> Eff localEs r) -> (forall r. Eff localEs r -> Eff es r) -> Eff es a) -> Eff es a
-- | Create a local unlifting function with the given strategy along with
-- an unrestricted lifting function.
--
-- Useful for lifting complicated IO computations where the
-- monadic action shows in both positive (as a result) and negative (as
-- an argument) position.
--
-- Note: depending on the computation you're lifting
-- localUnliftIO along with withLiftMapIO might be enough
-- and is more efficient.
localLiftUnliftIO :: (HasCallStack, SharedSuffix es handlerEs, IOE :> es) => LocalEnv localEs handlerEs -> UnliftStrategy -> ((forall r. IO r -> Eff localEs r) -> (forall r. Eff localEs r -> IO r) -> IO a) -> Eff es a
-- | Lend effects to the local environment.
--
-- Consider the following effect:
--
--
-- >>> :{
-- data D :: Effect where
-- D :: D m ()
-- type instance DispatchOf D = Dynamic
-- :}
--
--
-- and an auxiliary effect that requires both IOE and D
-- to run:
--
--
-- >>> :{
-- data E :: Effect
-- runE :: (IOE :> es, D :> es) => Eff (E : es) a -> Eff es a
-- runE = error "runE"
-- :}
--
--
-- Trying to use runE inside the handler of D doesn't
-- work out of the box:
--
--
-- >>> :{
-- runD :: IOE :> es => Eff (D : es) a -> Eff es a
-- runD = interpret $ \env -> \case
-- D -> localSeqUnlift env $ \unlift -> do
-- unlift . runE $ pure ()
-- :}
-- ...
-- ...Could not deduce ...IOE :> localEs... arising from a use of ‘runE’
-- ...from the context: IOE :> es
-- ...
--
--
-- The problem is that runE needs IOE :> localEs,
-- but only IOE :> es is available. This function allows us
-- to bridge the gap:
--
--
-- >>> :{
-- runD :: IOE :> es => Eff (D : es) a -> Eff es a
-- runD = interpret $ \env -> \case
-- D -> localSeqUnlift env $ \unlift -> do
-- localSeqLend @'[IOE] env $ \useIOE -> do
-- unlift . useIOE . runE $ pure ()
-- :}
--
localSeqLend :: forall lentEs es handlerEs localEs a. (HasCallStack, KnownSubset lentEs es, SharedSuffix es handlerEs) => LocalEnv localEs handlerEs -> ((forall r. Eff (lentEs ++ localEs) r -> Eff localEs r) -> Eff es a) -> Eff es a
-- | Lend effects to the local environment with a given unlifting strategy.
--
-- Generalizes localSeqLend.
localLend :: forall lentEs es handlerEs localEs a. (HasCallStack, KnownSubset lentEs es, SharedSuffix es handlerEs) => LocalEnv localEs handlerEs -> UnliftStrategy -> ((forall r. Eff (lentEs ++ localEs) r -> Eff localEs r) -> Eff es a) -> Eff es a
-- | Borrow effects from the local environment.
localSeqBorrow :: forall borrowedEs es handlerEs localEs a. (HasCallStack, KnownSubset borrowedEs localEs, SharedSuffix es handlerEs) => LocalEnv localEs handlerEs -> ((forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a) -> Eff es a
-- | Borrow effects from the local environment with a given unlifting
-- strategy.
--
-- Generalizes localSeqBorrow.
localBorrow :: forall borrowedEs es handlerEs localEs a. (HasCallStack, KnownSubset borrowedEs localEs, SharedSuffix es handlerEs) => LocalEnv localEs handlerEs -> UnliftStrategy -> ((forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a) -> Eff es a
-- | Require that both effect stacks share an opaque suffix.
--
-- Functions from the localUnlift family utilize this constraint
-- to guarantee sensible usage of unlifting functions.
--
-- As an example, consider the following higher order effect:
--
--
-- >>> :{
-- data E :: Effect where
-- E :: m a -> E m a
-- type instance DispatchOf E = Dynamic
-- :}
--
--
-- Running local actions in a more specific environment is fine:
--
--
-- >>> :{
-- runE1 :: Eff (E : es) a -> Eff es a
-- runE1 = interpret $ \env -> \case
-- E m -> runReader () $ do
-- localSeqUnlift env $ \unlift -> unlift m
-- :}
--
--
-- Running local actions in a more general environment is fine:
--
--
-- >>> :{
-- runE2 :: Eff (E : es) a -> Eff es a
-- runE2 = reinterpret (runReader ()) $ \env -> \case
-- E m -> raise $ do
-- localSeqUnlift env $ \unlift -> unlift m
-- :}
--
--
-- However, running local actions in an unrelated environment is not fine
-- as this would make it possible to run anything within
-- runPureEff:
--
--
-- >>> :{
-- runE3 :: Eff (E : es) a -> Eff es a
-- runE3 = reinterpret (runReader ()) $ \env -> \case
-- E m -> pure . runPureEff $ do
-- localSeqUnlift env $ \unlift -> unlift m
-- :}
-- ...
-- ...Could not deduce ...SharedSuffix '[] es...
-- ...
--
--
-- Running local actions in a monomorphic effect stack is also not fine
-- as this makes a special case of the above possible:
--
--
-- >>> :{
-- runE4 :: Eff [E, IOE] a -> Eff '[IOE] a
-- runE4 = interpret $ \env -> \case
-- E m -> pure . runPureEff $ do
-- localSeqUnlift env $ \unlift -> unlift m
-- :}
-- ...
-- ...Running local actions in monomorphic effect stacks is not supported...
-- ...
--
class SharedSuffix (es1 :: [Effect]) (es2 :: [Effect])
-- | Provide evidence that subEs is a known subset of es.
class Subset subEs es => KnownSubset (subEs :: [Effect]) (es :: [Effect])
-- | Type signature of a first order effect handler.
type EffectHandler_ (e :: Effect) (es :: [Effect]) = forall a localEs. HasCallStack => -- | The operation. e (Eff localEs) a -> Eff es a
-- | interpret for first order effects.
interpret_ :: (HasCallStack, DispatchOf e ~ Dynamic) => EffectHandler_ e es -> Eff (e : es) a -> Eff es a
-- | interpretWith for first order effects.
interpretWith_ :: (HasCallStack, DispatchOf e ~ Dynamic) => Eff (e : es) a -> EffectHandler_ e es -> Eff es a
-- | reinterpret for first order effects.
reinterpret_ :: (HasCallStack, DispatchOf e ~ Dynamic) => (Eff handlerEs a -> Eff es b) -> EffectHandler_ e handlerEs -> Eff (e : es) a -> Eff es b
-- | reinterpretWith for first order effects.
reinterpretWith_ :: (HasCallStack, DispatchOf e ~ Dynamic) => (Eff handlerEs a -> Eff es b) -> Eff (e : es) a -> EffectHandler_ e handlerEs -> Eff es b
-- | interpose for first order effects.
interpose_ :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es) => EffectHandler_ e es -> Eff es a -> Eff es a
-- | interposeWith for first order effects.
interposeWith_ :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es) => Eff es a -> EffectHandler_ e es -> Eff es a
-- | impose for first order effects.
impose_ :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es) => (Eff handlerEs a -> Eff es b) -> EffectHandler_ e handlerEs -> Eff es a -> Eff es b
-- | imposeWith for first order effects.
imposeWith_ :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es) => (Eff handlerEs a -> Eff es b) -> Eff es a -> EffectHandler_ e handlerEs -> Eff es b
-- | Request a CallStack.
--
-- NOTE: The implicit parameter ?callStack :: CallStack is an
-- implementation detail and should not be considered part of the
-- CallStack API, we may decide to change the implementation in
-- the future.
type HasCallStack = ?callStack :: CallStack
instance Effectful.Dispatch.Dynamic.SharedSuffix es es
instance Effectful.Dispatch.Dynamic.SharedSuffix es1 es2 => Effectful.Dispatch.Dynamic.SharedSuffix (e : es1) es2
instance Effectful.Dispatch.Dynamic.SharedSuffix es1 es2 => Effectful.Dispatch.Dynamic.SharedSuffix es1 (e : es2)
instance (TypeError ...) => Effectful.Dispatch.Dynamic.SharedSuffix '[] '[]
-- | Provider of the MonadFail instance for Eff.
module Effectful.Fail
-- | Provide the ability to use the MonadFail instance for
-- Eff.
data Fail :: Effect
[Fail] :: String -> Fail m a
-- | Run the Fail effect via Error.
runFail :: HasCallStack => Eff (Fail : es) a -> Eff es (Either String a)
-- | Run the Fail effect via the MonadFail instance for
-- IO.
runFailIO :: (HasCallStack, IOE :> es) => Eff (Fail : es) a -> Eff es a
-- | The dynamically dispatched variant of the Error effect.
--
-- Note: unless you plan to change interpretations at runtime,
-- it's recommended to use the statically dispatched variant, i.e.
-- Effectful.Error.Static.
module Effectful.Error.Dynamic
-- | Provide the ability to handle errors of type e.
data Error e :: Effect
[ThrowErrorWith] :: (e -> String) -> e -> Error e m a
[CatchError] :: m a -> (CallStack -> e -> m a) -> Error e m a
-- | Handle errors of type e (via Effectful.Error.Static).
runError :: HasCallStack => Eff (Error e : es) a -> Eff es (Either (CallStack, e) a)
-- | Handle errors of type e (via Effectful.Error.Static)
-- with a specific error handler.
runErrorWith :: HasCallStack => (CallStack -> e -> Eff es a) -> Eff (Error e : es) a -> Eff es a
-- | Handle errors of type e (via Effectful.Error.Static).
-- In case of an error discard the CallStack.
runErrorNoCallStack :: HasCallStack => Eff (Error e : es) a -> Eff es (Either e a)
-- | Handle errors of type e (via Effectful.Error.Static)
-- with a specific error handler. In case of an error discard the
-- CallStack.
runErrorNoCallStackWith :: HasCallStack => (e -> Eff es a) -> Eff (Error e : es) a -> Eff es a
-- | Throw an error of type e and specify a display function in
-- case a third-party code catches the internal exception and
-- shows it.
throwErrorWith :: (HasCallStack, Error e :> es) => (e -> String) -> e -> Eff es a
-- | Throw an error of type e with show as a display
-- function.
throwError :: (HasCallStack, Error e :> es, Show e) => e -> Eff es a
-- | Throw an error of type e with no display function.
throwError_ :: (HasCallStack, Error e :> es) => e -> Eff es a
-- | Handle an error of type e.
catchError :: (HasCallStack, Error e :> es) => Eff es a -> (CallStack -> e -> Eff es a) -> Eff es a
-- | The same as flip catchError, which is useful in
-- situations where the code for the handler is shorter.
handleError :: (HasCallStack, Error e :> es) => (CallStack -> e -> Eff es a) -> Eff es a -> Eff es a
-- | Similar to catchError, but returns an Either result
-- which is a Right if no error was thrown and a Left
-- otherwise.
tryError :: (HasCallStack, Error e :> es) => Eff es a -> Eff es (Either (CallStack, e) a)
-- | Request a CallStack.
--
-- NOTE: The implicit parameter ?callStack :: CallStack is an
-- implementation detail and should not be considered part of the
-- CallStack API, we may decide to change the implementation in
-- the future.
type HasCallStack = ?callStack :: CallStack
-- | CallStacks are a lightweight method of obtaining a partial
-- call-stack at any point in the program.
--
-- A function can request its call-site with the HasCallStack
-- constraint. For example, we can define
--
-- -- putStrLnWithCallStack :: HasCallStack => String -> IO () ---- -- as a variant of putStrLn that will get its call-site and -- print it, along with the string given as argument. We can access the -- call-stack inside putStrLnWithCallStack with -- callStack. -- --
-- >>> :{
-- putStrLnWithCallStack :: HasCallStack => String -> IO ()
-- putStrLnWithCallStack msg = do
-- putStrLn msg
-- putStrLn (prettyCallStack callStack)
-- :}
--
--
-- Thus, if we call putStrLnWithCallStack we will get a
-- formatted call-stack alongside our string.
--
-- -- >>> putStrLnWithCallStack "hello" -- hello -- CallStack (from HasCallStack): -- putStrLnWithCallStack, called at <interactive>:... in interactive:Ghci... ---- -- GHC solves HasCallStack constraints in three steps: -- --
-- >>> import Effectful.Dispatch.Dynamic ---- --
-- >>> :{
-- data X :: Effect where
-- X :: X m Int
-- type instance DispatchOf X = Dynamic
-- :}
--
--
--
-- >>> :{
-- runPureEff . runLabeled @"x" (interpret_ $ \X -> pure 333) $ do
-- send $ Labeled @"x" X
-- :}
-- 333
--
newtype Labeled (label :: k) (e :: Effect) :: Effect
[Labeled] :: forall label e m a. e m a -> Labeled label e m a
-- | Run a Labeled effect with a given effect handler.
runLabeled :: forall label e es a b. HasCallStack => (Eff (e : es) a -> Eff es b) -> Eff (Labeled label e : es) a -> Eff es b
-- | Bring an effect into scope without a label.
--
-- Useful for running code written with the non-labeled effect in mind.
labeled :: forall label e es a. (HasCallStack, Labeled label e :> es) => Eff (e : es) a -> Eff es a
-- | Convenience functions for the Labeled Error effect.
module Effectful.Labeled.Error
-- | Provide the ability to handle errors of type e.
data Error e :: Effect
[ThrowErrorWith] :: (e -> String) -> e -> Error e m a
[CatchError] :: m a -> (CallStack -> e -> m a) -> Error e m a
-- | Handle errors of type e (via Effectful.Error.Static).
runError :: forall label e es a. HasCallStack => Eff (Labeled label (Error e) : es) a -> Eff es (Either (CallStack, e) a)
-- | Handle errors of type e (via Effectful.Error.Static)
-- with a specific error handler.
runErrorWith :: forall label e es a. HasCallStack => (CallStack -> e -> Eff es a) -> Eff (Labeled label (Error e) : es) a -> Eff es a
-- | Handle errors of type e (via Effectful.Error.Static).
-- In case of an error discard the CallStack.
runErrorNoCallStack :: forall label e es a. HasCallStack => Eff (Labeled label (Error e) : es) a -> Eff es (Either e a)
-- | Handle errors of type e (via Effectful.Error.Static)
-- with a specific error handler. In case of an error discard the
-- CallStack.
runErrorNoCallStackWith :: forall label e es a. HasCallStack => (e -> Eff es a) -> Eff (Labeled label (Error e) : es) a -> Eff es a
-- | Throw an error of type e and specify a display function in
-- case a third-party code catches the internal exception and
-- shows it.
throwErrorWith :: forall label e es a. (HasCallStack, Labeled label (Error e) :> es) => (e -> String) -> e -> Eff es a
-- | Throw an error of type e with show as a display
-- function.
throwError :: forall label e es a. (HasCallStack, Labeled label (Error e) :> es, Show e) => e -> Eff es a
-- | Throw an error of type e with no display function.
throwError_ :: forall label e es a. (HasCallStack, Labeled label (Error e) :> es) => e -> Eff es a
-- | Handle an error of type e.
catchError :: forall label e es a. (HasCallStack, Labeled label (Error e) :> es) => Eff es a -> (CallStack -> e -> Eff es a) -> Eff es a
-- | The same as flip catchError, which is useful in
-- situations where the code for the handler is shorter.
handleError :: forall label e es a. (HasCallStack, Labeled label (Error e) :> es) => (CallStack -> e -> Eff es a) -> Eff es a -> Eff es a
-- | Similar to catchError, but returns an Either result
-- which is a Right if no error was thrown and a Left
-- otherwise.
tryError :: forall label e es a. (HasCallStack, Labeled label (Error e) :> es) => Eff es a -> Eff es (Either (CallStack, e) a)
-- | Request a CallStack.
--
-- NOTE: The implicit parameter ?callStack :: CallStack is an
-- implementation detail and should not be considered part of the
-- CallStack API, we may decide to change the implementation in
-- the future.
type HasCallStack = ?callStack :: CallStack
-- | CallStacks are a lightweight method of obtaining a partial
-- call-stack at any point in the program.
--
-- A function can request its call-site with the HasCallStack
-- constraint. For example, we can define
--
-- -- putStrLnWithCallStack :: HasCallStack => String -> IO () ---- -- as a variant of putStrLn that will get its call-site and -- print it, along with the string given as argument. We can access the -- call-stack inside putStrLnWithCallStack with -- callStack. -- --
-- >>> :{
-- putStrLnWithCallStack :: HasCallStack => String -> IO ()
-- putStrLnWithCallStack msg = do
-- putStrLn msg
-- putStrLn (prettyCallStack callStack)
-- :}
--
--
-- Thus, if we call putStrLnWithCallStack we will get a
-- formatted call-stack alongside our string.
--
-- -- >>> putStrLnWithCallStack "hello" -- hello -- CallStack (from HasCallStack): -- putStrLnWithCallStack, called at <interactive>:... in interactive:Ghci... ---- -- GHC solves HasCallStack constraints in three steps: -- --
-- putStrLnWithCallStack :: HasCallStack => String -> IO () ---- -- as a variant of putStrLn that will get its call-site and -- print it, along with the string given as argument. We can access the -- call-stack inside putStrLnWithCallStack with -- callStack. -- --
-- >>> :{
-- putStrLnWithCallStack :: HasCallStack => String -> IO ()
-- putStrLnWithCallStack msg = do
-- putStrLn msg
-- putStrLn (prettyCallStack callStack)
-- :}
--
--
-- Thus, if we call putStrLnWithCallStack we will get a
-- formatted call-stack alongside our string.
--
-- -- >>> putStrLnWithCallStack "hello" -- hello -- CallStack (from HasCallStack): -- putStrLnWithCallStack, called at <interactive>:... in interactive:Ghci... ---- -- GHC solves HasCallStack constraints in three steps: -- --
-- asks f ≡ f <$> ask --asks :: (HasCallStack, Reader r :> es) => (r -> a) -> Eff es a -- | Execute a computation in a modified environment. -- --
-- runReader r (local f m) ≡ runReader (f r) m --local :: (HasCallStack, Reader r :> es) => (r -> r) -> Eff es a -> Eff es a -- | The dynamically dispatched variant of the Reader effect. -- -- Note: unless you plan to change interpretations at runtime, -- it's recommended to use the statically dispatched variant, i.e. -- Effectful.Reader.Static. module Effectful.Reader.Dynamic data Reader r :: Effect [Ask] :: Reader r m r [Local] :: (r -> r) -> m a -> Reader r m a -- | Run the Reader effect with the given initial environment (via -- Effectful.Reader.Static). runReader :: HasCallStack => r -> Eff (Reader r : es) a -> Eff es a -- | Execute a computation in a modified environment. withReader :: HasCallStack => (r1 -> r2) -> Eff (Reader r2 : es) a -> Eff (Reader r1 : es) a -- | Fetch the value of the environment. ask :: (HasCallStack, Reader r :> es) => Eff es r -- | Retrieve a function of the current environment. -- --
-- asks f ≡ f <$> ask --asks :: (HasCallStack, Reader r :> es) => (r -> a) -> Eff es a -- | Execute a computation in a modified environment. -- --
-- runReader r (local f m) ≡ runReader (f r) m --local :: (HasCallStack, Reader r :> es) => (r -> r) -> Eff es a -> Eff es a -- | Convenience functions for the Labeled Reader effect. module Effectful.Labeled.Reader data Reader r :: Effect [Ask] :: Reader r m r [Local] :: (r -> r) -> m a -> Reader r m a -- | Run the Reader effect with the given initial environment (via -- Effectful.Reader.Static). runReader :: forall label r es a. HasCallStack => r -> Eff (Labeled label (Reader r) : es) a -> Eff es a -- | Fetch the value of the environment. ask :: forall label r es. (HasCallStack, Labeled label (Reader r) :> es) => Eff es r -- | Retrieve a function of the current environment. -- --
-- asks f ≡ f <$> ask --asks :: forall label r es a. (HasCallStack, Labeled label (Reader r) :> es) => (r -> a) -> Eff es a -- | Execute a computation in a modified environment. -- --
-- runReader r (local f m) ≡ runReader (f r) m --local :: forall label r es a. (HasCallStack, Labeled label (Reader r) :> es) => (r -> r) -> Eff es a -> Eff es a -- | Support for access to a mutable value of a particular type. -- -- The value is thread local. If you want it to be shared between -- threads, use Effectful.State.Static.Shared. -- -- Note: unlike the StateT monad transformer from the -- transformers library, the State effect doesn't discard -- state updates when an exception is received: -- --
-- >>> import Control.Exception (ErrorCall) -- -- >>> import Control.Monad.Catch -- -- >>> import Control.Monad.Trans.State.Strict qualified as S ---- --
-- >>> :{
-- (`S.execStateT` "Hi") . handle (\(_::ErrorCall) -> pure ()) $ do
-- S.modify (++ " there!")
-- error "oops"
-- :}
-- "Hi"
--
--
--
-- >>> :{
-- runEff . execState "Hi" . handle (\(_::ErrorCall) -> pure ()) $ do
-- modify (++ " there!")
-- error "oops"
-- :}
-- "Hi there!"
--
module Effectful.State.Static.Local
-- | Provide access to a strict (WHNF), thread local, mutable value of type
-- s.
data State (s :: Type) :: Effect
-- | Run the State effect with the given initial state and return
-- the final value along with the final state.
runState :: HasCallStack => s -> Eff (State s : es) a -> Eff es (a, s)
-- | Run the State effect with the given initial state and return
-- the final value, discarding the final state.
evalState :: HasCallStack => s -> Eff (State s : es) a -> Eff es a
-- | Run the State effect with the given initial state and return
-- the final state, discarding the final value.
execState :: HasCallStack => s -> Eff (State s : es) a -> Eff es s
-- | Fetch the current value of the state.
get :: (HasCallStack, State s :> es) => Eff es s
-- | Get a function of the current state.
--
-- -- gets f ≡ f <$> get --gets :: (HasCallStack, State s :> es) => (s -> a) -> Eff es a -- | Set the current state to the given value. put :: (HasCallStack, State s :> es) => s -> Eff es () -- | Apply the function to the current state and return a value. state :: (HasCallStack, State s :> es) => (s -> (a, s)) -> Eff es a -- | Apply the function to the current state. -- --
-- modify f ≡ state (\s -> ((), f s)) --modify :: (HasCallStack, State s :> es) => (s -> s) -> Eff es () -- | Apply the monadic function to the current state and return a value. stateM :: (HasCallStack, State s :> es) => (s -> Eff es (a, s)) -> Eff es a -- | Apply the monadic function to the current state. -- --
-- modifyM f ≡ stateM (\s -> ((), ) <$> f s) --modifyM :: (HasCallStack, State s :> es) => (s -> Eff es s) -> Eff es () -- | Support for access to a shared, mutable value of a particular type. -- -- The value is shared between multiple threads. If you want each thead -- to manage its own version of the value, use -- Effectful.State.Static.Local. -- -- Note: unlike the StateT monad transformer from the -- transformers library, the State effect doesn't discard -- state updates when an exception is received: -- --
-- >>> import Control.Exception (ErrorCall) -- -- >>> import Control.Monad.Catch -- -- >>> import Control.Monad.Trans.State.Strict qualified as S ---- --
-- >>> :{
-- (`S.execStateT` "Hi") . handle (\(_::ErrorCall) -> pure ()) $ do
-- S.modify (++ " there!")
-- error "oops"
-- :}
-- "Hi"
--
--
--
-- >>> :{
-- runEff . execState "Hi" . handle (\(_::ErrorCall) -> pure ()) $ do
-- modify (++ " there!")
-- error "oops"
-- :}
-- "Hi there!"
--
module Effectful.State.Static.Shared
-- | Provide access to a strict (WHNF), shared, mutable value of type
-- s.
data State (s :: Type) :: Effect
-- | Run the State effect with the given initial state and return
-- the final value along with the final state.
runState :: HasCallStack => s -> Eff (State s : es) a -> Eff es (a, s)
-- | Run the State effect with the given initial state and return
-- the final value, discarding the final state.
evalState :: HasCallStack => s -> Eff (State s : es) a -> Eff es a
-- | Run the State effect with the given initial state and return
-- the final state, discarding the final value.
execState :: HasCallStack => s -> Eff (State s : es) a -> Eff es s
-- | Run the State effect with the given initial state MVar'
-- and return the final value along with the final state.
runStateMVar :: HasCallStack => MVar' s -> Eff (State s : es) a -> Eff es (a, s)
-- | Run the State effect with the given initial state MVar'
-- and return the final value, discarding the final state.
evalStateMVar :: HasCallStack => MVar' s -> Eff (State s : es) a -> Eff es a
-- | Run the State effect with the given initial state MVar'
-- and return the final state, discarding the final value.
execStateMVar :: HasCallStack => MVar' s -> Eff (State s : es) a -> Eff es s
-- | Fetch the current value of the state.
get :: (HasCallStack, State s :> es) => Eff es s
-- | Get a function of the current state.
--
-- -- gets f ≡ f <$> get --gets :: (HasCallStack, State s :> es) => (s -> a) -> Eff es a -- | Set the current state to the given value. put :: (HasCallStack, State s :> es) => s -> Eff es () -- | Apply the function to the current state and return a value. -- -- Note: this function gets an exclusive access to the state for -- its duration. state :: (HasCallStack, State s :> es) => (s -> (a, s)) -> Eff es a -- | Apply the function to the current state. -- --
-- modify f ≡ state (\s -> ((), f s)) ---- -- Note: this function gets an exclusive access to the state for -- its duration. modify :: (HasCallStack, State s :> es) => (s -> s) -> Eff es () -- | Apply the monadic function to the current state and return a value. -- -- Note: this function gets an exclusive access to the state for -- its duration. stateM :: (HasCallStack, State s :> es) => (s -> Eff es (a, s)) -> Eff es a -- | Apply the monadic function to the current state. -- --
-- modifyM f ≡ stateM (\s -> ((), ) <$> f s) ---- -- Note: this function gets an exclusive access to the state for -- its duration. modifyM :: (HasCallStack, State s :> es) => (s -> Eff es s) -> Eff es () -- | The dynamically dispatched variant of the State effect. -- -- Note: unless you plan to change interpretations at runtime, -- it's recommended to use one of the statically dispatched variants, -- i.e. Effectful.State.Static.Local or -- Effectful.State.Static.Shared. module Effectful.State.Dynamic -- | Provide access to a mutable value of type s. data State s :: Effect [Get] :: State s m s [Put] :: s -> State s m () [State] :: (s -> (a, s)) -> State s m a [StateM] :: (s -> m (a, s)) -> State s m a -- | Run the State effect with the given initial state and return -- the final value along with the final state (via -- Effectful.State.Static.Local). runStateLocal :: HasCallStack => s -> Eff (State s : es) a -> Eff es (a, s) -- | Run the State effect with the given initial state and return -- the final value, discarding the final state (via -- Effectful.State.Static.Local). evalStateLocal :: HasCallStack => s -> Eff (State s : es) a -> Eff es a -- | Run the State effect with the given initial state and return -- the final state, discarding the final value (via -- Effectful.State.Static.Local). execStateLocal :: HasCallStack => s -> Eff (State s : es) a -> Eff es s -- | Run the State effect with the given initial state and return -- the final value along with the final state (via -- Effectful.State.Static.Shared). runStateShared :: HasCallStack => s -> Eff (State s : es) a -> Eff es (a, s) -- | Run the State effect with the given initial state and return -- the final value, discarding the final state (via -- Effectful.State.Static.Shared). evalStateShared :: HasCallStack => s -> Eff (State s : es) a -> Eff es a -- | Run the State effect with the given initial state and return -- the final state, discarding the final value (via -- Effectful.State.Static.Shared). execStateShared :: HasCallStack => s -> Eff (State s : es) a -> Eff es s -- | Fetch the current value of the state. get :: (HasCallStack, State s :> es) => Eff es s -- | Get a function of the current state. -- --
-- gets f ≡ f <$> get --gets :: (HasCallStack, State s :> es) => (s -> a) -> Eff es a -- | Set the current state to the given value. put :: (HasCallStack, State s :> es) => s -> Eff es () -- | Apply the function to the current state and return a value. state :: (HasCallStack, State s :> es) => (s -> (a, s)) -> Eff es a -- | Apply the function to the current state. -- --
-- modify f ≡ state (\s -> ((), f s)) --modify :: (HasCallStack, State s :> es) => (s -> s) -> Eff es () -- | Apply the monadic function to the current state and return a value. stateM :: (HasCallStack, State s :> es) => (s -> Eff es (a, s)) -> Eff es a -- | Apply the monadic function to the current state. -- --
-- modifyM f ≡ stateM (\s -> ((), ) <$> f s) --modifyM :: (HasCallStack, State s :> es) => (s -> Eff es s) -> Eff es () -- | Convenience functions for the Labeled State effect. module Effectful.Labeled.State -- | Provide access to a mutable value of type s. data State s :: Effect [Get] :: State s m s [Put] :: s -> State s m () [State] :: (s -> (a, s)) -> State s m a [StateM] :: (s -> m (a, s)) -> State s m a -- | Run the State effect with the given initial state and return -- the final value along with the final state (via -- Effectful.State.Static.Local). runStateLocal :: forall label s es a. HasCallStack => s -> Eff (Labeled label (State s) : es) a -> Eff es (a, s) -- | Run the State effect with the given initial state and return -- the final value, discarding the final state (via -- Effectful.State.Static.Local). evalStateLocal :: forall label s es a. HasCallStack => s -> Eff (Labeled label (State s) : es) a -> Eff es a -- | Run the State effect with the given initial state and return -- the final state, discarding the final value (via -- Effectful.State.Static.Local). execStateLocal :: forall label s es a. HasCallStack => s -> Eff (Labeled label (State s) : es) a -> Eff es s -- | Run the State effect with the given initial state and return -- the final value along with the final state (via -- Effectful.State.Static.Shared). runStateShared :: forall label s es a. HasCallStack => s -> Eff (Labeled label (State s) : es) a -> Eff es (a, s) -- | Run the State effect with the given initial state and return -- the final value, discarding the final state (via -- Effectful.State.Static.Shared). evalStateShared :: forall label s es a. HasCallStack => s -> Eff (Labeled label (State s) : es) a -> Eff es a -- | Run the State effect with the given initial state and return -- the final state, discarding the final value (via -- Effectful.State.Static.Shared). execStateShared :: forall label s es a. HasCallStack => s -> Eff (Labeled label (State s) : es) a -> Eff es s -- | Fetch the current value of the state. get :: forall label s es. (HasCallStack, Labeled label (State s) :> es) => Eff es s -- | Get a function of the current state. -- --
-- gets f ≡ f <$> get --gets :: forall label s es a. (HasCallStack, Labeled label (State s) :> es) => (s -> a) -> Eff es a -- | Set the current state to the given value. put :: forall label s es. (HasCallStack, Labeled label (State s) :> es) => s -> Eff es () -- | Apply the function to the current state and return a value. state :: forall label s es a. (HasCallStack, Labeled label (State s) :> es) => (s -> (a, s)) -> Eff es a -- | Apply the function to the current state. -- --
-- modify f ≡ state (\s -> ((), f s)) --modify :: forall label s es. (HasCallStack, Labeled label (State s) :> es) => (s -> s) -> Eff es () -- | Apply the monadic function to the current state and return a value. stateM :: forall label s es a. (HasCallStack, Labeled label (State s) :> es) => (s -> Eff es (a, s)) -> Eff es a -- | Apply the monadic function to the current state. -- --
-- modifyM f ≡ stateM (\s -> ((), ) <$> f s) --modifyM :: forall label s es. (HasCallStack, Labeled label (State s) :> es) => (s -> Eff es s) -> Eff es () -- | Support for access to a write only value of a particular type. -- -- The value is thread local. If you want it to be shared between -- threads, use Effectful.Writer.Static.Shared. -- -- Warning: Writer's state will be accumulated via -- left-associated uses of <>, which makes it -- unsuitable for use with types for which such pattern is inefficient. -- This applies, in particular, to the standard list type, which -- makes the Writer effect pretty niche. -- -- Note: while the Writer from the transformers -- package includes additional operations pass and censor, -- they don't cooperate with runtime exceptions very well, so they're -- deliberately omitted here. module Effectful.Writer.Static.Local -- | Provide access to a strict (WHNF), thread local, write only value of -- type w. data Writer (w :: Type) :: Effect -- | Run a Writer effect and return the final value along with the -- final output. runWriter :: (HasCallStack, Monoid w) => Eff (Writer w : es) a -> Eff es (a, w) -- | Run a Writer effect and return the final output, discarding the -- final value. execWriter :: (HasCallStack, Monoid w) => Eff (Writer w : es) a -> Eff es w -- | Append the given output to the overall output of the Writer. tell :: (HasCallStack, Writer w :> es, Monoid w) => w -> Eff es () -- | Execute an action and append its output to the overall output of the -- Writer. -- -- Note: if an exception is received while the action is executed, -- the partial output of the action will still be appended to the overall -- output of the Writer: -- --
-- >>> :{
-- runEff . execWriter @String $ do
-- tell "Hi"
-- handle (\(_::ErrorCall) -> pure ((), "")) $ do
-- tell " there"
-- listen $ do
-- tell "!"
-- error "oops"
-- :}
-- "Hi there!"
--
listen :: (HasCallStack, Writer w :> es, Monoid w) => Eff es a -> Eff es (a, w)
-- | Execute an action and append its output to the overall output of the
-- Writer, then return the final value along with a function of
-- the recorded output.
--
-- -- listens f m ≡ second f <$> listen m --listens :: (HasCallStack, Writer w :> es, Monoid w) => (w -> b) -> Eff es a -> Eff es (a, b) -- | Support for access to a write only value of a particular type. -- -- The value is shared between multiple threads. If you want each thead -- to manage its own version of the value, use -- Effectful.Writer.Static.Local. -- -- Warning: Writer's state will be accumulated via -- left-associated uses of <>, which makes it -- unsuitable for use with types for which such pattern is inefficient. -- This applies, in particular, to the standard list type, which -- makes the Writer effect pretty niche. -- -- Note: while the Writer from the transformers -- package includes additional operations pass and censor, -- they don't cooperate with runtime exceptions very well, so they're -- deliberately omitted here. module Effectful.Writer.Static.Shared -- | Provide access to a strict (WHNF), shared, write only value of type -- w. data Writer (w :: Type) :: Effect -- | Run a Writer effect and return the final value along with the -- final output. runWriter :: (HasCallStack, Monoid w) => Eff (Writer w : es) a -> Eff es (a, w) -- | Run a Writer effect and return the final output, discarding the -- final value. execWriter :: (HasCallStack, Monoid w) => Eff (Writer w : es) a -> Eff es w -- | Append the given output to the overall output of the Writer. tell :: (HasCallStack, Writer w :> es, Monoid w) => w -> Eff es () -- | Execute an action and append its output to the overall output of the -- Writer. -- -- Note: if an exception is received while the action is executed, -- the partial output of the action will still be appended to the overall -- output of the Writer: -- --
-- >>> :{
-- runEff . execWriter @String $ do
-- tell "Hi"
-- handle (\(_::ErrorCall) -> pure ((), "")) $ do
-- tell " there"
-- listen $ do
-- tell "!"
-- error "oops"
-- :}
-- "Hi there!"
--
listen :: (HasCallStack, Writer w :> es, Monoid w) => Eff es a -> Eff es (a, w)
-- | Execute an action and append its output to the overall output of the
-- Writer, then return the final value along with a function of
-- the recorded output.
--
-- -- listens f m ≡ second f <$> listen m --listens :: (HasCallStack, Writer w :> es, Monoid w) => (w -> b) -> Eff es a -> Eff es (a, b) -- | The dynamically dispatched variant of the Writer effect. -- -- Note: unless you plan to change interpretations at runtime, -- it's recommended to use one of the statically dispatched variants, -- i.e. Effectful.Writer.Static.Local or -- Effectful.Writer.Static.Shared. module Effectful.Writer.Dynamic -- | Provide access to a write only value of type w. data Writer w :: Effect [Tell] :: w -> Writer w m () [Listen] :: m a -> Writer w m (a, w) -- | Run the Writer effect and return the final value along with the -- final output (via Effectful.Writer.Static.Local). runWriterLocal :: (HasCallStack, Monoid w) => Eff (Writer w : es) a -> Eff es (a, w) -- | Run a Writer effect and return the final output, discarding the -- final value (via Effectful.Writer.Static.Local). execWriterLocal :: (HasCallStack, Monoid w) => Eff (Writer w : es) a -> Eff es w -- | Run the Writer effect and return the final value along with the -- final output (via Effectful.Writer.Static.Shared). runWriterShared :: (HasCallStack, Monoid w) => Eff (Writer w : es) a -> Eff es (a, w) -- | Run the Writer effect and return the final output, discarding -- the final value (via Effectful.Writer.Static.Shared). execWriterShared :: (HasCallStack, Monoid w) => Eff (Writer w : es) a -> Eff es w -- | Append the given output to the overall output of the Writer. tell :: (HasCallStack, Writer w :> es) => w -> Eff es () -- | Execute an action and append its output to the overall output of the -- Writer. listen :: (HasCallStack, Writer w :> es) => Eff es a -> Eff es (a, w) -- | Execute an action and append its output to the overall output of the -- Writer, then return the final value along with a function of -- the recorded output. -- --
-- listens f m ≡ second f <$> listen m --listens :: (HasCallStack, Writer w :> es) => (w -> b) -> Eff es a -> Eff es (a, b) -- | Convenience functions for the Labeled Writer effect. module Effectful.Labeled.Writer -- | Provide access to a write only value of type w. data Writer w :: Effect [Tell] :: w -> Writer w m () [Listen] :: m a -> Writer w m (a, w) -- | Run the Writer effect and return the final value along with the -- final output (via Effectful.Writer.Static.Local). runWriterLocal :: forall label w es a. (HasCallStack, Monoid w) => Eff (Labeled label (Writer w) : es) a -> Eff es (a, w) -- | Run a Writer effect and return the final output, discarding the -- final value (via Effectful.Writer.Static.Local). execWriterLocal :: forall label w es a. (HasCallStack, Monoid w) => Eff (Labeled label (Writer w) : es) a -> Eff es w -- | Run the Writer effect and return the final value along with the -- final output (via Effectful.Writer.Static.Shared). runWriterShared :: forall label w es a. (HasCallStack, Monoid w) => Eff (Labeled label (Writer w) : es) a -> Eff es (a, w) -- | Run the Writer effect and return the final output, discarding -- the final value (via Effectful.Writer.Static.Shared). execWriterShared :: forall label w es a. (HasCallStack, Monoid w) => Eff (Labeled label (Writer w) : es) a -> Eff es w -- | Append the given output to the overall output of the Writer. tell :: forall label w es. (HasCallStack, Labeled label (Writer w) :> es) => w -> Eff es () -- | Execute an action and append its output to the overall output of the -- Writer. listen :: forall label w es a. (HasCallStack, Labeled label (Writer w) :> es) => Eff es a -> Eff es (a, w) -- | Execute an action and append its output to the overall output of the -- Writer, then return the final value along with a function of -- the recorded output. -- --
-- listens f m ≡ second f <$> listen m --listens :: forall label w es a b. (HasCallStack, Labeled label (Writer w) :> es) => (w -> b) -> Eff es a -> Eff es (a, b)