errors (empty) → 1.0.0
raw patch · 8 files changed
+469/−0 lines, 8 filesdep +EitherTdep +basedep +safesetup-changed
Dependencies added: EitherT, base, safe, transformers
Files
- Control/Error.hs +31/−0
- Control/Error/Safe.hs +141/−0
- Control/Error/Script.hs +57/−0
- Control/Error/Util.hs +38/−0
- Data/EitherR.hs +142/−0
- LICENSE +24/−0
- Setup.hs +2/−0
- errors.cabal +34/−0
+ Control/Error.hs view
@@ -0,0 +1,31 @@+{-|+ Import this module in your code to access the entire library's+ functionality:++> import Control.Error++ This module exports the entire library as well as useful exports from other+ standard error-handling libraries.+-}++module Control.Error (+ module Control.Error.Script,+ module Control.Error.Safe,+ module Control.Error.Util,+ module Control.Monad.Trans.Either,+ module Control.Monad.Trans.Maybe,+ module Data.Either,+ module Data.EitherR,+ module Data.Maybe,+ module Safe+ ) where++import Control.Error.Script+import Control.Error.Safe+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
+ Control/Error/Safe.hs view
@@ -0,0 +1,141 @@+{-|+ This module extends the @safe@ library's functions with corresponding+ versions compatible with 'Either' and 'EitherT'.++ All functions take an exceptional value to return should they fail.++ I suffix the 'Either'-compatible functions with @Err@ and prefix the+ 'EitherT'-compatible functions with @try@.++ Note that this library re-exports the 'Maybe' compatible functions from+ @safe@ in the "Control.Error" module, so they are not provided here.+-}++module Control.Error.Safe (+ -- * Either-compatible functions+ tailErr,+ initErr,+ headErr,+ lastErr,+ minimumErr,+ maximumErr,+ foldr1Err,+ foldl1Err,+ foldl1Err',+ atErr,+ readErr,+ assertErr,+ -- * EitherT-compatible functions+ tryTail,+ tryInit,+ tryHead,+ tryLast,+ tryMinimum,+ tryMaximum,+ tryFoldr1,+ tryFoldl1,+ tryFoldl1',+ tryAt,+ tryRead,+ tryAssert,+ ) where++import Control.Error.Util+import Control.Monad.Trans.Either+import Safe++-- | A 'tail' that fails in the 'Either' monad+tailErr :: e -> [a] -> Either e [a]+tailErr e = note e . tailMay++-- | An 'init' that fails in the 'Either' monad+initErr :: e -> [a] -> Either e [a]+initErr e = note e . initMay++-- | A 'head' that fails in the 'Either' monad+headErr :: e -> [a] -> Either e a+headErr e = note e . headMay++-- | A 'last' that fails in the 'Either' monad+lastErr :: e -> [a] -> Either e a+lastErr e = note e . lastMay++-- | A 'minimum' that fails in the 'Either' monad+minimumErr :: (Ord a) => e -> [a] -> Either e a+minimumErr e = note e . minimumMay++-- | A 'maximum' that fails in the 'Either' monad+maximumErr :: (Ord a) => e -> [a] -> Either e a+maximumErr e = note e . maximumMay++-- | A 'foldr1' that fails in the 'Either' monad+foldr1Err :: e -> (a -> a -> a) -> [a] -> Either e a+foldr1Err e step xs = note e $ foldr1May step xs++-- | A 'foldl1' that fails in the 'Either' monad+foldl1Err :: e -> (a -> a -> a) -> [a] -> Either e a+foldl1Err e step xs = note e $ foldl1May step xs++-- | A 'foldl1'' that fails in the 'Either' monad+foldl1Err' :: e -> (a -> a -> a) -> [a] -> Either e a+foldl1Err' e step xs = note e $ foldl1May' step xs++-- | A ('!!') that fails in the 'Either' monad+atErr :: e -> [a] -> Int -> Either e a+atErr e xs n = note e $ atMay xs n++-- | A 'read' that fails in the 'Either' monad+readErr :: (Read a) => e -> String -> Either e a+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++-- | A 'tail' that fails in the 'EitherT' monad+tryTail :: (Monad m) => e -> [a] -> EitherT e m [a]+tryTail e xs = liftEither $ 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++-- | A 'head' that fails in the 'EitherT' monad+tryHead :: (Monad m) => e -> [a] -> EitherT e m a+tryHead e xs = liftEither $ 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++-- | 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++-- | 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++-- | 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++-- | 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++-- | 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++-- | 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++-- | 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++-- | 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
+ Control/Error/Script.hs view
@@ -0,0 +1,57 @@+{-|+ Use this module if you like to write simple scripts, but you prefer to use+ 'EitherT' to handle errors rather than @Control.Exception@.++> import Control.Error+>+> main = runScript $ do+> str <- tryIO getLine+> n <- tryRead "Read failed" str+> tryIO $ print (n + 1)+-}++module Control.Error.Script (+ -- * The Script Monad+ Script,+ runScript,+ tryMaybe,+ tryEither,+ tryIO+ ) where++import Control.Exception+import Control.Monad.Trans.Either+import Control.Error.Util+import Data.EitherR+import System.IO+import System.Exit++-- | An 'IO' action that can fail with a 'String' error message+type Script = EitherT String IO++{-|+ Runs the 'Script' monad++ Prints the first error to 'stderr' and exits with 'exitFailure'+-}+runScript :: Script a -> IO a+runScript s = do+ e <- runEitherT s+ case e of+ Left e -> do+ hPutStrLn stderr 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++-- | '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
+ Control/Error/Util.hs view
@@ -0,0 +1,38 @@+{-|+ Use this module to convert between 'Maybe', 'Either', 'MaybeT', and+ 'EitherT'.+-}++module Control.Error.Util where++import Control.Monad+import Control.Monad.Trans.Either+import Control.Monad.Trans.Maybe++-- | Suppress the 'Left' value of an 'Either'+hush :: Either a b -> Maybe b+hush e = case e of+ Left _ -> Nothing+ Right b -> Just b++-- | Suppress the 'Left' value of an 'EitherT'+hushT :: (Monad m) => EitherT a m b -> MaybeT m b+hushT = MaybeT . liftM hush . runEitherT++-- | 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++-- | 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++-- | Lift an 'Either' to the 'EitherT' monad+liftEither :: (Monad m) => Either a b -> EitherT a m b+liftEither = EitherT . return
+ Data/EitherR.hs view
@@ -0,0 +1,142 @@+{-|+ This modules provides newtypes which flip the type variables of 'Either'+ and 'EitherT' to access the symmetric monad over the opposite type variable.++ This module provides the following simple benefits to the casual user:++ * A type-class free alternative to @MonadError@++ * No @UndecidableInstances@ or any other extensions, for that matter++ * A more powerful 'catchE' statement that allows you to change the type of+ error value returned++ More advanced users can take advantage of the fact that 'EitherR' and+ 'EitherRT' define an entirely symmetric \"success monad\" where+ error-handling computations are the default and successful results terminate+ the monad. This allows you to chain error-handlers and pass around values+ other than exceptions until you can finally recover from the error:++> runEitherRT $ do+> e2 <- ioExceptionHandler e1+> bool <- arithmeticExceptionhandler e2+> when bool $ lift $ putStrLn "DEBUG: Arithmetic handler did something"++ If any of the above error handlers 'succeed', no other handlers are tried.+-}++module Data.EitherR (+ EitherR(..),+ -- ** Operations in the EitherR monad+ succeed,+ -- ** Conversions to the Either monad+ throwE,+ catchE,+ handleE,+ fmapL,+ -- * EitherRT+ EitherRT(..),+ -- ** Operations in the EitherRT monad+ right,+ succeedT,+ -- ** Conversions to the EitherT monad+ throwT,+ catchT,+ handleT,+ fmapLT+ ) where++import Control.Applicative+import Control.Monad+import Control.Monad.Trans.Class+import Control.Monad.Trans.Either++{-|+ If \"@Either e r@\" is the error monad, then \"@EitherR r e@\" is the+ corresponding success monad, where:++ * 'return' is 'throwE'.++ * ('>>=') is 'catchE'.++ * Successful results abort the computation+-}+newtype EitherR r e = EitherR { runEitherR :: Either e r }++instance Functor (EitherR r) where+ fmap = liftM++instance Applicative (EitherR r) where+ pure = return+ (<*>) = ap++instance Monad (EitherR r) where+ return = EitherR . Left+ (EitherR m) >>= f = EitherR $ case m of+ Left e -> runEitherR (f e)+ Right r -> Right r++-- | Complete error handling, returning a result+succeed :: r -> EitherR r e+succeed = EitherR . return++-- | 'throwE' in the error monad corresponds to 'return' in the success monad+throwE :: e -> Either e r+throwE = runEitherR . return++-- | 'catchE' in the error monad corresponds to ('>>=') in the success monad+catchE :: Either a r -> (a -> Either b r) -> Either b r+e `catchE` f = runEitherR $ (EitherR e) >>= (EitherR . f)++-- | 'catchE' with the arguments flipped+handleE :: (a -> Either b r) -> Either a r -> Either b r+handleE = flip catchE++-- | Map a function over the 'Left' value of an 'Either'+fmapL :: (a -> b) -> Either a r -> Either b r+fmapL f = runEitherR . fmap f . EitherR++-- | 'EitherR' converted into a monad transformer+newtype EitherRT r m e = EitherRT { runEitherRT :: EitherT e m r }++instance (Monad m) => Functor (EitherRT r m) where+ fmap = liftM++instance (Monad m) => Applicative (EitherRT r m) where+ pure = return+ (<*>) = ap++instance (Monad m) => Monad (EitherRT r m) where+ return = EitherRT . left+ m >>= f = EitherRT $ EitherT $ do+ x <- runEitherT $ runEitherRT m+ runEitherT $ runEitherRT $ case x of+ Left e -> f e+ Right r -> right r++instance MonadTrans (EitherRT r) where+ lift = EitherRT . EitherT . liftM Left++-- | The dual to 'left' and synonymous with 'succeedT'+right :: (Monad m) => r -> EitherRT r m e+right = EitherRT . return++-- | Complete error handling, returning a result+succeedT :: (Monad m) => r -> EitherRT r m e+succeedT = right++-- | 'throwT' in the error monad corresponds to 'return' in the success monad+throwT :: (Monad m) => e -> EitherT e m r+throwT = runEitherRT . return++-- | 'catchT' in the error monad corresponds to ('>>=') in the success monad+catchT :: (Monad m) => EitherT a m r -> (a -> EitherT b m r) -> EitherT b m r+e `catchT` f = runEitherRT $ (EitherRT e) >>= (EitherRT . f)++-- | 'catchT' with the arguments flipped+handleT :: (Monad m) => (a -> EitherT b m r) -> EitherT a m r -> EitherT b m r+handleT = flip catchT++-- | 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
+ LICENSE view
@@ -0,0 +1,24 @@+Copyright (c) 2012, Gabriel Gonzalez+All rights reserved.++Redistribution and use in source and binary forms, with or without modification,+are permitted provided that the following conditions are met:+ * Redistributions of source code must retain the above copyright notice,+ this list of conditions and the following disclaimer.+ * Redistributions in binary form must reproduce the above copyright notice,+ this list of conditions and the following disclaimer in the documentation+ and/or other materials provided with the distribution.+ * Neither the name of Gabriel Gonzalez nor the names of other contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ errors.cabal view
@@ -0,0 +1,34 @@+Name: errors+Version: 1.0.0+Cabal-Version: >=1.14.0+Build-Type: Simple+License: BSD3+License-File: LICENSE+Copyright: 2012 Gabriel Gonzalez+Author: Gabriel Gonzalez+Maintainer: Gabriel439@gmail.com+Stability: Experimental+Bug-Reports: https://github.com/Gabriel439/Haskell-Errors-Library/issues+Synopsis: Simplified error-handling+Description:+ The one-stop shop for all your error-handling needs! Just import+ "Control.Error".+ .+ This library encourages an error-handling style that directly uses the type+ system, rather than out-of-band exceptions.+Category: Control, Error Handling+Tested-With: GHC ==7.4.1+Source-Repository head+ Type: git+ Location: https://github.com/Gabriel439/Haskell-Errors-Library++Library+ Build-Depends: base >= 4 && < 5, EitherT, safe, transformers+ Exposed-Modules:+ Control.Error,+ Control.Error.Script,+ Control.Error.Util,+ Control.Error.Safe,+ Data.EitherR+ GHC-Options: -O2+ Default-Language: Haskell2010