packages feed

effectful 2.0.0.0 → 2.1.0.0

raw patch · 5 files changed

+49/−18 lines, 5 filesdep ~effectful-corePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: effectful-core

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,3 +1,9 @@+# effectful-2.1.0.0 (2022-08-22)+* Include the `e :> localEs` constraint in the `EffectHandler` to allow more+  flexibility in handling higher order effects.+* Do not include internal stack frames in `throwError` from+  `Effectful.Error.Dynamic`.+ # effectful-2.0.0.0 (2022-08-12) * Make storage references in the environment immutable. * Remove `checkSizeEnv` and `forkEnv` from
effectful.cabal view
@@ -1,7 +1,7 @@ cabal-version:      2.4 build-type:         Simple name:               effectful-version:            2.0.0.0+version:            2.1.0.0 license:            BSD-3-Clause license-file:       LICENSE category:           Control@@ -67,7 +67,7 @@                     , async               >= 2.2.2                     , bytestring          >= 0.10                     , directory           >= 1.3.2-                    , effectful-core      >= 2.0.0.0   && < 2.0.1.0+                    , effectful-core      >= 2.1.0.0   && < 2.1.1.0                     , process             >= 1.6.9                      , time                >= 1.9.2
src/Effectful/Concurrent/Effect.hs view
@@ -44,9 +44,9 @@ -- it's inside the 'Effectful.Reader.Static.local' block, even though the parent -- thread already got out of it. ----- This is because the value provided by the 'Effectful.Reader.Static.Reader'+-- This is because the value provided by the t'Effectful.Reader.Static.Reader' -- effect is thread local, i.e. each thread manages its own version of it. For--- the 'Effectful.Reader.Static.Reader' it is the only reasonable behavior, it+-- the t'Effectful.Reader.Static.Reader' it is the only reasonable behavior, it -- wouldn't be very useful if its "read only" value was affected by calls to -- 'Effectful.Reader.Static.local' from its parent or child threads. --
tests/EnvTests.hs view
@@ -16,7 +16,7 @@   [ testCase "tailEnv works" test_tailEnv   , testCase "subsume works" test_subsumeEnv   , testCase "inject works" test_injectEnv-  , testCase "unsafeCoerce doesn't leak" test_noUnsafeCoerce+  , testCase "unsafeCoerce doesn't work" test_noUnsafeCoerce   , testCase "interpose works" test_interpose   ] @@ -56,17 +56,29 @@       modify @Int (+4)       raise $ modify @Int (+8) +----------------------------------------+ test_noUnsafeCoerce :: Assertion test_noUnsafeCoerce = do-  r <- try @ErrorCall $ funToInt id-  assertBool "unsafeCoerce leaks" (isLeft r)-  where-    funToInt :: (a -> b) -> IO Int-    funToInt f = runEff $ do-      oops <- runReader @Int 0 $ do-        withEffToIO $ \unlift -> do-          pure . unlift $ ask @Int-      runReader f $ liftIO oops+  r <- try @ErrorCall . evaluate $ unsafeCoerce @Int 'a'+  assertBool "unsafeCoerce" (isLeft r)++unsafeCoerce :: forall b a. a -> b+unsafeCoerce a = runPureEff $ do+  -- 'oops' gains access to the effect stack with Reader (Box b) via the+  -- unlifting function that escaped its scope. The problem here is that this+  -- effect is no longer in scope.+  oops <- runReader @(Box b) (Box undefined) $ do+    raiseWith SeqUnlift $ \unlift -> do+      pure . unlift $ ask @(Box b)+  -- Put Reader (Box a) where the Reader (Box b) was before and attempt to+  -- retrieve 'a' coerced to 'b'. It fails because 'getLocation' in+  -- 'Effectful.Internal.Env' checks that version of the reference is the same+  -- as version of the effect.+  Box b <- runReader (Box a) $ raise oops+  pure b++data Box a = Box a  ---------------------------------------- 
tests/ReaderTests.hs view
@@ -5,12 +5,13 @@  import Effectful import Effectful.Dispatch.Dynamic-import Effectful.Reader.Static+import Effectful.Reader.Dynamic import qualified Utils as U  readerTests :: TestTree readerTests = testGroup "Reader"-  [ testCase "local works in handlers" test_localInHandler+  [ testCase "local works in handlers (dynamic/static)" $ test_localInHandler runReader+  , testCase "local works in handlers (dynamic/pure)" $ test_localInHandler runPureReader   ]  data SomeEff :: Effect where@@ -18,9 +19,21 @@  type instance DispatchOf SomeEff = Dynamic -test_localInHandler :: Assertion-test_localInHandler = runEff . runReader "global" . interpret f $ do+test_localInHandler+  :: (forall r es a. r -> Eff (Reader r : es) a -> Eff es a)+  -> Assertion+test_localInHandler runR = runEff . runR "global" . interpret f $ do   local (const "local") $ send SomeAction   where     f :: [IOE, Reader String] :>> es => EffectHandler SomeEff es     f _ SomeAction = U.assertEqual "expected result" "local" =<< ask++-- | Purely dynamic Reader for testing purposes.+runPureReader :: r -> Eff (Reader r : es) a -> Eff es a+runPureReader r0 = interpret (handler r0)+  where+    handler :: r -> EffectHandler (Reader r) handlerEs+    handler r env = \case+      Ask       -> pure r+      Local f m -> localSeqUnlift env $ \unlift -> do+        unlift $ interpose (handler $ f r) m