commit
31c9b7cdee
|
@ -0,0 +1 @@
|
||||||
|
README.md
|
24
README.md
24
README.md
|
@ -4,16 +4,32 @@
|
||||||
[![BSD3 license](https://img.shields.io/badge/license-BSD3-blue.svg)](LICENSE)
|
[![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)
|
[![Build Status](https://action-badges.now.sh/fused-effects/fused-effects-exceptions)](https://github.com/fused-effects/fused-effects-exceptions/actions)
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Setup, hidden from the rendered markdown.
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}
|
||||||
|
module Main (module Main) where
|
||||||
|
|
||||||
|
import Control.Carrier.State.Strict
|
||||||
|
import Control.Effect.Exception
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = pure ()
|
||||||
|
```
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
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.
|
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:
|
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
|
```haskell
|
||||||
λ run (runState 'a' ((throwIO (userError "urk") `finally` put @Char 'z')
|
discardsState :: IO Char
|
||||||
`catch` (\(_ :: IOException) -> pure ())))
|
discardsState = execState 'a' ((throwIO (userError "urk") `finally` put @Char 'z')
|
||||||
('a', ())
|
`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.
|
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.
|
||||||
|
|
|
@ -22,9 +22,12 @@ tested-with:
|
||||||
GHC == 8.6.5
|
GHC == 8.6.5
|
||||||
GHC == 8.8.1
|
GHC == 8.8.1
|
||||||
|
|
||||||
library
|
common common
|
||||||
hs-source-dirs: src
|
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
library
|
||||||
|
import: common
|
||||||
|
hs-source-dirs: src
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
Control.Carrier.State.IORef
|
Control.Carrier.State.IORef
|
||||||
Control.Effect.Exception
|
Control.Effect.Exception
|
||||||
|
@ -34,8 +37,8 @@ library
|
||||||
, transformers >= 0.4 && < 0.6
|
, transformers >= 0.4 && < 0.6
|
||||||
|
|
||||||
test-suite test
|
test-suite test
|
||||||
|
import: common
|
||||||
type: exitcode-stdio-1.0
|
type: exitcode-stdio-1.0
|
||||||
default-language: Haskell2010
|
|
||||||
hs-source-dirs: test
|
hs-source-dirs: test
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
build-depends:
|
build-depends:
|
||||||
|
@ -46,6 +49,18 @@ test-suite test
|
||||||
, tasty-hunit ^>= 0.10
|
, tasty-hunit ^>= 0.10
|
||||||
, transformers
|
, 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
|
source-repository head
|
||||||
type: git
|
type: git
|
||||||
location: https://github.com/fused-effects/fused-effects-exceptions
|
location: https://github.com/fused-effects/fused-effects-exceptions
|
||||||
|
|
|
@ -19,12 +19,12 @@ problematic =
|
||||||
|
|
||||||
testStateDropsWrites :: Tasty.TestTree
|
testStateDropsWrites :: Tasty.TestTree
|
||||||
testStateDropsWrites = HUnit.testCase "State.Strict drops writes" $ do
|
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
|
result HUnit.@?= 'a' -- writes are lost
|
||||||
|
|
||||||
testIOStatePreservesWrites :: Tasty.TestTree
|
testIOStatePreservesWrites :: Tasty.TestTree
|
||||||
testIOStatePreservesWrites = HUnit.testCase "State.IORef preserves writes" $ do
|
testIOStatePreservesWrites = HUnit.testCase "State.IORef preserves writes" $ do
|
||||||
result <- runM . IOState.execState 'a' $ problematic
|
result <- IOState.execState 'a' $ problematic
|
||||||
result HUnit.@?= 'x'
|
result HUnit.@?= 'x'
|
||||||
|
|
||||||
tests :: Tasty.TestTree
|
tests :: Tasty.TestTree
|
||||||
|
|
Loading…
Reference in New Issue