effectful-core 2.5.1.0 → 2.6.1.0
raw patch · 17 files changed
Files
- CHANGELOG.md +15/−0
- README.md +2/−2
- effectful-core.cabal +5/−2
- src/Effectful.hs +1/−1
- src/Effectful/Dispatch/Dynamic.hs +36/−4
- src/Effectful/Dispatch/Static/Unsafe.hs +0/−47
- src/Effectful/Error/Dynamic.hs +4/−10
- src/Effectful/Error/Static.hs +4/−1
- src/Effectful/Exception.hs +22/−0
- src/Effectful/Internal/Effect.hs +0/−1
- src/Effectful/Internal/Env.hs +2/−6
- src/Effectful/Internal/MTL.hs +90/−0
- src/Effectful/Internal/Monad.hs +84/−35
- src/Effectful/Internal/Utils.hs +12/−1
- src/Effectful/Reader/Dynamic.hs +13/−14
- src/Effectful/State/Dynamic.hs +4/−11
- src/Effectful/Writer/Dynamic.hs +5/−9
CHANGELOG.md view
@@ -1,3 +1,18 @@+# effectful-core-2.6.1.0 (2025-08-30)+* Add `MonadError`, `MonadReader`, `MonadState` and `MonadWriter` instances for+ `Eff` for compatibility with existing code.++# effectful-core-2.6.0.0 (2025-06-13)+* Adjust `generalBracket` with `base >= 4.21` to make use of the new exception+ annotation mechanism.+* Add `withException` to `Effectful.Exception`.+* Deprecate `Effectful.Reader.Dynamic.withReader` as it doesn't work correctly+ for all potential interpreters.+* **Breaking changes**:+ - Change the order of type parameters in `raise` for better usability.+ - `Effectful.Error.Static.ErrorWrapper` is no longer caught by `catchSync`.+ - Remove deprecated function `Effectful.withConcEffToIO`.+ # effectful-core-2.5.1.0 (2024-11-27) * Add `passthrough` to `Effectful.Dispatch.Dynamic` for passing operations to the upstream handler within `interpose` and `impose` without having to fully
README.md view
@@ -1,12 +1,12 @@ # effectful -[](https://github.com/haskell-effectful/effectful/actions?query=branch%3Amaster)+[](https://github.com/haskell-effectful/effectful/actions/workflows/haskell-ci.yml) [](https://hackage.haskell.org/package/effectful) [](https://www.stackage.org/lts/package/effectful) [](https://www.stackage.org/nightly/package/effectful) -<img src="https://user-images.githubusercontent.com/387658/127747903-f728437f-2ee4-47b8-9f0c-5102fd44c8e4.png" width="128">+<img src="https://raw.githubusercontent.com/haskell-effectful/effectful/master/logo.svg" width="150"> An easy to use, fast extensible effects library with seamless integration with the existing Haskell ecosystem.
effectful-core.cabal view
@@ -1,7 +1,7 @@ cabal-version: 3.0 build-type: Simple name: effectful-core-version: 2.5.1.0+version: 2.6.1.0 license: BSD-3-Clause license-file: LICENSE category: Control@@ -21,7 +21,7 @@ CHANGELOG.md README.md -tested-with: GHC == { 8.10.7, 9.0.2, 9.2.8, 9.4.8, 9.6.5, 9.8.3, 9.10.1, 9.12.1 }+tested-with: GHC == { 8.10.7, 9.0.2, 9.2.8, 9.4.8, 9.6.7, 9.8.4, 9.10.2, 9.12.2, 9.14.1 } bug-reports: https://github.com/haskell-effectful/effectful/issues source-repository head@@ -60,6 +60,7 @@ TypeApplications TypeFamilies TypeOperators+ UndecidableInstances library import: language@@ -70,6 +71,7 @@ , containers >= 0.6 , deepseq >= 1.2 , exceptions >= 0.10.4+ , mtl >= 2.2.1 , monad-control >= 1.0.3 , primitive >= 0.7.3.0 , strict-mutable-base >= 1.1.0.0@@ -92,6 +94,7 @@ Effectful.Fail Effectful.Internal.Effect Effectful.Internal.Env+ Effectful.Internal.MTL Effectful.Internal.Monad Effectful.Internal.Unlift Effectful.Internal.Utils
src/Effectful.hs view
@@ -46,7 +46,6 @@ , withUnliftStrategy , withSeqEffToIO , withEffToIO- , withConcEffToIO -- ** Lifting , raise@@ -65,6 +64,7 @@ import Effectful.Internal.Effect import Effectful.Internal.Env+import Effectful.Internal.MTL () import Effectful.Internal.Monad -- $intro
src/Effectful/Dispatch/Dynamic.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE ImplicitParams #-}-{-# LANGUAGE UndecidableInstances #-} -- | Dynamically dispatched effects. module Effectful.Dispatch.Dynamic ( -- * Introduction@@ -349,8 +348,6 @@ -- __orphan__, __canonical__ instance of @MonadRNG@ for 'Eff' that delegates to -- the @RNG@ effect: ----- >>> :set -XUndecidableInstances--- -- >>> :{ -- instance RNG :> es => MonadRNG (Eff es) where -- randomInt = send RandomInt@@ -466,6 +463,41 @@ -- | Interpret an effect using other, private effects. -- -- @'interpret' ≡ 'reinterpret' 'id'@+--+-- /Note:/ If you want to interpret multiple effects using other, private+-- effects, you can do so with a combination of 'interpret' and 'inject'.+--+-- This is in particular useful for splitting a large effect into smaller+-- ones. For example, let's say you want to split a+-- t'Effectful.State.Static.Local.State' into a read only and read write+-- component:+--+-- >>> :{+-- data Get s :: Effect where+-- Get :: Get s m s+-- type instance DispatchOf (Get s) = Dynamic+-- :}+--+-- >>> :{+-- data Put s :: Effect where+-- Put :: s -> Put s m ()+-- type instance DispatchOf (Put s) = Dynamic+-- :}+--+-- >>> import Effectful.State.Static.Local qualified as S+--+-- >>> :{+-- runGetPut :: forall s es a. s -> Eff (Get s : Put s : es) a -> Eff es (a, s)+-- runGetPut s0+-- = S.runState s0+-- . interpret_ @(Put s) (\(Put s) -> S.put s)+-- . interpret_ @(Get s) (\Get -> S.get)+-- . inject+-- :}+--+-- Here, a t'Effectful.State.Static.Local.State' effect is introduced, then+-- @Put@ and @Get@ effects that use it underneath and finally 'inject' hides the+-- original state from downstream code. reinterpret :: (HasCallStack, DispatchOf e ~ Dynamic) => (Eff handlerEs a -> Eff es b)@@ -539,7 +571,7 @@ -- -- >>> runEff . runE . augmentOp2 $ send Op3 -- *** Exception: Op3 not implemented--- CallStack (from HasCallStack):+-- ... -- error, called at <interactive>:... -- handler, called at src/Effectful/Dispatch/Dynamic.hs:... -- passthrough, called at <interactive>:...
src/Effectful/Dispatch/Static/Unsafe.hs view
@@ -5,50 +5,3 @@ ) where import Effectful.Internal.Monad---- | Utility for lifting 'IO' computations of type------ @'IO' a -> 'IO' b@------ to------ @'Eff' es a -> 'Eff' es b@------ This function is __really unsafe__ because:------ - It can be used to introduce arbitrary 'IO' actions into pure 'Eff'--- computations.------ - The 'IO' computation must run its argument in a way that's perceived as--- sequential to the outside observer, e.g. in the same thread or in a worker--- thread that finishes before the argument is run again.------ __Warning:__ if you disregard the second point, you will experience weird--- bugs, data races or internal consistency check failures.------ When in doubt, use 'Effectful.Dispatch.Static.unsafeLiftMapIO', especially--- since this version saves only a simple safety check per call of--- @reallyUnsafeLiftMapIO f@.-reallyUnsafeLiftMapIO :: (IO a -> IO b) -> Eff es a -> Eff es b-reallyUnsafeLiftMapIO f m = unsafeEff $ \es -> f (unEff m es)---- | Create an unlifting function.------ This function is __really unsafe__ because:------ - It can be used to introduce arbitrary 'IO' actions into pure 'Eff'--- computations.------ - Unlifted 'Eff' computations must be run in a way that's perceived as--- sequential to the outside observer, e.g. in the same thread as the caller--- of 'reallyUnsafeUnliftIO' or in a worker thread that finishes before--- another unlifted computation is run.------ __Warning:__ if you disregard the second point, you will experience weird--- bugs, data races or internal consistency check failures.------ When in doubt, use 'Effectful.Dispatch.Static.unsafeSeqUnliftIO', especially--- since this version saves only a simple safety check per call of the unlifting--- function.-reallyUnsafeUnliftIO :: ((forall r. Eff es r -> IO r) -> IO a) -> Eff es a-reallyUnsafeUnliftIO k = unsafeEff $ \es -> k (`unEff` es)
src/Effectful/Error/Dynamic.hs view
@@ -1,7 +1,8 @@ -- | 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,+-- /Note:/ unless you plan to change interpretations at runtime or you need the+-- t'Control.Monad.Except.MonadError' instance for compatibility with existing+-- code, it's recommended to use the statically dispatched variant, -- i.e. "Effectful.Error.Static". module Effectful.Error.Dynamic ( -- * Effect@@ -33,14 +34,7 @@ import Effectful import Effectful.Dispatch.Dynamic import Effectful.Error.Static qualified as E---- | Provide the ability to handle errors of type @e@.-data Error e :: Effect where- -- | @since 2.4.0.0- ThrowErrorWith :: (e -> String) -> e -> Error e m a- CatchError :: m a -> (E.CallStack -> e -> m a) -> Error e m a--type instance DispatchOf (Error e) = Dynamic+import Effectful.Internal.MTL (Error(..)) -- | Handle errors of type @e@ (via "Effectful.Error.Static"). runError
src/Effectful/Error/Static.hs view
@@ -247,7 +247,10 @@ . ("\n" ++) . (prettyCallStack cs ++) -instance Exception ErrorWrapper+instance Exception ErrorWrapper where+ -- See discussion in https://github.com/haskell-effectful/effectful/pull/232.+ toException = asyncExceptionToException+ fromException = asyncExceptionFromException matchError :: ErrorId -> ErrorWrapper -> Maybe (CallStack, e) matchError eid (ErrorWrapper etag cs _ e)
src/Effectful/Exception.hs view
@@ -59,6 +59,7 @@ , C.ExitCase(..) , finally , onException+ , withException -- * Utils @@ -511,6 +512,27 @@ -> Eff es a onException action handler = reallyUnsafeUnliftIO $ \unlift -> do E.onException (unlift action) (unlift handler)++-- | A variant of 'onException' that gives access to the exception.+--+-- @since 2.6.0.0+withException+ :: E.Exception e+ => Eff es a+ -> (e -> Eff es b)+ -- ^ Computation to run last when an exception or+ -- t'Effectful.Error.Static.Error' was thrown.+ -> Eff es a+withException action cleanup = do+#if MIN_VERSION_base(4,21,0)+ action `catchNoPropagate` \ec@(E.ExceptionWithContext _ e) -> do+ _ <- annotateIO (E.WhileHandling (E.toException ec)) (cleanup e)+ rethrowIO ec+#else+ action `catch` \e -> do+ _ <- cleanup e+ throwIO e+#endif ---------------------------------------- -- Utils
src/Effectful/Internal/Effect.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_HADDOCK not-home #-} -- | Type-safe indexing for 'Effectful.Internal.Monad.Env'. --
src/Effectful/Internal/Env.hs view
@@ -439,7 +439,7 @@ ++ show storageVersion ++ ")\n" ++ "If you're attempting to run an unlifting function outside " ++ "of the scope of effects it captures, have a look at "- ++ "UnliftingStrategy (SeqForkUnlift)."+ ++ "UnliftStrategy (SeqForkUnlift)." pure (ref, es) where Ref ref version = indexPrimArray refs (offset + reifyIndex @e @es)@@ -477,7 +477,7 @@ Storage (bumpVersion version) (StorageData (size + 1) vs0 es0 fs0) pure $ Ref size version EQ -> do- let len = doubleCapacity len0+ let len = growCapacity len0 vs <- newPrimArray len es <- newSmallArray len undefinedEffect fs <- newSmallArray len undefinedRelinker@@ -510,10 +510,6 @@ -- | Relink the environment to use the new storage. relinkEnv :: IORef' Storage -> Env es -> IO (Env es) relinkEnv storage (Env offset refs _) = pure $ Env offset refs storage---- | Double the capacity of an array.-doubleCapacity :: Int -> Int-doubleCapacity n = max 1 n * 2 undefinedVersion :: Version undefinedVersion = Version 0
+ src/Effectful/Internal/MTL.hs view
@@ -0,0 +1,90 @@+{-# OPTIONS_GHC -Wno-orphans #-}+-- | Definitions and instances for MTL compatibility.+--+-- This module is intended for internal use only, and may change without warning+-- in subsequent releases.+module Effectful.Internal.MTL where++import Control.Monad.Except qualified as MTL+import Control.Monad.Reader qualified as MTL+import Control.Monad.State qualified as MTL+import Control.Monad.Writer qualified as MTL+import GHC.Stack (CallStack)++import Effectful.Internal.Effect+import Effectful.Internal.Env+import Effectful.Internal.Monad++-- | Provide the ability to handle errors of type @e@.+data Error e :: Effect where+ -- | @since 2.4.0.0+ ThrowErrorWith :: (e -> String) -> e -> Error e m a+ CatchError :: m a -> (CallStack -> e -> m a) -> Error e m a++type instance DispatchOf (Error e) = Dynamic++-- | Instance included for compatibility with existing code.+instance+ ( Show e+ , Error e :> es+ , MTL.MonadError e (Eff es)+ ) => MTL.MonadError e (Eff es) where+ throwError = send . ThrowErrorWith show+ catchError action = send . CatchError action . const++----------------------------------------++data Reader r :: Effect where+ Ask :: Reader r m r+ Local :: (r -> r) -> m a -> Reader r m a++type instance DispatchOf (Reader r) = Dynamic++-- | Instance included for compatibility with existing code.+instance+ ( Reader r :> es+ , MTL.MonadReader r (Eff es)+ ) => MTL.MonadReader r (Eff es) where+ ask = send Ask+ local f = send . Local f+ reader f = f <$> send Ask++----------------------------------------++-- | Provide access to a mutable value of type @s@.+data State s :: Effect where+ 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++type instance DispatchOf (State s) = Dynamic++-- | Instance included for compatibility with existing code.+instance+ ( State s :> es+ , MTL.MonadState s (Eff es)+ ) => MTL.MonadState s (Eff es) where+ get = send Get+ put = send . Put+ state = send . State++----------------------------------------++-- | Provide access to a write only value of type @w@.+data Writer w :: Effect where+ Tell :: w -> Writer w m ()+ Listen :: m a -> Writer w m (a, w)++type instance DispatchOf (Writer w) = Dynamic++-- | Instance included for compatibility with existing code.+instance+ ( Monoid w+ , Writer w :> es+ , MTL.MonadWriter w (Eff es)+ ) => MTL.MonadWriter w (Eff es) where+ writer (a, w) = a <$ send (Tell w)+ tell = send . Tell+ listen = send . Listen+ pass = error "pass is not implemented due to ambiguous semantics in presence of runtime exceptions"
src/Effectful/Internal/Monad.hs view
@@ -1,5 +1,4 @@-{-# LANGUAGE UndecidableInstances #-}-{-# OPTIONS_GHC -Wno-noncanonical-monad-instances #-}+{-# LANGUAGE CPP #-} {-# OPTIONS_GHC -Wno-orphans #-} {-# OPTIONS_HADDOCK not-home #-} -- | The 'Eff' monad.@@ -46,7 +45,8 @@ , withUnliftStrategy , withSeqEffToIO , withEffToIO- , withConcEffToIO+ , reallyUnsafeLiftMapIO+ , reallyUnsafeUnliftIO -- ** Low-level unlifts , seqUnliftIO@@ -203,20 +203,6 @@ ConcUnlift p b -> unsafeEff $ \es -> concUnliftIO es p b k {-# INLINE withEffToIO #-} --- | Create an unlifting function with the 'ConcUnlift' strategy.------ @since 2.2.2.0-withConcEffToIO- :: (HasCallStack, IOE :> es)- => Persistence- -> Limit- -> ((forall r. Eff es r -> IO r) -> IO a)- -- ^ Continuation with the unlifting function in scope.- -> Eff es a-withConcEffToIO persistence limit k = unsafeEff $ \es ->- concUnliftIO es persistence limit k-{-# DEPRECATED withConcEffToIO "Use withEffToIO with the appropriate strategy." #-}- -- | Create an unlifting function with the 'SeqUnlift' strategy. seqUnliftIO :: HasCallStack@@ -261,6 +247,53 @@ concUnliftIO es Persistent (Limited threads) = persistentConcUnlift es False threads concUnliftIO es Persistent Unlimited = persistentConcUnlift es True maxBound +-- | Utility for lifting 'IO' computations of type+--+-- @'IO' a -> 'IO' b@+--+-- to+--+-- @'Eff' es a -> 'Eff' es b@+--+-- This function is __really unsafe__ because:+--+-- - It can be used to introduce arbitrary 'IO' actions into pure 'Eff'+-- computations.+--+-- - The 'IO' computation must run its argument in a way that's perceived as+-- sequential to the outside observer, e.g. in the same thread or in a worker+-- thread that finishes before the argument is run again.+--+-- __Warning:__ if you disregard the second point, you will experience weird+-- bugs, data races or internal consistency check failures.+--+-- When in doubt, use 'Effectful.Dispatch.Static.unsafeLiftMapIO', especially+-- since this version saves only a simple safety check per call of+-- @reallyUnsafeLiftMapIO f@.+reallyUnsafeLiftMapIO :: (IO a -> IO b) -> Eff es a -> Eff es b+reallyUnsafeLiftMapIO f m = unsafeEff $ \es -> f (unEff m es)++-- | Create an unlifting function.+--+-- This function is __really unsafe__ because:+--+-- - It can be used to introduce arbitrary 'IO' actions into pure 'Eff'+-- computations.+--+-- - Unlifted 'Eff' computations must be run in a way that's perceived as+-- sequential to the outside observer, e.g. in the same thread as the caller+-- of 'reallyUnsafeUnliftIO' or in a worker thread that finishes before+-- another unlifted computation is run.+--+-- __Warning:__ if you disregard the second point, you will experience weird+-- bugs, data races or internal consistency check failures.+--+-- When in doubt, use 'Effectful.Dispatch.Static.unsafeSeqUnliftIO', especially+-- since this version saves only a simple safety check per call of the unlifting+-- function.+reallyUnsafeUnliftIO :: ((forall r. Eff es r -> IO r) -> IO a) -> Eff es a+reallyUnsafeUnliftIO k = unsafeEff $ \es -> k (`unEff` es)+ ---------------------------------------- -- Base @@ -276,10 +309,9 @@ liftA2 f (Eff ma) (Eff mb) = unsafeEff $ \es -> liftA2 f (ma es) (mb es) instance Monad (Eff es) where- return = unsafeEff_ . pure Eff m >>= k = unsafeEff $ \es -> m es >>= \a -> unEff (k a) es -- https://gitlab.haskell.org/ghc/ghc/-/issues/20008- Eff ma >> Eff mb = unsafeEff $ \es -> ma es >> mb es+ {-# INLINE (>>=) #-} instance MonadFix (Eff es) where mfix f = unsafeEff $ \es -> mfix $ \a -> unEff (f a) es@@ -290,6 +322,10 @@ -- | Provide the ability to use the 'Alternative' and 'MonadPlus' instance for -- 'Eff'. --+-- /Note:/ 'NonDet' does not backtrack. Formally, it obeys the "left-catch" law+-- for 'MonadPlus', rather than the "left-distribution" law. This means that it+-- behaves more like 'Maybe' than @[]@.+-- -- @since 2.2.0.0 data NonDet :: Effect where Empty :: NonDet m a@@ -309,27 +345,40 @@ -- Exception instance C.MonadThrow (Eff es) where- throwM = unsafeEff_ . E.throwIO+ throwM = unsafeEff_ . withFrozenCallStack E.throwIO instance C.MonadCatch (Eff es) where- catch m handler = unsafeEff $ \es -> do- unEff m es `E.catch` \e -> do- unEff (handler e) es+ catch action handler = reallyUnsafeUnliftIO $ \unlift -> do+ E.catch (unlift action) (unlift . handler) instance C.MonadMask (Eff es) where- mask k = unsafeEff $ \es -> E.mask $ \unmask ->- unEff (k $ \m -> unsafeEff $ unmask . unEff m) es+ mask k = reallyUnsafeUnliftIO $ \unlift -> do+ E.mask $ \release -> unlift $ k (reallyUnsafeLiftMapIO release) - uninterruptibleMask k = unsafeEff $ \es -> E.uninterruptibleMask $ \unmask ->- unEff (k $ \m -> unsafeEff $ unmask . unEff m) es+ uninterruptibleMask k = reallyUnsafeUnliftIO $ \unlift -> do+ E.uninterruptibleMask $ \release -> unlift $ k (reallyUnsafeLiftMapIO release) - generalBracket acquire release use = unsafeEff $ \es -> E.mask $ \unmask -> do- resource <- unEff acquire es- b <- unmask (unEff (use resource) es) `E.catch` \e -> do- _ <- unEff (release resource $ C.ExitCaseException e) es- E.throwIO e- c <- unEff (release resource $ C.ExitCaseSuccess b) es- pure (b, c)+ generalBracket before after action = reallyUnsafeUnliftIO $ \unlift -> do+ E.mask $ \unmask -> do+ a <- unlift before+#if MIN_VERSION_base(4,21,0)+ b <- E.catchNoPropagate+ (unmask . unlift $ action a)+ (\ec@(E.ExceptionWithContext _ e) -> do+ _ <- E.annotateIO (E.WhileHandling (E.toException ec)) $ do+ unlift . after a $ C.ExitCaseException e+ E.rethrowIO ec+ )+#else+ b <- E.catch+ (unmask . unlift $ action a)+ (\e -> do+ _ <- unlift . after a $ C.ExitCaseException e+ E.throwIO e+ )+#endif+ c <- unlift . after a $ C.ExitCaseSuccess b+ pure (b, c) ---------------------------------------- -- Fail@@ -418,7 +467,7 @@ -- Lifting -- | Lift an 'Eff' computation into an effect stack with one more effect.-raise :: Eff es a -> Eff (e : es) a+raise :: forall e es a. Eff es a -> Eff (e : es) a raise m = unsafeEff $ \es -> unEff m =<< tailEnv es -- | Lift an 'Eff' computation into an effect stack with one more effect and
src/Effectful/Internal/Utils.hs view
@@ -18,8 +18,11 @@ , Unique , newUnique - -- * CallStack+ -- * CallStack , thawCallStack++ -- * Array capacity+ , growCapacity ) where import Control.Exception@@ -129,3 +132,11 @@ thawCallStack = \case FreezeCallStack cs -> cs cs -> cs++----------------------------------------++-- | Grow capacity of an array.+--+-- See https://archive.ph/Z2R8w.+growCapacity :: Int -> Int+growCapacity n = 1 + quot (n * 3) 2
src/Effectful/Reader/Dynamic.hs view
@@ -1,7 +1,8 @@ -- | 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,+-- /Note:/ unless you plan to change interpretations at runtime or you need the+-- t'Control.Monad.Reader.MonadReader' instance for compatibility with existing+-- code, it's recommended to use the statically dispatched variant, -- i.e. "Effectful.Reader.Static". module Effectful.Reader.Dynamic ( -- * Effect@@ -19,24 +20,21 @@ import Effectful import Effectful.Dispatch.Dynamic-import Effectful.Reader.Static qualified as R--data Reader r :: Effect where- Ask :: Reader r m r- Local :: (r -> r) -> m a -> Reader r m a--type instance DispatchOf (Reader r) = Dynamic+import Effectful.Internal.MTL (Reader(..)) --- | Run the 'Reader' effect with the given initial environment (via--- "Effectful.Reader.Static").+-- | Run the 'Reader' effect with the given initial environment. runReader :: HasCallStack => r -- ^ The initial environment. -> Eff (Reader r : es) a -> Eff es a-runReader r = reinterpret (R.runReader r) $ \env -> \case- Ask -> R.ask- Local f m -> localSeqUnlift env $ \unlift -> R.local f (unlift m)+runReader r0 = interpret $ handler r0+ where+ handler :: r -> EffectHandler (Reader r) es+ handler r env = \case+ Ask -> pure r+ Local f action -> localSeqUnlift env $ \unlift -> do+ unlift $ interpose (handler $ f r) action -- | Execute a computation in a modified environment. --@@ -51,6 +49,7 @@ withReader f m = do r <- ask raise $ runReader (f r) m+{-# DEPRECATED withReader "withReader doesn't work correctly for all potential interpreters" #-} ---------------------------------------- -- Operations
src/Effectful/State/Dynamic.hs view
@@ -1,7 +1,8 @@ -- | 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,+-- /Note:/ unless you plan to change interpretations at runtime or you need the+-- t'Control.Monad.State.MonadState' instance for compatibility with existing+-- code, 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 ( -- * Effect@@ -31,17 +32,9 @@ import Effectful import Effectful.Dispatch.Dynamic+import Effectful.Internal.MTL (State(..)) import Effectful.State.Static.Local qualified as L import Effectful.State.Static.Shared qualified as S---- | Provide access to a mutable value of type @s@.-data State s :: Effect where- 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--type instance DispatchOf (State s) = Dynamic ---------------------------------------- -- Local
src/Effectful/Writer/Dynamic.hs view
@@ -1,7 +1,9 @@+{-# OPTIONS_GHC -Wno-orphans #-} -- | 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,+-- /Note:/ unless you plan to change interpretations at runtime or you need the+-- t'Control.Monad.Writer.MonadWriter' instance for compatibility with existing+-- code, 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 ( -- * Effect@@ -25,15 +27,9 @@ import Effectful import Effectful.Dispatch.Dynamic+import Effectful.Internal.MTL (Writer(..)) import Effectful.Writer.Static.Local qualified as L import Effectful.Writer.Static.Shared qualified as S---- | Provide access to a write only value of type @w@.-data Writer w :: Effect where- Tell :: w -> Writer w m ()- Listen :: m a -> Writer w m (a, w)--type instance DispatchOf (Writer w) = Dynamic ---------------------------------------- -- Local