errors 1.2.1 → 1.3.0
raw patch · 6 files changed
+265/−72 lines, 6 filesdep ~basedep ~eitherdep ~safePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base, either, safe, transformers
API changes (from Hackage documentation)
- Control.Error.Script: tryEither :: Either String r -> Script r
- Control.Error.Script: tryIO :: IO a -> Script a
- Control.Error.Script: tryMaybe :: String -> Maybe a -> Script a
- Control.Error.Util: liftEither :: Monad m => Either a b -> EitherT a m b
- Control.Error.Util: liftMaybe :: Monad m => Maybe b -> MaybeT m b
+ Control.Error.Safe: assertMay :: Bool -> Maybe ()
+ Control.Error.Safe: assertZ :: MonadPlus m => Bool -> m ()
+ Control.Error.Safe: atZ :: MonadPlus m => [a] -> Int -> m a
+ Control.Error.Safe: foldl1Z :: MonadPlus m => (a -> a -> a) -> [a] -> m a
+ Control.Error.Safe: foldl1Z' :: MonadPlus m => (a -> a -> a) -> [a] -> m a
+ Control.Error.Safe: foldr1Z :: MonadPlus m => (a -> a -> a) -> [a] -> m a
+ Control.Error.Safe: headZ :: MonadPlus m => [a] -> m a
+ Control.Error.Safe: initZ :: MonadPlus m => [a] -> m [a]
+ Control.Error.Safe: justErr :: e -> Maybe a -> Either e a
+ Control.Error.Safe: justZ :: MonadPlus m => Maybe a -> m a
+ Control.Error.Safe: lastZ :: MonadPlus m => [a] -> m a
+ Control.Error.Safe: maximumZ :: MonadPlus m => Ord a => [a] -> m a
+ Control.Error.Safe: minimumZ :: MonadPlus m => Ord a => [a] -> m a
+ Control.Error.Safe: readZ :: MonadPlus m => Read a => String -> m a
+ Control.Error.Safe: rightMay :: Either e a -> Maybe a
+ Control.Error.Safe: rightZ :: MonadPlus m => Either e a -> m a
+ Control.Error.Safe: tailZ :: MonadPlus m => [a] -> m [a]
+ Control.Error.Safe: tryJust :: Monad m => e -> Maybe a -> EitherT e m a
+ Control.Error.Safe: tryRight :: Monad m => Either e a -> EitherT e m a
+ Control.Error.Script: scriptIO :: MonadIO m => IO a -> EitherT String m a
+ Control.Error.Util: err :: String -> IO ()
+ Control.Error.Util: errLn :: String -> IO ()
+ Control.Error.Util: fmapR :: (a -> b) -> Either l a -> Either l b
+ Control.Error.Util: fmapRT :: Functor m => (a -> b) -> EitherT l m a -> EitherT l m b
+ Control.Error.Util: hoistMaybe :: Monad m => Maybe b -> MaybeT m b
+ Control.Error.Util: isLeft :: Either a b -> Bool
+ Control.Error.Util: isRight :: Either a b -> Bool
+ Control.Error.Util: tryIO :: MonadIO m => IO a -> EitherT IOException m a
+ Data.EitherR: flipE :: Either a b -> Either b a
+ Data.EitherR: flipET :: Monad m => EitherT a m b -> EitherT b m a
- Control.Error.Safe: assertErr :: e -> Bool -> a -> Either e a
+ Control.Error.Safe: assertErr :: e -> Bool -> Either e ()
- Control.Error.Safe: tryAssert :: Monad m => e -> Bool -> a -> EitherT e m a
+ Control.Error.Safe: tryAssert :: Monad m => e -> Bool -> EitherT e m ()
Files
- Control/Error.hs +25/−4
- Control/Error/Safe.hs +117/−18
- Control/Error/Script.hs +28/−25
- Control/Error/Util.hs +67/−19
- Data/EitherR.hs +20/−1
- errors.cabal +8/−5
Control/Error.hs view
@@ -6,11 +6,13 @@ This module exports the entire library as well as useful exports from other standard error-handling libraries.++ This module does not re-export partial functions from other libraries. -} module Control.Error (- module Control.Error.Script, module Control.Error.Safe,+ module Control.Error.Script, module Control.Error.Util, module Control.Monad.Trans.Either, module Control.Monad.Trans.Maybe,@@ -20,12 +22,31 @@ module Safe ) where -import Control.Error.Script import Control.Error.Safe+import Control.Error.Script import Control.Error.Util import Control.Monad.Trans.Either import Control.Monad.Trans.Maybe import Data.Either import Data.EitherR-import Data.Maybe-import Safe+import Data.Maybe hiding (fromJust)+import Safe hiding (+ tailNote,+ initNote,+ headNote,+ lastNote,+ minimumNote,+ maximumNote,+ foldr1Note,+ foldl1Note,+ foldl1Note',+ fromJustNote,+ assertNote,+ at,+ atNote,+ readNote,+ lookupJust,+ lookupJustNote,+ findJust,+ findJustNote,+ abort)
Control/Error/Safe.hs view
@@ -1,6 +1,7 @@ {-| This module extends the @safe@ library's functions with corresponding- versions compatible with 'Either' and 'EitherT'.+ versions compatible with 'Either' and 'EitherT', and also provides several+ 'Maybe'-compatible functions missing from @safe@. All functions take an exceptional value to return should they fail. @@ -12,6 +13,9 @@ -} module Control.Error.Safe (+ -- * Maybe-compatible functions+ assertMay,+ rightMay, -- * Either-compatible functions tailErr, initErr,@@ -25,6 +29,7 @@ atErr, readErr, assertErr,+ justErr, -- * EitherT-compatible functions tryTail, tryInit,@@ -38,12 +43,38 @@ tryAt, tryRead, tryAssert,+ tryJust,+ tryRight,+ -- * MonadPlus-compatible functions+ tailZ,+ initZ,+ headZ,+ lastZ,+ minimumZ,+ maximumZ,+ foldr1Z,+ foldl1Z,+ foldl1Z',+ atZ,+ readZ,+ assertZ,+ justZ,+ rightZ ) where -import Control.Error.Util-import Control.Monad.Trans.Either+import Control.Error.Util (note)+import Control.Monad (MonadPlus(mzero))+import Control.Monad.Trans.Either (EitherT, hoistEither) import Safe +-- | An assertion that fails in the 'Maybe' monad+assertMay :: Bool -> Maybe ()+assertMay = assertZ++-- | A 'fromRight' that fails in the 'Maybe' monad+rightMay :: Either e a -> Maybe a+rightMay = either (\_ -> Nothing) Just+ -- | A 'tail' that fails in the 'Either' monad tailErr :: e -> [a] -> Either e [a] tailErr e = note e . tailMay@@ -89,53 +120,121 @@ readErr e = note e . readMay -- | An assertion that fails in the 'Either' monad-assertErr :: e -> Bool -> a -> Either e a-assertErr e p a = if p then Right a else Left e+assertErr :: e -> Bool -> Either e ()+assertErr e p = if p then Right () else Left e +-- | A 'fromJust' that fails in the 'Either' monad+justErr :: e -> Maybe a -> Either e a+justErr e = maybe (Left e) Right+ -- | A 'tail' that fails in the 'EitherT' monad tryTail :: (Monad m) => e -> [a] -> EitherT e m [a]-tryTail e xs = liftEither $ tailErr e xs+tryTail e xs = hoistEither $ tailErr e xs -- | An 'init' that fails in the 'EitherT' monad tryInit :: (Monad m) => e -> [a] -> EitherT e m [a]-tryInit e xs = liftEither $ initErr e xs+tryInit e xs = hoistEither $ initErr e xs -- | A 'head' that fails in the 'EitherT' monad tryHead :: (Monad m) => e -> [a] -> EitherT e m a-tryHead e xs = liftEither $ headErr e xs+tryHead e xs = hoistEither $ headErr e xs -- | A 'last' that fails in the 'EitherT' monad tryLast :: (Monad m) => e -> [a] -> EitherT e m a-tryLast e xs = liftEither $ lastErr e xs+tryLast e xs = hoistEither $ lastErr e xs -- | A 'minimum' that fails in the 'EitherT' monad tryMinimum :: (Monad m, Ord a) => e -> [a] -> EitherT e m a-tryMinimum e xs = liftEither $ maximumErr e xs+tryMinimum e xs = hoistEither $ maximumErr e xs -- | A 'maximum' that fails in the 'EitherT' monad tryMaximum :: (Monad m, Ord a) => e -> [a] -> EitherT e m a-tryMaximum e xs = liftEither $ maximumErr e xs+tryMaximum e xs = hoistEither $ maximumErr e xs -- | A 'foldr1' that fails in the 'EitherT' monad tryFoldr1 :: (Monad m) => e -> (a -> a -> a) -> [a] -> EitherT e m a-tryFoldr1 e step xs = liftEither $ foldr1Err e step xs+tryFoldr1 e step xs = hoistEither $ foldr1Err e step xs -- | A 'foldl1' that fails in the 'EitherT' monad tryFoldl1 :: (Monad m) => e -> (a -> a -> a) -> [a] -> EitherT e m a-tryFoldl1 e step xs = liftEither $ foldl1Err e step xs+tryFoldl1 e step xs = hoistEither $ foldl1Err e step xs -- | A 'foldl1'' that fails in the 'EitherT' monad tryFoldl1' :: (Monad m) => e -> (a -> a -> a) -> [a] -> EitherT e m a-tryFoldl1' e step xs = liftEither $ foldl1Err' e step xs+tryFoldl1' e step xs = hoistEither $ foldl1Err' e step xs -- | A ('!!') that fails in the 'EitherT' monad tryAt :: (Monad m) => e -> [a] -> Int -> EitherT e m a-tryAt e xs n = liftEither $ atErr e xs n+tryAt e xs n = hoistEither $ atErr e xs n -- | A 'read' that fails in the 'EitherT' monad tryRead :: (Monad m, Read a) => e -> String -> EitherT e m a-tryRead e str = liftEither $ readErr e str+tryRead e str = hoistEither $ readErr e str -- | An assertion that fails in the 'EitherT' monad-tryAssert :: (Monad m) => e -> Bool -> a -> EitherT e m a-tryAssert e p a = liftEither $ assertErr e p a+tryAssert :: (Monad m) => e -> Bool -> EitherT e m ()+tryAssert e p = hoistEither $ assertErr e p++-- | A 'fromJust' that fails in the 'EitherT' monad+tryJust :: (Monad m) => e -> Maybe a -> EitherT e m a+tryJust e m = hoistEither $ justErr e m++-- | A 'fromRight' that fails in the 'EitherT' monad+tryRight :: (Monad m) => Either e a -> EitherT e m a+tryRight = hoistEither++-- | A 'tail' that fails using 'mzero'+tailZ :: (MonadPlus m) => [a] -> m [a]+tailZ = maybe mzero return . tailMay++-- | An 'init' that fails using 'mzero'+initZ :: (MonadPlus m) => [a] -> m [a]+initZ = maybe mzero return . initMay++-- | A 'head' that fails using 'mzero'+headZ :: (MonadPlus m) => [a] -> m a+headZ = maybe mzero return . headMay++-- | A 'last' that fails using 'mzero'+lastZ :: (MonadPlus m) => [a] -> m a+lastZ = maybe mzero return . lastMay++-- | A 'minimum' that fails using 'mzero'+minimumZ :: (MonadPlus m) => (Ord a) => [a] -> m a+minimumZ = maybe mzero return . minimumMay++-- | A 'maximum' that fails using 'mzero'+maximumZ :: (MonadPlus m) => (Ord a) => [a] -> m a+maximumZ = maybe mzero return . maximumMay++-- | A 'foldr1' that fails using 'mzero'+foldr1Z :: (MonadPlus m) => (a -> a -> a) -> [a] -> m a+foldr1Z step xs = maybe mzero return $ foldr1May step xs++-- | A 'foldl1' that fails using 'mzero'+foldl1Z :: (MonadPlus m) => (a -> a -> a) -> [a] -> m a+foldl1Z step xs = maybe mzero return $ foldl1May step xs++-- | A 'foldl1'' that fails using 'mzero'+foldl1Z' :: (MonadPlus m) => (a -> a -> a) -> [a] -> m a+foldl1Z' step xs = maybe mzero return $ foldl1May' step xs++-- | A ('!!') that fails using 'mzero'+atZ :: (MonadPlus m) => [a] -> Int -> m a+atZ xs n = maybe mzero return $ atMay xs n++-- | A 'read' that fails using 'mzero'+readZ :: (MonadPlus m) => (Read a) => String -> m a+readZ = maybe mzero return . readMay++-- | An assertion that fails using 'mzero'+assertZ :: (MonadPlus m) => Bool -> m ()+assertZ p = if p then return () else mzero++-- | A 'fromJust' that fails using 'mzero'+justZ :: (MonadPlus m) => Maybe a -> m a+justZ = maybe mzero return++-- | A 'fromRight' that fails using 'mzero'+rightZ :: (MonadPlus m) => Either e a -> m a+rightZ = either (\_ -> mzero) return
Control/Error/Script.hs view
@@ -1,31 +1,35 @@ {-|- Use this module if you like to write simple scripts, but you prefer to use- 'EitherT' to handle errors rather than @Control.Exception@.+ Use this module if you like to write simple scripts with 'String'-based+ errors, but you prefer to use 'EitherT' to handle errors rather than+ @Control.Exception@. > import Control.Error > > main = runScript $ do-> str <- tryIO getLine+> str <- scriptIO getLine > n <- tryRead "Read failed" str-> tryIO $ print (n + 1)+> scriptIO $ print (n + 1) -} module Control.Error.Script ( -- * The Script Monad Script, runScript,- tryMaybe,- tryEither,- tryIO+ scriptIO ) where -import Control.Exception-import Control.Monad.Trans.Either-import Control.Error.Util-import Data.EitherR-import System.IO-import System.Exit+import Control.Exception (try, SomeException)+import Control.Monad (liftM)+import Control.Monad.IO.Class (MonadIO(liftIO))+import Control.Monad.Trans.Either (EitherT(EitherT, runEitherT))+import Control.Error.Util (errLn)+import Data.EitherR (fmapL)+import System.Exit (exitFailure) +-- Documentation+import Control.Monad.Trans.Class (lift)+import System.IO (stderr)+ -- | An 'IO' action that can fail with a 'String' error message type Script = EitherT String IO @@ -39,19 +43,18 @@ e <- runEitherT s case e of Left e -> do- hPutStrLn stderr e+ errLn e exitFailure Right a -> return a --- | A 'Maybe' that fails in the 'Script' monad-tryMaybe :: String -> Maybe a -> Script a-tryMaybe str = tryEither . note str---- | An 'Either' that fails in the 'Script' monad-tryEither :: Either String r -> Script r-tryEither = liftEither+{-|+ 'scriptIO' resembles 'lift', except it catches all exceptions and converts+ them to 'String's. --- | 'tryIO' is like 'lift', except it converts exceptions to the 'Script' monad-tryIO :: IO a -> Script a-tryIO io = EitherT . fmap (fmapL show)- $ (try :: IO a -> IO (Either SomeException a)) io+ Note that 'scriptIO' is compatible with the 'Script' monad.+-}+scriptIO :: (MonadIO m) => IO a -> EitherT String m a+scriptIO = EitherT+ . liftIO+ . liftM (fmapL show)+ . (try :: IO a -> IO (Either SomeException a))
Control/Error/Util.hs view
@@ -1,19 +1,45 @@-{-|- Use this module to convert between 'Maybe', 'Either', 'MaybeT', and- 'EitherT'.--}+-- | This module exports miscellaneous error-handling functions. -module Control.Error.Util where+module Control.Error.Util (+ -- * Conversion+ -- $conversion+ hush,+ hushT,+ note,+ noteT,+ hoistMaybe,+ -- * Either+ isLeft,+ isRight,+ fmapR,+ -- * EitherT+ fmapRT,+ -- * Error Reporting+ err,+ errLn,+ -- * Exceptions+ tryIO+ ) where -import Control.Monad-import Control.Monad.Trans.Either-import Control.Monad.Trans.Maybe+import Control.Exception (try, IOException)+import Control.Monad (liftM)+import Control.Monad.IO.Class (MonadIO(liftIO))+import Control.Monad.Trans.Either (EitherT(EitherT, runEitherT))+import Control.Monad.Trans.Maybe (MaybeT(MaybeT, runMaybeT))+import System.IO (hPutStr, hPutStrLn, stderr) +-- For Documentation+import Data.EitherR (fmapL, fmapLT)++{- $conversion+ Use these functions to convert between 'Maybe', 'Either', 'MaybeT', and+ 'EitherT'.++ Note that 'hoistEither' is provided by the @either@ package.+-} -- | Suppress the 'Left' value of an 'Either' hush :: Either a b -> Maybe b-hush e = case e of- Left _ -> Nothing- Right b -> Just b+hush = either (\_ -> Nothing) Just -- | Suppress the 'Left' value of an 'EitherT' hushT :: (Monad m) => EitherT a m b -> MaybeT m b@@ -21,18 +47,40 @@ -- | Tag the 'Nothing' value of a 'Maybe' note :: a -> Maybe b -> Either a b-note a m = case m of- Nothing -> Left a- Just b -> Right b+note a = maybe (Left a) Right -- | Tag the 'Nothing' value of a 'MaybeT' noteT :: (Monad m) => a -> MaybeT m b -> EitherT a m b noteT a = EitherT . liftM (note a) . runMaybeT -- | Lift a 'Maybe' to the 'MaybeT' monad-liftMaybe :: (Monad m) => Maybe b -> MaybeT m b-liftMaybe = MaybeT . return+hoistMaybe :: (Monad m) => Maybe b -> MaybeT m b+hoistMaybe = MaybeT . return --- | Lift an 'Either' to the 'EitherT' monad-liftEither :: (Monad m) => Either a b -> EitherT a m b-liftEither = EitherT . return+-- | Returns whether argument is a 'Left'+isLeft :: Either a b -> Bool+isLeft = either (\_ -> True) (\_ -> False)++-- | Returns whether argument is a 'Right'+isRight :: Either a b -> Bool+isRight = either (\_ -> False) (\_ -> True)++-- | 'fmap' specialized to 'Either', given a name symmetric to 'fmapL'+fmapR :: (a -> b) -> Either l a -> Either l b+fmapR = fmap++-- | 'fmap' specialized to 'EitherT', given a name symmetric to 'fmapLT'+fmapRT :: (Functor m) => (a -> b) -> EitherT l m a -> EitherT l m b+fmapRT = fmap++-- | Write a string to standard error+err :: String -> IO ()+err = hPutStr stderr++-- | Write a string with a newline to standard error+errLn :: String -> IO ()+errLn = hPutStrLn stderr++-- | Catch 'IOException's and convert them to the 'EitherT' monad+tryIO :: (MonadIO m) => IO a -> EitherT IOException m a+tryIO = EitherT . liftIO . try
Data/EitherR.hs view
@@ -23,9 +23,14 @@ > when bool $ lift $ putStrLn "DEBUG: Arithmetic handler did something" If any of the above error handlers 'succeed', no other handlers are tried.++ If you choose not to typefully distinguish between the error and sucess+ monad, then use 'flipE' and 'flipET', which swap the type variables without+ changing the type. -} module Data.EitherR (+ -- * EitherR EitherR(..), -- ** Operations in the EitherR monad succeed,@@ -34,6 +39,8 @@ catchE, handleE, fmapL,+ -- ** Flip alternative+ flipE, -- * EitherRT EitherRT(..), -- ** Operations in the EitherRT monad@@ -42,7 +49,9 @@ throwT, catchT, handleT,- fmapLT+ fmapLT,+ -- ** Flip alternative+ flipET, ) where import Control.Applicative@@ -95,6 +104,12 @@ fmapL :: (a -> b) -> Either a r -> Either b r fmapL f = runEitherR . fmap f . EitherR +-- | Flip the type variables of 'Either'+flipE :: Either a b -> Either b a+flipE e = case e of+ Left a -> Right a+ Right b -> Left b+ -- | 'EitherR' converted into a monad transformer newtype EitherRT r m e = EitherRT { runEitherRT :: EitherT e m r } @@ -135,3 +150,7 @@ -- | Map a function over the 'Left' value of an 'EitherT' fmapLT :: (Monad m) => (a -> b) -> EitherT a m r -> EitherT b m r fmapLT f = runEitherRT . fmap f . EitherRT++-- | Flip the type variables of an 'EitherT'+flipET :: (Monad m) => EitherT a m b -> EitherT b m a+flipET = EitherT . liftM flipE . runEitherT
errors.cabal view
@@ -1,6 +1,6 @@ Name: errors-Version: 1.2.1-Cabal-Version: >=1.14.0+Version: 1.3.0+Cabal-Version: >=1.8.0.2 Build-Type: Simple License: BSD3 License-File: LICENSE@@ -23,12 +23,15 @@ Location: https://github.com/Gabriel439/Haskell-Errors-Library Library- Build-Depends: base >= 4 && < 5, either >= 3.0.1, safe, transformers+ Build-Depends:+ base >= 4 && < 5,+ either >= 3.0.1,+ safe >= 0.3.3,+ transformers >= 0.3.0.0 Exposed-Modules: Control.Error,+ Control.Error.Safe, Control.Error.Script, Control.Error.Util,- Control.Error.Safe, Data.EitherR GHC-Options: -O2- Default-Language: Haskell2010