rescue 0.2.1 → 0.3.0
raw patch · 10 files changed
+349/−142 lines, 10 filesdep +transformers-base
Dependencies added: transformers-base
Files
- README.md +1/−0
- library/Control/Monad/Cleanup/Class.hs +6/−7
- library/Control/Monad/Raise/Class.hs +16/−5
- library/Control/Monad/Raise/Constraint.hs +13/−3
- library/Control/Monad/Rescue.hs +37/−9
- library/Control/Monad/Rescue/Class.hs +170/−77
- library/Control/Monad/Rescue/Constraint.hs +23/−0
- library/Control/Monad/Trans/Cleanup/Types.hs +55/−33
- library/Control/Monad/Trans/Rescue/Types.hs +18/−5
- rescue.cabal +10/−3
README.md view
@@ -36,6 +36,7 @@ * e.g. "can raise X, Y, and Z", or "raises exactly X and Y but none others" * Extensible * Ability to call code that raises some subset of errors+* Handle (and eliminate) exceptions from the context # Approach
library/Control/Monad/Cleanup/Class.hs view
@@ -1,18 +1,17 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} module Control.Monad.Cleanup.Class (MonadCleanup (..)) where import Control.Exception import Control.Monad.Rescue -import Data.WorldPeace- -- | Safely work with resources when an asynchronous exception may be thrown-class (Raises m SomeException, MonadRescue m) => MonadCleanup m where+class (m `Raises` SomeException, MonadRescueFrom m m) => MonadCleanup m where cleanup- :: m resource -- ^ Acquire some resource- -> (resource -> OpenUnion (Errors m) -> m _ig1) -- ^ Cleanup and re-raise- -> (resource -> m _ig2) -- ^ Cleanup normally- -> (resource -> m a) -- ^ Inner action to perform with the resource+ :: m resource -- ^ Acquire some resource+ -> (resource -> ErrorCase m -> m _ig1) -- ^ Cleanup and re-raise+ -> (resource -> m _ig2) -- ^ Cleanup normally+ -> (resource -> m a) -- ^ Inner action to perform with the resource -> m a
library/Control/Monad/Raise/Class.hs view
@@ -3,12 +3,16 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} -- | The 'MonadRaise' class, which is an effect for -- early escape / happy path programming with an exception side channel -module Control.Monad.Raise.Class (MonadRaise (..)) where+module Control.Monad.Raise.Class+ ( MonadRaise (..)+ , ErrorCase+ ) where import Control.Exception @@ -86,8 +90,11 @@ -- -- >>> maybeBoom 42 -- Nothing- raise :: Subset err (OpenUnion (Errors m)) => err -> m a+ raise :: Subset err (ErrorCase m) => err -> m a +-- | Type alias representing the concrete union of the monad's errors+type ErrorCase m = OpenUnion (Errors m)+ instance MonadRaise [] where type Errors [] = '[()] raise _ = []@@ -121,9 +128,13 @@ type Errors (IdentityT m) = Errors m raise = lift . raise -instance MonadRaise m => MonadRaise (MaybeT m) where- type Errors (MaybeT m) = Errors m- raise = lift . raise+instance+ ( () `IsMember` Errors m+ , MonadRaise m+ )+ => MonadRaise (MaybeT m) where+ type Errors (MaybeT m) = Errors m+ raise err = MaybeT $ raise err instance MonadRaise m => MonadRaise (ReaderT cfg m) where type Errors (ReaderT cfg m) = Errors m
library/Control/Monad/Raise/Constraint.hs view
@@ -4,9 +4,15 @@ -- | Declare which exceptions may be raised/rescued in a given context module Control.Monad.Raise.Constraint- ( Raises+ ( -- * Permissive++ Raises , RaisesAtLeast++ -- * Precise+ , RaisesOnly+ , RaisesOne ) where import Control.Monad.Raise.Class@@ -15,10 +21,14 @@ import Data.WorldPeace.Subset.Class -- | Raises this exception, but potentially others-type Raises m err = Subset err (OpenUnion (Errors m))+type Raises m err = Subset err (ErrorCase m) -- | May raise errors, including the provided list-type RaisesAtLeast m errs = Subset (OpenUnion errs) (OpenUnion (Errors m))+type RaisesAtLeast m errs = Subset (OpenUnion errs) (ErrorCase m) -- | Restrict exceptions to exactly this list type RaisesOnly m errs = errs ~ Errors m++-- | Raises an exception, guaranteed to NOT be the outer union+type RaisesOne m err = IsMember err (Errors m)+
library/Control/Monad/Rescue.hs view
@@ -1,5 +1,7 @@-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} -- | Rescue semantics & helpers --@@ -11,6 +13,10 @@ module Control.Monad.Rescue ( rescue+ , handle++ -- * Guaranteed runs+ , reattempt , onRaise , lastly@@ -18,14 +24,18 @@ -- * Reexports , module Control.Monad.Raise+ , module Control.Monad.Rescue.Class+ , module Control.Monad.Rescue.Constraint ) where import Data.Result.Types import Data.WorldPeace import Control.Monad.Raise+ import Control.Monad.Rescue.Class+import Control.Monad.Rescue.Constraint import Numeric.Natural @@ -57,17 +67,28 @@ -- :} -- -- >>> handler = catchesOpenUnion (\foo -> "Foo: " <> show foo, \bar -> "Bar:" <> show bar)--- >>> rescue (goesBoom 42) (pure . handler)+-- >>> rescue (goesBoom 42) (pure . handler) :: Rescue MyErrs String -- RescueT (Identity (Right "Foo: FooErr")) rescue- :: ( MonadRescue m- , RaisesOnly m errs- )- => m a- -> (OpenUnion errs -> m a)+ :: MonadRescueFrom n m+ => n a+ -> (ErrorCase n -> m a) -> m a rescue action handler = either handler pure =<< attempt action +handle+ :: ( MonadRaise m+ , MonadRescueFrom n m+ , Handles err n m+ )+ => n a+ -> (err -> m a)+ -> m a+handle action handler =+ either runHandler pure =<< attempt action+ where+ runHandler = openUnionHandle raise handler+ onRaise :: ( MonadRescue m , RaisesOnly m errs@@ -96,7 +117,14 @@ -- | Run an additional step, and throw away the result. -- Return the result of the action passed.-lastly :: (Contains (Errors m) (Errors m), MonadRescue m) => m a -> m b -> m a+lastly+ :: ( Errors m `Contains` Errors m+ , MonadRaise m+ , MonadRescueFrom m m+ )+ => m a+ -> m b+ -> m a lastly action finalizer = do errOrOk <- attempt action _ <- finalizer
library/Control/Monad/Rescue/Class.hs view
@@ -1,39 +1,39 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-} -- | The 'MonadRescue' class, meant for retrieving the success/failure branches -module Control.Monad.Rescue.Class (MonadRescue (..)) where+module Control.Monad.Rescue.Class (MonadRescueFrom (..)) where import Data.Functor- import Data.WorldPeace import Exception -import Control.Monad.Raise.Class-import Control.Monad.Raise.Constraint-+import Control.Monad.Base import Control.Monad.Cont +import Control.Monad.Raise+ import Control.Monad.Trans.Except import Control.Monad.Trans.Identity import Control.Monad.Trans.Maybe import Control.Monad.Trans.Reader -import qualified Control.Monad.RWS.Lazy as Lazy-import qualified Control.Monad.RWS.Strict as Strict--import qualified Control.Monad.State.Lazy as Lazy-import qualified Control.Monad.State.Strict as Strict+import qualified Control.Monad.RWS.Lazy as Lazy+import qualified Control.Monad.RWS.Strict as Strict -import qualified Control.Monad.Writer.Lazy as Lazy-import qualified Control.Monad.Writer.Strict as Strict+import qualified Control.Monad.State.Lazy as Lazy+import qualified Control.Monad.State.Strict as Strict -import Data.WorldPeace.Subset.Class+import qualified Control.Monad.Writer.Lazy as Lazy+import qualified Control.Monad.Writer.Strict as Strict -- $setup --@@ -42,6 +42,7 @@ -- >>> :set -XTypeApplications -- -- >>> import Control.Monad.Trans.Rescue+-- >>> import Data.Functor.Identity -- >>> import Data.Proxy -- >>> import Data.WorldPeace as OpenUnion --@@ -50,7 +51,8 @@ -- >>> data QuuxErr = QuuxErr deriving Show -- | Pull a potential error out of the surrounding context-class MonadRaise m => MonadRescue m where+-- NOTE that the target `m` may not even be aware of Raise/Rescue. It's an escape to the "normal" world+class (Monad m, MonadRaise n) => MonadRescueFrom n m where -- | Attempt some action, exposing the success and error branches -- -- ==== __Examples__@@ -63,96 +65,187 @@ -- else raise FooErr -- :} --- -- >>> runRescue . attempt $ goesBoom 42- -- Right (Left (Identity FooErr))+ -- >>> :{+ -- result :: Identity (Either (OpenUnion '[FooErr, BarErr]) Int)+ -- result = attempt $ goesBoom 42+ -- :} --- -- Where @Identity fooErr@ is the selection of the 'OpenUnion'.- -- In practice you would handle the 'OpenUnion' like so:+ -- >>> result+ -- Identity (Left (Identity FooErr)) --- -- >>> let handleErr = catchesOpenUnion (show, show)- -- >>> let x = attempt (goesBoom 42) >>= pure . either handleErr show- -- >>> runRescue x- -- Right "FooErr"- attempt :: m a -> m (Either (OpenUnion (Errors m)) a)+ -- Where @Identity FooErr@ is the selection of the 'OpenUnion'.+ attempt :: n a -> m (Either (ErrorCase n) a) -instance MonadRescue Maybe where- attempt = return . \case+instance Monad n => MonadRescueFrom Maybe n where+ attempt = pure . \case Nothing -> Left $ openUnionLift () Just x -> Right x -instance MonadRescue [] where+instance Monad m => MonadRescueFrom [] m where attempt = return . \case [] -> Left $ include () (a : _) -> Right a -instance MonadRescue (Either (OpenUnion errs)) where- attempt action = Right action+instance Monad m => MonadRescueFrom (Either (OpenUnion errs)) m where+ attempt action = pure action -instance MonadRescue IO where+instance MonadIO m => MonadRescueFrom IO m where attempt action =- tryIO action <&> \case+ liftIO (tryIO action) <&> \case Right val -> Right val Left ioExc -> Left $ include ioExc -instance MonadRescue m => MonadRescue (MaybeT m) where- attempt (MaybeT action) = MaybeT . fmap sequence $ attempt action+instance+ ( Monad m+ , MonadRescueFrom n m+ , n `RaisesOne` ()+ )+ => MonadRescueFrom (MaybeT n) m where+ attempt (MaybeT action) =+ attempt action <&> \case+ Right (Just val) -> Right val+ Right Nothing -> Left $ include ()+ Left errs -> Left errs -instance MonadRescue m => MonadRescue (IdentityT m) where- attempt (IdentityT action) = lift (attempt action)+instance MonadRescueFrom n m => MonadRescueFrom (IdentityT n) m where+ attempt (IdentityT action) = attempt action instance- ( MonadRescue m- , Contains (Errors m) errs+ ( MonadBase n m+ , MonadRescueFrom n n+ , Contains (Errors n) errs )- => MonadRescue (ExceptT (OpenUnion errs) m) where- attempt (ExceptT action) =- lift $- attempt action <&> \case- Left err -> Left $ include err- Right errOrVal -> errOrVal+ => MonadRescueFrom n (ExceptT (OpenUnion errs) m) where+ attempt = liftBase . attempt -instance MonadRescue m => MonadRescue (ReaderT cfg m) where- attempt = mapReaderT attempt+instance+ ( Monad m+ , MonadBase n m+ , MonadRaise n+ , MonadRescueFrom n m+ )+ => MonadRescueFrom (ReaderT cfg n) (ReaderT cfg m) where+ attempt = mapReaderT attempt -instance (Monoid w, MonadRescue m) => MonadRescue (Lazy.WriterT w m) where- attempt = Lazy.mapWriterT runner2+instance+ ( Monad m+ , MonadBase n m+ , MonadRaise n+ , MonadRescueFrom n n+ )+ => MonadRescueFrom n (ReaderT cfg m) where+ attempt = liftBase . attempt -instance (Monoid w, MonadRescue m) => MonadRescue (Strict.WriterT w m) where- attempt = Strict.mapWriterT runner2+instance+ ( Monoid w+ , MonadBase n m+ , MonadRescueFrom n m+ )+ => MonadRescueFrom (Lazy.WriterT w n) (Lazy.WriterT w m) where+ attempt = Lazy.mapWriterT runner2 -instance MonadRescue m => MonadRescue (Lazy.StateT s m) where- attempt = Lazy.mapStateT runner2+instance+ ( Monoid w+ , MonadBase n m+ , MonadRescueFrom n n+ )+ => MonadRescueFrom n (Lazy.WriterT w m) where+ attempt = liftBase . attempt -instance MonadRescue m => MonadRescue (Strict.StateT s m) where- attempt = Strict.mapStateT runner2+instance+ ( Monoid w+ , MonadBase n m+ , MonadRescueFrom n m+ )+ => MonadRescueFrom (Strict.WriterT w n) (Strict.WriterT w m) where+ attempt = Strict.mapWriterT runner2 -instance (Monoid w, MonadRescue m) => MonadRescue (Lazy.RWST r w s m) where- attempt = Lazy.mapRWST runner3+instance+ ( Monoid w+ , MonadBase n m+ , MonadRescueFrom n n+ )+ => MonadRescueFrom n (Strict.WriterT w m) where+ attempt = liftBase . attempt -instance (Monoid w, MonadRescue m) => MonadRescue (Strict.RWST r w s m) where- attempt = Strict.mapRWST runner3+instance+ ( MonadBase n m+ , MonadRescueFrom n m+ )+ => MonadRescueFrom (Lazy.StateT s n) (Lazy.StateT s m) where+ attempt = Lazy.mapStateT runner2 -instance MonadRescue m => MonadRescue (ContT r m) where- attempt = withContT $ \b_mr current -> b_mr =<< attempt (pure current)+instance+ ( MonadBase n m+ , MonadRescueFrom n n+ )+ => MonadRescueFrom n (Lazy.StateT s m) where+ attempt = liftBase . attempt +instance+ ( MonadBase n m+ , MonadRescueFrom n m+ )+ => MonadRescueFrom (Strict.StateT s n) (Strict.StateT s m) where+ attempt = Strict.mapStateT runner2++instance+ ( Monoid w+ , MonadBase n m+ , MonadRescueFrom n m+ )+ => MonadRescueFrom (Lazy.RWST r w s n) (Lazy.RWST r w s m) where+ attempt = Lazy.mapRWST runner3++instance+ ( MonadBase n m+ , MonadRescueFrom n n+ )+ => MonadRescueFrom n (Strict.StateT s m) where+ attempt = liftBase . attempt++instance+ ( Monoid w+ , MonadBase n m+ , MonadRescueFrom n n+ )+ => MonadRescueFrom n (Strict.RWST r w s m) where+ attempt = liftBase . attempt++instance+ ( MonadBase n m+ , MonadRescueFrom n n+ )+ => MonadRescueFrom n (ContT r m) where+ attempt = liftBase . attempt++instance forall m r . (MonadRescueFrom (ContT r m) m) => MonadRescueFrom (ContT r m) (ContT r m) where+ attempt =+ withContT $ \b_mr (current :: a) ->+ b_mr =<< attempt (pure current :: ContT r m a)+ runner2- :: ( MonadRescue m- , RaisesOnly m errs+ :: forall m n errs a w .+ ( MonadBase n m+ , MonadRescueFrom n m+ , n `RaisesOnly` errs )- => m (a, w)- -> m (Either (OpenUnion errs) a, w)+ => n (a, w)+ -> m (Either (ErrorCase n) a, w) runner2 inner = do- (a, w) <- inner- errOrVal <- attempt (pure a)- return (errOrVal, w)+ (val, log') <- liftBase inner+ result <- attempt (pure val :: n a)+ return (result, log') runner3- :: ( MonadRescue m- , RaisesOnly m errs+ :: forall m n errs a s w .+ ( MonadBase n m+ , MonadRescueFrom n m+ , n `RaisesOnly` errs )- => m (a, b, c)- -> m (Either (OpenUnion errs) a, b, c)+ => n (a, s, w)+ -> m (Either (OpenUnion errs) a, s, w) runner3 inner = do- (a, s, w) <- inner- errOrVal <- attempt (pure a)- return (errOrVal, s, w)+ (val, state, log') <- liftBase inner+ result <- attempt (pure val :: n a)+ return (result, state, log')
+ library/Control/Monad/Rescue/Constraint.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}++module Control.Monad.Rescue.Constraint+ ( Handles+ , MonadRescue+ ) where++import Control.Monad.Raise.Class+import Control.Monad.Rescue.Class++import Data.WorldPeace++-- | Express the ability to 'handle' / eliminate an exception case+type Handles err n m+ = ( ElemRemove err (Errors n)+ , Contains (Remove err (Errors n)) (Errors m)+ )++-- | Rescue from the existing context only+--+-- Note: cannot 'handle' (elimininate) exceptions+type MonadRescue m = MonadRescueFrom m m
library/Control/Monad/Trans/Cleanup/Types.hs view
@@ -1,9 +1,11 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-} -- | The 'CleanupT' transformer for adding async exceptions to a stack @@ -15,13 +17,16 @@ import Control.Applicative import Control.Monad +import Control.Monad.Base import Control.Monad.Catch as Catch import Control.Monad.Cleanup import Control.Monad.Fix import Control.Monad.IO.Class import Control.Monad.Trans.Class +import Data.Functor import Data.Functor.Contravariant+ import Data.WorldPeace -- | Adds 'SomeException' to an exception stack,@@ -76,33 +81,6 @@ instance MonadThrow m => MonadThrow (CleanupT m) where throwM = CleanupT . throwM -instance- ( Contains (Errors m) (Errors m)- , MonadRaise m- , MonadThrow m- )- => MonadRaise (CleanupT m) where- type Errors (CleanupT m) = SomeException ': Errors m-- raise err = openUnion raiser throwM errsUnion- where- errsUnion :: OpenUnion (SomeException ': Errors m)- errsUnion = include err-- raiser :: Contains err (Errors m) => OpenUnion err -> CleanupT m a- raiser = CleanupT . raise--instance- ( Contains (Errors m) (Errors m)- , MonadCatch m- , MonadRescue m- )- => MonadRescue (CleanupT m) where- attempt action =- Catch.try action >>= \case- Left e@(SomeException _) -> return . Left $ include e- Right result -> attempt $ pure result- instance MonadCatch m => MonadCatch (CleanupT m) where catch (CleanupT action) handler = CleanupT $ catch action (runCleanupT . handler)@@ -127,7 +105,51 @@ instance ( Contains (Errors m) (Errors m)+ , MonadRaise m+ , MonadThrow m+ )+ => MonadRaise (CleanupT m) where+ type Errors (CleanupT m) = SomeException ': Errors m++ raise err = openUnion raiser throwM errsUnion+ where+ errsUnion :: OpenUnion (SomeException ': Errors m)+ errsUnion = include err++ raiser :: Contains err (Errors m) => OpenUnion err -> CleanupT m a+ raiser = CleanupT . raise++instance MonadBase m m => MonadBase m (CleanupT m) where+ liftBase = liftBaseDefault++instance (Monad m, MonadRescue m) => MonadRescueFrom m (CleanupT m) where+ attempt = CleanupT . attempt++instance forall n m .+ ( MonadRescueFrom n m+ , MonadBase n m+ , MonadRescue n+ , MonadCatch n+ , Contains (Errors n) (Errors n)+ , Contains (Errors n) (SomeException ': Errors n)+ )+ => MonadRescueFrom (CleanupT n) m where+ attempt (CleanupT action) =+ liftBase $+ inner <&> \case+ Left err -> Left $ include err+ Right (Left err) -> Left $ include err+ Right (Right val) -> Right val+ where+ inner =+ Catch.try action >>= \case+ Left e@(SomeException _) -> return $ Left e+ Right (val :: a) -> Right <$> attempt (pure val :: n a)++instance+ ( Contains (Errors m) (Errors m) , Contains (Errors m) (SomeException ': Errors m)+ , MonadBase m m , MonadRescue m , MonadMask m )
library/Control/Monad/Trans/Rescue/Types.hs view
@@ -12,11 +12,14 @@ , runRescue ) where +import Prelude+ import Control.Monad.Catch import Control.Monad.Cont import Control.Monad.Fix import Control.Monad.Reader import Control.Monad.Rescue+import Control.Monad.Base import Data.Functor.Identity import Data.WorldPeace@@ -32,9 +35,12 @@ runRescue = runIdentity . runRescueT mapRescueT- :: (m (Either (OpenUnion errs) a) -> n (Either (OpenUnion errs') b))- -> RescueT errs m a -> RescueT errs' n b-mapRescueT f (RescueT m) = RescueT $ f m+ :: ( n (Either (OpenUnion errs) a)+ -> m (Either (OpenUnion errs') b)+ )+ -> RescueT errs n a+ -> RescueT errs' m b+mapRescueT f (RescueT n) = RescueT $ f n instance Eq (m (Either (OpenUnion errs) a)) => Eq (RescueT errs m a) where RescueT a == RescueT b = a == b@@ -60,6 +66,9 @@ instance MonadTrans (RescueT errs) where lift action = RescueT (Right <$> action) +instance MonadBase b m => MonadBase b (RescueT errs m) where+ liftBase = liftBaseDefault+ instance MonadIO m => MonadIO (RescueT errs m) where liftIO io = RescueT $ do action <- liftIO io@@ -86,8 +95,12 @@ type Errors (RescueT errs m) = errs raise err = RescueT . pure $ raise err -instance Monad m => MonadRescue (RescueT errs m) where- attempt (RescueT action) = RescueT (Right <$> action)+instance+ ( Monad m+ , MonadBase n m+ )+ => MonadRescueFrom (RescueT errs n) m where+ attempt (RescueT action) = liftBase action instance MonadThrow m => MonadThrow (RescueT errs m) where throwM = lift . throwM
rescue.cabal view
@@ -1,13 +1,13 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.33.0.+-- This file has been generated from package.yaml by hpack version 0.34.2. -- -- see: https://github.com/sol/hpack ----- hash: 3e4995b89bcb6d9791c2c448d52d59c9ca79e160013ba0d3fbad54936b417fe3+-- hash: 6fb768a7355701f4063e91ba078ad7698c52571f65d298ebcf667cacd6a8b1a8 name: rescue-version: 0.2.1+version: 0.3.0 synopsis: More understandable exceptions description: An error handling library focused on clarity and control category: Error Handling@@ -36,6 +36,7 @@ Control.Monad.Raise.Constraint Control.Monad.Rescue Control.Monad.Rescue.Class+ Control.Monad.Rescue.Constraint Control.Monad.Trans.Cleanup Control.Monad.Trans.Cleanup.Types Control.Monad.Trans.Rescue@@ -58,6 +59,7 @@ , mtl , text , transformers+ , transformers-base , world-peace default-language: Haskell2010 @@ -83,6 +85,7 @@ , quickcheck-instances , text , transformers+ , transformers-base , world-peace , yaml default-language: Haskell2010@@ -104,6 +107,7 @@ , rio , text , transformers+ , transformers-base , world-peace default-language: Haskell2010 @@ -118,6 +122,7 @@ Control.Monad.Raise.Constraint Control.Monad.Rescue Control.Monad.Rescue.Class+ Control.Monad.Rescue.Constraint Control.Monad.Trans.Cleanup Control.Monad.Trans.Cleanup.Types Control.Monad.Trans.Rescue@@ -151,6 +156,7 @@ , tasty-smallcheck , text , transformers+ , transformers-base , world-peace default-language: Haskell2010 @@ -171,5 +177,6 @@ , rescue , text , transformers+ , transformers-base , world-peace default-language: Haskell2010