From 4b77ba2f155008e2d8c64864263f15ff0c839fec Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Fri, 1 Nov 2019 11:23:13 -0400 Subject: [PATCH 1/2] Symlink the README. --- README.lhs | 1 + 1 file changed, 1 insertion(+) create mode 120000 README.lhs diff --git a/README.lhs b/README.lhs new file mode 120000 index 0000000..42061c0 --- /dev/null +++ b/README.lhs @@ -0,0 +1 @@ +README.md \ No newline at end of file From 83bd118d7914ecebd92d6fb0b524ce1e3c57660c Mon Sep 17 00:00:00 2001 From: Patrick Thomson Date: Fri, 1 Nov 2019 11:30:36 -0400 Subject: [PATCH 2/2] Compile the README. As per https://github.com/fused-effects/fused-effects/pull/310. --- README.md | 24 ++++++++++++++++++++---- fused-effects-exceptions.cabal | 21 ++++++++++++++++++--- test/Main.hs | 4 ++-- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 065328e..2023131 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,32 @@ [![BSD3 license](https://img.shields.io/badge/license-BSD3-blue.svg)](LICENSE) [![Build Status](https://action-badges.now.sh/fused-effects/fused-effects-exceptions)](https://github.com/fused-effects/fused-effects-exceptions/actions) + + + This package provides `Control.Effect.Exception`, a module that wraps the [`Control.Exception`](http://hackage.haskell.org/package/base/docs/Control-Exception.html) API from `base` with the vocabulary provided by the [`fused-effects`](http://hackage.haskell.org/package/fused-effects) library. These functions interact with GHC's support for dynamic exceptions, including functions like `catch` for exception handling and `bracket` for resource management. Please be aware that injudicious use of these functions may provoke surprising interactions with carriers that thread a monadic state as a parameter, à la the `Control.Carrier.State` types provided by `fused-effects`. For example, a function like `finally`, which does not thread any state from its body to its handler block, may discard state writes in cleanup handlers: ```haskell -λ run (runState 'a' ((throwIO (userError "urk") `finally` put @Char 'z') - `catch` (\(_ :: IOException) -> pure ()))) -('a', ()) +discardsState :: IO Char +discardsState = execState 'a' ((throwIO (userError "urk") `finally` put @Char 'z') + `catch` (\(_ :: IOException) -> pure ())) ``` -If this behavior is a concern, a `Control.Carrier.State.IORef` carrier is provided, which fixes this issue given access to a `MonadIO` constraint. If it is not a concern (such as if the cleanup block is only run for its effects in `IO`), then the `StateC` carriers from `fused-effects` will suffice. For more information about the issues associated with this approach, consult Alexis King's excellent [Demystifying `MonadBaseControl`](https://lexi-lambda.github.io/blog/2019/09/07/demystifying-monadbasecontrol/). +Though the `put @Char 'z'` statement is evaluated, its effect is ultimately discarded; the result of executing the above is `'a'`. If this behavior is a concern, a `Control.Carrier.State.IORef` carrier is provided, which fixes this issue given access to a `MonadIO` constraint. If it is not a concern (such as if the cleanup block is only run for its effects in `IO`), then the `StateC` carriers from `fused-effects` will suffice. For more information about the issues associated with this approach, consult Alexis King's excellent [Demystifying `MonadBaseControl`](https://lexi-lambda.github.io/blog/2019/09/07/demystifying-monadbasecontrol/). Prior versions of this package provided a `Catch` effect; this has been excised in favor of the more-general `Control.Effect.Exception`, which provides more functionality without requiring any additional carriers beyond a `Lift IO` effect. diff --git a/fused-effects-exceptions.cabal b/fused-effects-exceptions.cabal index a322e2b..0c1035a 100644 --- a/fused-effects-exceptions.cabal +++ b/fused-effects-exceptions.cabal @@ -22,9 +22,12 @@ tested-with: GHC == 8.6.5 GHC == 8.8.1 -library - hs-source-dirs: src +common common default-language: Haskell2010 + +library + import: common + hs-source-dirs: src exposed-modules: Control.Carrier.State.IORef Control.Effect.Exception @@ -34,8 +37,8 @@ library , transformers >= 0.4 && < 0.6 test-suite test + import: common type: exitcode-stdio-1.0 - default-language: Haskell2010 hs-source-dirs: test main-is: Main.hs build-depends: @@ -46,6 +49,18 @@ test-suite test , tasty-hunit ^>= 0.10 , transformers +test-suite docs + import: common + type: exitcode-stdio-1.0 + main-is: README.lhs + ghc-options: -pgmL markdown-unlit + build-depends: + base + , fused-effects + , fused-effects-exceptions + build-tool-depends: + markdown-unlit:markdown-unlit ^>= 0.5 + source-repository head type: git location: https://github.com/fused-effects/fused-effects-exceptions diff --git a/test/Main.hs b/test/Main.hs index 6f79a86..536e95d 100644 --- a/test/Main.hs +++ b/test/Main.hs @@ -19,12 +19,12 @@ problematic = testStateDropsWrites :: Tasty.TestTree testStateDropsWrites = HUnit.testCase "State.Strict drops writes" $ do - result <- runM . State.execState 'a' $ problematic + result <- State.execState 'a' $ problematic result HUnit.@?= 'a' -- writes are lost testIOStatePreservesWrites :: Tasty.TestTree testIOStatePreservesWrites = HUnit.testCase "State.IORef preserves writes" $ do - result <- runM . IOState.execState 'a' $ problematic + result <- IOState.execState 'a' $ problematic result HUnit.@?= 'x' tests :: Tasty.TestTree