errors 2.0.1 → 2.3.0
raw patch · 6 files changed
Files
- CHANGELOG.md +149/−0
- Control/Error.hs +1/−1
- Control/Error/Script.hs +14/−7
- Control/Error/Util.hs +55/−32
- Data/EitherR.hs +10/−1
- errors.cabal +14/−6
+ CHANGELOG.md view
@@ -0,0 +1,149 @@+# 2.3.0++* BREAKING CHANGE: `syncIO` now expects a `MonadIO` constraint instead of+ `UnexceptionalIO`+ * `syncIO` also changes how it detects asynchronous exceptions. It now+ decides based on whether or not an exception inherits from+ `SomeAsyncException`+ * See: https://github.com/Gabriel439/Haskell-Errors-Library/pull/53++# 2.2.5++* Increase upper bound on `exceptions`++# 2.2.4++* Increase upper bound on `exceptions`++# 2.2.3++* Increase upper bound on `transformers-compat`++# 2.2.2++* Support GHC 8.4 through compatibility with Semigroup/Monoid proposal++# 2.2.1++* Add precedence and fixity for `(?:)`++# 2.2.0++* BREAKING CHANGE: Use `Text` instead of `String`+* Add `handleExceptT`++# 2.1.3++* Support older versions of `ghc`++# 2.1.2++* Increase upper bound on `transformers` dependency++# 2.1.1++* Increase upper bound on `transformers-compat`++# 2.1.0++* Change `syncio` to use `unexceptionalio` to prove that all synchronous+ exceptions were caught and handled++# 2.0.0++* Switch from `EitherT` to `ExceptT`++# 1.4.7++* Increase upper bound on `transformers` from `0.4` to `0.5`++# 1.4.6++* Add `bool`+* Add `(?:)`+* Add `isJustT`+* Add `isNothingT`+* Add `isLeftT`+* Add `isRightT`++# 1.4.5++* Increase upper bound on `either` from `4.1` to `5`++# 1.4.4++* Add `failWith`+* Add `failWithM`++# 1.4.3++* Add `AllE`+* Add `AnyE`+* Increase upper bound on `either` from `3.5` to `4.1`++# 1.4.2++* Add `(??)`+* Add `(!?)`+* Add `syncIO`++# 1.4.1++* Re-export `EitherT`+* Re-export `MaybeT`++# 1.4.0++* Add `maybeT`+* Add `just`+* Add `nothing`+* Add upper bound to `either`+* Add upper bound to `safe`+* Add upper bound to `transformers`++# 1.3.1++* Increase lower bound on `transformers` from `0.2` to `0.3.0.0`++# 1.3.0++* Add `assertMay`+* Add `rightMay`+* Add `justErr`+* Add `tryJust`+* Add `tryRight`+* Add `MonadPlus` functions to `Control.Error.Safe`+* Add `isLeft`+* Add `isRight`+* Add `fmapR`+* Add `fmapRT`+* Add `err`+* Add `errLn`+* Add `flipE`+* Add `flipET`+* Rename `tryIO` to `scriptIO`+* Remove `tryMaybe`+* Remove `tryEither`+* Rename `liftMaybe` to `hoistMaybe`+* Rename `liftEither` to `hoistEither`++# 1.2.1++* Add lower bound to `either`++# 1.2.0++* Remove `right`+* Remove `left`++# 1.1.1++* Cosmetic changes++# 1.1.0++* Add `left`++# 1.0.0++* Initial release
Control/Error.hs view
@@ -10,7 +10,7 @@ 'EitherT', and 'MonadPlus' variations on total functions * "Control.Error.Script": Support for simple scripts that catch all errors- and transform them to 'String's+ and transform them to 'Text' * "Control.Error.Util": Utility functions and conversions between common error-handling types
Control/Error/Script.hs view
@@ -1,5 +1,7 @@+{-# LANGUAGE OverloadedStrings #-}+ {-|- Use this module if you like to write simple scripts with 'String'-based+ Use this module if you like to write simple scripts with 'Text'-based errors, but you prefer to use 'ExceptT' to handle errors rather than @Control.Exception@. @@ -24,6 +26,8 @@ import Control.Monad.Trans.Except (ExceptT(ExceptT), runExceptT) import Control.Error.Util (errLn) import Data.EitherR (fmapL)+import Data.Monoid ((<>))+import Data.Text (Text) import System.Environment (getProgName) import System.Exit (exitFailure) @@ -31,9 +35,11 @@ import Control.Monad.Trans.Class (lift) import System.IO (stderr) --- | An 'IO' action that can fail with a 'String' error message-type Script = ExceptT String IO+import qualified Data.Text +-- | An 'IO' action that can fail with a 'Text' error message+type Script = ExceptT Text IO+ {-| Runs the 'Script' monad Prints the first error to 'stderr' and exits with 'exitFailure'@@ -43,17 +49,18 @@ e <- runExceptT s case e of Left e -> do- errLn =<< liftM (++ ": " ++ e) getProgName+ let adapt str = Data.Text.pack str <> ": " <> e+ errLn =<< liftM adapt getProgName exitFailure Right a -> return a {-| 'scriptIO' resembles 'lift', except it catches all exceptions and converts- them to 'String's.+ them to 'Text' Note that 'scriptIO' is compatible with the 'Script' monad. -}-scriptIO :: (MonadIO m) => IO a -> ExceptT String m a+scriptIO :: (MonadIO m) => IO a -> ExceptT Text m a scriptIO = ExceptT . liftIO- . liftM (fmapL show)+ . liftM (fmapL (Data.Text.pack . show)) . (try :: IO a -> IO (Either SomeException a))
Control/Error/Util.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE CPP #-}+ -- | This module exports miscellaneous error-handling functions. module Control.Error.Util (@@ -47,21 +49,28 @@ -- * Exceptions tryIO,+ handleExceptT, syncIO ) where import Control.Applicative (Applicative, pure, (<$>))-import qualified Control.Exception as Ex+import Control.Exception (IOException, SomeException, Exception) import Control.Monad (liftM)+import Control.Monad.Catch (MonadCatch, try) import Control.Monad.IO.Class (MonadIO(liftIO)) import Control.Monad.Trans.Except (ExceptT(ExceptT), runExceptT) import Control.Monad.Trans.Maybe (MaybeT(MaybeT), runMaybeT)-import Data.Dynamic (Dynamic) import Data.Monoid (Monoid(mempty, mappend))+#if MIN_VERSION_base(4,9,0)+import Data.Semigroup+#endif import Data.Maybe (fromMaybe)-import System.Exit (ExitCode)-import System.IO (hPutStr, hPutStrLn, stderr)+import Data.Text (Text)+import System.IO (stderr) +import qualified Control.Exception as Exception+import qualified Data.Text.IO+ -- | Fold an 'ExceptT' by providing one continuation for each constructor exceptT :: Monad m => (a -> m c) -> (b -> m c) -> ExceptT a m b -> m c exceptT f g (ExceptT m) = m >>= \z -> case z of@@ -119,6 +128,8 @@ maybeA ?: b = fromMaybe b maybeA {-# INLINABLE (?:) #-} +infixr 0 ?:+ {-| Convert a 'Maybe' value into the 'ExceptT' monad Named version of ('??') with arguments flipped@@ -187,12 +198,22 @@ -} newtype AllE e r = AllE { runAllE :: Either e r } +#if MIN_VERSION_base(4,9,0)+instance (Semigroup e, Semigroup r) => Semigroup (AllE e r) where+ AllE (Right x) <> AllE (Right y) = AllE (Right (x <> y))+ AllE (Right _) <> AllE (Left y) = AllE (Left y)+ AllE (Left x) <> AllE (Right _) = AllE (Left x)+ AllE (Left x) <> AllE (Left y) = AllE (Left (x <> y))+#endif+ instance (Monoid e, Monoid r) => Monoid (AllE e r) where mempty = AllE (Right mempty)+#if !(MIN_VERSION_base(4,11,0)) mappend (AllE (Right x)) (AllE (Right y)) = AllE (Right (mappend x y)) mappend (AllE (Right _)) (AllE (Left y)) = AllE (Left y) mappend (AllE (Left x)) (AllE (Right _)) = AllE (Left x) mappend (AllE (Left x)) (AllE (Left y)) = AllE (Left (mappend x y))+#endif {-| Run multiple 'Either' computations and succeed if any of them succeed @@ -200,12 +221,22 @@ -} newtype AnyE e r = AnyE { runAnyE :: Either e r } +#if MIN_VERSION_base(4,9,0)+instance (Semigroup e, Semigroup r) => Semigroup (AnyE e r) where+ AnyE (Right x) <> AnyE (Right y) = AnyE (Right (x <> y))+ AnyE (Right x) <> AnyE (Left _) = AnyE (Right x)+ AnyE (Left _) <> AnyE (Right y) = AnyE (Right y)+ AnyE (Left x) <> AnyE (Left y) = AnyE (Left (x <> y))+#endif+ instance (Monoid e, Monoid r) => Monoid (AnyE e r) where mempty = AnyE (Right mempty)+#if !(MIN_VERSION_base(4,11,0)) mappend (AnyE (Right x)) (AnyE (Right y)) = AnyE (Right (mappend x y)) mappend (AnyE (Right x)) (AnyE (Left _)) = AnyE (Right x) mappend (AnyE (Left _)) (AnyE (Right y)) = AnyE (Right y) mappend (AnyE (Left x)) (AnyE (Left y)) = AnyE (Left (mappend x y))+#endif -- | Analogous to 'isLeft', but for 'ExceptT' isLeftT :: (Monad m) => ExceptT a m b -> m Bool@@ -224,38 +255,30 @@ fmapRT = liftM -- | Write a string to standard error-err :: String -> IO ()-err = hPutStr stderr+err :: Text -> IO ()+err = Data.Text.IO.hPutStr stderr -- | Write a string with a newline to standard error-errLn :: String -> IO ()-errLn = hPutStrLn stderr+errLn :: Text -> IO ()+errLn = Data.Text.IO.hPutStrLn stderr --- | Catch 'Ex.IOException's and convert them to the 'ExceptT' monad-tryIO :: (MonadIO m) => IO a -> ExceptT Ex.IOException m a-tryIO = ExceptT . liftIO . Ex.try+-- | Catch 'IOException's and convert them to the 'ExceptT' monad+tryIO :: MonadIO m => IO a -> ExceptT IOException m a+tryIO = ExceptT . liftIO . Exception.try +-- | Run a monad action which may throw an exception in the `ExceptT` monad+handleExceptT :: (Exception e, Functor m, MonadCatch m) => (e -> x) -> m a -> ExceptT x m a+handleExceptT handler = bimapExceptT handler id . ExceptT . try++ {-| Catch all exceptions, except for asynchronous exceptions found in @base@ and convert them to the 'ExceptT' monad -}-syncIO :: MonadIO m => IO a -> ExceptT Ex.SomeException m a-syncIO a = ExceptT . liftIO $ Ex.catches (Right <$> a)- [ Ex.Handler $ \e -> Ex.throw (e :: Ex.ArithException)- , Ex.Handler $ \e -> Ex.throw (e :: Ex.ArrayException)- , Ex.Handler $ \e -> Ex.throw (e :: Ex.AssertionFailed)- , Ex.Handler $ \e -> Ex.throw (e :: Ex.AsyncException)- , Ex.Handler $ \e -> Ex.throw (e :: Ex.BlockedIndefinitelyOnMVar)- , Ex.Handler $ \e -> Ex.throw (e :: Ex.BlockedIndefinitelyOnSTM)- , Ex.Handler $ \e -> Ex.throw (e :: Ex.Deadlock)- , Ex.Handler $ \e -> Ex.throw (e :: Dynamic)- , Ex.Handler $ \e -> Ex.throw (e :: Ex.ErrorCall)- , Ex.Handler $ \e -> Ex.throw (e :: ExitCode)- , Ex.Handler $ \e -> Ex.throw (e :: Ex.NestedAtomically)- , Ex.Handler $ \e -> Ex.throw (e :: Ex.NoMethodError)- , Ex.Handler $ \e -> Ex.throw (e :: Ex.NonTermination)- , Ex.Handler $ \e -> Ex.throw (e :: Ex.PatternMatchFail)- , Ex.Handler $ \e -> Ex.throw (e :: Ex.RecConError)- , Ex.Handler $ \e -> Ex.throw (e :: Ex.RecSelError)- , Ex.Handler $ \e -> Ex.throw (e :: Ex.RecUpdError)- , Ex.Handler $ return . Left- ]+syncIO :: MonadIO m => IO a -> ExceptT SomeException m a+syncIO = ExceptT . liftIO . trySync++trySync :: IO a -> IO (Either SomeException a)+trySync io = (fmap Right io) `Exception.catch` \e ->+ case Exception.fromException e of+ Just (Exception.SomeAsyncException _) -> Exception.throwIO e+ Nothing -> return (Left e)
Data/EitherR.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE CPP #-}+ {-| This module provides 'throwEither' and 'catchEither' for 'Either'. These two functions reside here because 'throwEither' and 'catchEither' correspond to 'return' and ('>>=') for the flipped 'Either' monad: 'EitherR'. Additionally, this@@ -64,6 +66,8 @@ import Control.Monad.Trans.Except (ExceptT(ExceptT), runExceptT, throwE, catchE) import Data.Monoid (Monoid(mempty, mappend)) +import qualified Control.Monad.Trans.Except+ {-| If \"@Either e r@\" is the error monad, then \"@EitherR r e@\" is the corresponding success monad, where: @@ -169,13 +173,18 @@ succeedT :: (Monad m) => r -> ExceptRT r m e succeedT r = ExceptRT (return r) --- | 'catchT' with the arguments flipped+-- | 'catchE' with the arguments flipped handleE :: (Monad m) => (a -> ExceptT b m r) -> ExceptT a m r -> ExceptT b m r handleE = flip catchE -- | Map a function over the 'Left' value of an 'ExceptT'+#if MIN_VERSION_base(4,8,0)+fmapLT :: Functor m => (a -> b) -> ExceptT a m r -> ExceptT b m r+fmapLT = Control.Monad.Trans.Except.withExceptT+#else fmapLT :: (Monad m) => (a -> b) -> ExceptT a m r -> ExceptT b m r fmapLT f = runExceptRT . fmap f . ExceptRT+#endif -- | Flip the type variables of an 'ExceptT' flipET :: (Monad m) => ExceptT a m b -> ExceptT b m a
errors.cabal view
@@ -1,7 +1,8 @@ Name: errors-Version: 2.0.1+Version: 2.3.0 Cabal-Version: >=1.8.0.2 Build-Type: Simple+Tested-With: GHC == 7.8.4, GHC == 7.10.2, GHC == 8.0.1 License: BSD3 License-File: LICENSE Copyright: 2012, 2013 Gabriel Gonzalez@@ -16,20 +17,27 @@ This library encourages an error-handling style that directly uses the type system, rather than out-of-band exceptions. Category: Control, Error Handling+extra-source-files: CHANGELOG.md Source-Repository head Type: git Location: https://github.com/Gabriel439/Haskell-Errors-Library Library Build-Depends:- base >= 4 && < 5 ,- safe >= 0.3.3 && < 0.4,- transformers >= 0.2 && < 0.5,- transformers-compat >= 0.4 && < 0.5+ base >= 4.7 && < 5 ,+ exceptions >= 0.6 && < 0.11,+ text < 1.3 ,+ transformers >= 0.2 && < 0.6 ,+ transformers-compat >= 0.4 && < 0.7+ if impl(ghc <= 7.6.3)+ Build-Depends:+ safe >= 0.3.3 && < 0.3.10+ else+ Build-Depends:+ safe >= 0.3.3 && < 0.4 Exposed-Modules: Control.Error, Control.Error.Safe, Control.Error.Script, Control.Error.Util, Data.EitherR- GHC-Options: -O2