errors 2.1.3 → 2.3.0
raw patch · 6 files changed
Files
- CHANGELOG.md +42/−0
- Control/Error.hs +1/−1
- Control/Error/Script.hs +14/−7
- Control/Error/Util.hs +50/−12
- Data/EitherR.hs +1/−1
- errors.cabal +7/−6
CHANGELOG.md view
@@ -1,3 +1,45 @@+# 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`
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,24 +49,27 @@ -- * Exceptions tryIO,+ handleExceptT, syncIO ) where import Control.Applicative (Applicative, pure, (<$>))-import Control.Exception (Handler(..), IOException, SomeException)+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 UnexceptionalIO (UIO, Unexceptional)+import Data.Text (Text)+import System.IO (stderr) import qualified Control.Exception as Exception-import qualified UnexceptionalIO as UIO+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@@ -123,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@@ -191,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 @@ -204,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@@ -228,19 +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 '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 :: Unexceptional m => IO a -> ExceptT SomeException m a-syncIO = ExceptT . UIO.liftUIO . UIO.fromIO+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
@@ -173,7 +173,7 @@ 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
errors.cabal view
@@ -1,8 +1,8 @@ Name: errors-Version: 2.1.3+Version: 2.3.0 Cabal-Version: >=1.8.0.2 Build-Type: Simple-Tested-With: GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.2, GHC == 8.0.1+Tested-With: GHC == 7.8.4, GHC == 7.10.2, GHC == 8.0.1 License: BSD3 License-File: LICENSE Copyright: 2012, 2013 Gabriel Gonzalez@@ -24,10 +24,11 @@ Library Build-Depends:- base >= 4 && < 5 ,- transformers >= 0.2 && < 0.6,- transformers-compat >= 0.4 && < 0.6,- unexceptionalio >= 0.3 && < 0.4+ 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