├── .travis.yml ├── CHANGELOG.md ├── Control ├── Error.hs └── Error │ ├── Safe.hs │ ├── Script.hs │ └── Util.hs ├── Data └── EitherR.hs ├── LICENSE ├── Setup.hs ├── default.nix ├── errors.cabal ├── release.nix ├── shell.nix └── stack.yaml /.travis.yml: -------------------------------------------------------------------------------- 1 | # This file has been generated -- see https://github.com/hvr/multi-ghc-travis 2 | language: c 3 | sudo: false 4 | 5 | cache: 6 | directories: 7 | - $HOME/.cabsnap 8 | - $HOME/.cabal/packages 9 | 10 | before_cache: 11 | - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log 12 | - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar 13 | 14 | matrix: 15 | include: 16 | - env: CABALVER=1.18 GHCVER=7.8.4 17 | compiler: ": #GHC 7.8.4" 18 | addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4], sources: [hvr-ghc]}} 19 | - env: CABALVER=1.22 GHCVER=7.10.2 20 | compiler: ": #GHC 7.10.2" 21 | addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.2], sources: [hvr-ghc]}} 22 | - env: CABALVER=1.24 GHCVER=8.0.1 23 | compiler: ": #GHC 8.0.1" 24 | addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.1], sources: [hvr-ghc]}} 25 | 26 | before_install: 27 | - unset CC 28 | - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH 29 | 30 | install: 31 | - cabal --version 32 | - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]" 33 | - if [ -f $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz ]; 34 | then 35 | zcat $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz > 36 | $HOME/.cabal/packages/hackage.haskell.org/00-index.tar; 37 | fi 38 | - travis_retry cabal update -v 39 | - sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config 40 | - cabal install --only-dependencies --enable-tests --enable-benchmarks --dry -v > installplan.txt 41 | - sed -i -e '1,/^Resolving /d' installplan.txt; cat installplan.txt 42 | 43 | # check whether current requested install-plan matches cached package-db snapshot 44 | - if diff -u installplan.txt $HOME/.cabsnap/installplan.txt; 45 | then 46 | echo "cabal build-cache HIT"; 47 | rm -rfv .ghc; 48 | cp -a $HOME/.cabsnap/ghc $HOME/.ghc; 49 | cp -a $HOME/.cabsnap/lib $HOME/.cabsnap/share $HOME/.cabsnap/bin $HOME/.cabal/; 50 | else 51 | echo "cabal build-cache MISS"; 52 | rm -rf $HOME/.cabsnap; 53 | mkdir -p $HOME/.ghc $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin; 54 | cabal install --only-dependencies --enable-tests --enable-benchmarks; 55 | fi 56 | 57 | # snapshot package-db on cache miss 58 | - if [ ! -d $HOME/.cabsnap ]; 59 | then 60 | echo "snapshotting package-db to build-cache"; 61 | mkdir $HOME/.cabsnap; 62 | cp -a $HOME/.ghc $HOME/.cabsnap/ghc; 63 | cp -a $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin installplan.txt $HOME/.cabsnap/; 64 | fi 65 | 66 | # Here starts the actual work to be performed for the package under test; 67 | # any command which exits with a non-zero exit code causes the build to fail. 68 | script: 69 | - if [ -f configure.ac ]; then autoreconf -i; fi 70 | - cabal configure --enable-tests --enable-benchmarks -v2 # -v2 provides useful information for debugging 71 | - cabal build # this builds all libraries and executables (including tests/benchmarks) 72 | - cabal test 73 | - cabal check 74 | - cabal sdist # tests that a source-distribution can be generated 75 | 76 | # Check that the resulting source distribution can be built & installed. 77 | # If there are no other `.tar.gz` files in `dist`, this can be even simpler: 78 | # `cabal install --force-reinstalls dist/*-*.tar.gz` 79 | - SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz && 80 | (cd dist && cabal install --force-reinstalls "$SRC_TGZ") 81 | 82 | # EOF 83 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 2.3.0 2 | 3 | * BREAKING CHANGE: `syncIO` now expects a `MonadIO` constraint instead of 4 | `UnexceptionalIO` 5 | * `syncIO` also changes how it detects asynchronous exceptions. It now 6 | decides based on whether or not an exception inherits from 7 | `SomeAsyncException` 8 | * See: https://github.com/Gabriel439/Haskell-Errors-Library/pull/53 9 | 10 | # 2.2.5 11 | 12 | * Increase upper bound on `exceptions` 13 | 14 | # 2.2.4 15 | 16 | * Increase upper bound on `exceptions` 17 | 18 | # 2.2.3 19 | 20 | * Increase upper bound on `transformers-compat` 21 | 22 | # 2.2.2 23 | 24 | * Support GHC 8.4 through compatibility with Semigroup/Monoid proposal 25 | 26 | # 2.2.1 27 | 28 | * Add precedence and fixity for `(?:)` 29 | 30 | # 2.2.0 31 | 32 | * BREAKING CHANGE: Use `Text` instead of `String` 33 | * Add `handleExceptT` 34 | 35 | # 2.1.3 36 | 37 | * Support older versions of `ghc` 38 | 39 | # 2.1.2 40 | 41 | * Increase upper bound on `transformers` dependency 42 | 43 | # 2.1.1 44 | 45 | * Increase upper bound on `transformers-compat` 46 | 47 | # 2.1.0 48 | 49 | * Change `syncio` to use `unexceptionalio` to prove that all synchronous 50 | exceptions were caught and handled 51 | 52 | # 2.0.0 53 | 54 | * Switch from `EitherT` to `ExceptT` 55 | 56 | # 1.4.7 57 | 58 | * Increase upper bound on `transformers` from `0.4` to `0.5` 59 | 60 | # 1.4.6 61 | 62 | * Add `bool` 63 | * Add `(?:)` 64 | * Add `isJustT` 65 | * Add `isNothingT` 66 | * Add `isLeftT` 67 | * Add `isRightT` 68 | 69 | # 1.4.5 70 | 71 | * Increase upper bound on `either` from `4.1` to `5` 72 | 73 | # 1.4.4 74 | 75 | * Add `failWith` 76 | * Add `failWithM` 77 | 78 | # 1.4.3 79 | 80 | * Add `AllE` 81 | * Add `AnyE` 82 | * Increase upper bound on `either` from `3.5` to `4.1` 83 | 84 | # 1.4.2 85 | 86 | * Add `(??)` 87 | * Add `(!?)` 88 | * Add `syncIO` 89 | 90 | # 1.4.1 91 | 92 | * Re-export `EitherT` 93 | * Re-export `MaybeT` 94 | 95 | # 1.4.0 96 | 97 | * Add `maybeT` 98 | * Add `just` 99 | * Add `nothing` 100 | * Add upper bound to `either` 101 | * Add upper bound to `safe` 102 | * Add upper bound to `transformers` 103 | 104 | # 1.3.1 105 | 106 | * Increase lower bound on `transformers` from `0.2` to `0.3.0.0` 107 | 108 | # 1.3.0 109 | 110 | * Add `assertMay` 111 | * Add `rightMay` 112 | * Add `justErr` 113 | * Add `tryJust` 114 | * Add `tryRight` 115 | * Add `MonadPlus` functions to `Control.Error.Safe` 116 | * Add `isLeft` 117 | * Add `isRight` 118 | * Add `fmapR` 119 | * Add `fmapRT` 120 | * Add `err` 121 | * Add `errLn` 122 | * Add `flipE` 123 | * Add `flipET` 124 | * Rename `tryIO` to `scriptIO` 125 | * Remove `tryMaybe` 126 | * Remove `tryEither` 127 | * Rename `liftMaybe` to `hoistMaybe` 128 | * Rename `liftEither` to `hoistEither` 129 | 130 | # 1.2.1 131 | 132 | * Add lower bound to `either` 133 | 134 | # 1.2.0 135 | 136 | * Remove `right` 137 | * Remove `left` 138 | 139 | # 1.1.1 140 | 141 | * Cosmetic changes 142 | 143 | # 1.1.0 144 | 145 | * Add `left` 146 | 147 | # 1.0.0 148 | 149 | * Initial release 150 | -------------------------------------------------------------------------------- /Control/Error.hs: -------------------------------------------------------------------------------- 1 | {-| Import this module in your code to access the entire library's 2 | functionality: 3 | 4 | > import Control.Error 5 | 6 | This module exports the entire library as well as useful exports from other 7 | standard error-handling libraries: 8 | 9 | * "Control.Error.Safe": Generalizes the @safe@ library, including 'Either', 10 | 'ExceptT', and 'MonadPlus' variations on total functions 11 | 12 | * "Control.Error.Script": Support for simple scripts that catch all errors 13 | and transform them to 'Text' 14 | 15 | * "Control.Error.Util": Utility functions and conversions between common 16 | error-handling types 17 | 18 | * @Control.Monad.Trans.Except@: The 'ExceptT' monad transformer 19 | 20 | * @Control.Monad.Trans.Maybe@: The 'MaybeT' monad transformer 21 | 22 | * @Data.Either@: 'Either' utility functions 23 | 24 | * "Data.EitherR": throw and catch functions, and their corresponding 25 | \"success\" monads 26 | 27 | * @Data.Maybe@: 'Maybe' utility functions 28 | 29 | * @Safe@: Total versions of partial Prelude functions 30 | 31 | This module does not re-export partial functions from other libraries. 32 | -} 33 | 34 | module Control.Error ( 35 | -- * Re-exports 36 | module Control.Error.Safe, 37 | module Control.Error.Script, 38 | module Control.Error.Util, 39 | module Control.Monad.Trans.Except, 40 | module Control.Monad.Trans.Maybe, 41 | module Data.Either, 42 | module Data.EitherR, 43 | module Data.Maybe, 44 | module Safe 45 | ) where 46 | 47 | import Control.Error.Safe 48 | import Control.Error.Script 49 | import Control.Error.Util 50 | import Control.Monad.Trans.Except ( 51 | ExceptT(ExceptT), 52 | runExceptT, 53 | throwE, 54 | catchE, 55 | mapExceptT, 56 | withExceptT ) 57 | import Control.Monad.Trans.Maybe ( 58 | MaybeT(MaybeT), 59 | runMaybeT, 60 | mapMaybeT, 61 | liftCallCC, 62 | liftCatch, 63 | liftListen, 64 | liftPass ) 65 | import Data.Either (either, lefts, rights, partitionEithers) 66 | import Data.EitherR 67 | import Data.Maybe ( 68 | maybe, 69 | isJust, 70 | isNothing, 71 | fromMaybe, 72 | listToMaybe, 73 | maybeToList, 74 | catMaybes, 75 | mapMaybe ) 76 | import Safe ( 77 | tailDef, 78 | tailMay, 79 | tailSafe, 80 | initDef, 81 | initMay, 82 | initSafe, 83 | headDef, 84 | headMay, 85 | lastDef, 86 | lastMay, 87 | minimumDef, 88 | minimumMay, 89 | maximumDef, 90 | maximumMay, 91 | foldr1Def, 92 | foldr1May, 93 | foldl1Def', 94 | foldl1May', 95 | fromJustDef, 96 | atDef, 97 | atMay, 98 | readDef, 99 | readMay, 100 | lookupJustDef, 101 | findJustDef ) 102 | -------------------------------------------------------------------------------- /Control/Error/Safe.hs: -------------------------------------------------------------------------------- 1 | {-| This module extends the @safe@ library's functions with corresponding 2 | versions compatible with 'Either' and 'ExceptT', and also provides a few 3 | 'Maybe'-compatible functions missing from @safe@. 4 | 5 | I suffix the 'Either'-compatible functions with @Err@ and prefix the 6 | 'ExceptT'-compatible functions with @try@. 7 | 8 | Note that this library re-exports the 'Maybe' compatible functions from 9 | @safe@ in the "Control.Error" module, so they are not provided here. 10 | 11 | The \'@Z@\'-suffixed functions generalize the 'Maybe' functions to also work 12 | with anything that implements 'MonadPlus', including: 13 | 14 | * Lists 15 | 16 | * Most parsers 17 | 18 | * 'ExceptT' (if the left value is a 'Monoid') 19 | -} 20 | 21 | module Control.Error.Safe ( 22 | -- * Maybe-compatible functions 23 | assertMay, 24 | rightMay, 25 | 26 | -- * Either-compatible functions 27 | tailErr, 28 | initErr, 29 | headErr, 30 | lastErr, 31 | minimumErr, 32 | maximumErr, 33 | foldr1Err, 34 | foldl1Err, 35 | foldl1Err', 36 | atErr, 37 | readErr, 38 | assertErr, 39 | justErr, 40 | 41 | -- * ExceptT-compatible functions 42 | tryTail, 43 | tryInit, 44 | tryHead, 45 | tryLast, 46 | tryMinimum, 47 | tryMaximum, 48 | tryFoldr1, 49 | tryFoldl1, 50 | tryFoldl1', 51 | tryAt, 52 | tryRead, 53 | tryAssert, 54 | tryJust, 55 | tryRight, 56 | 57 | -- * MonadPlus-compatible functions 58 | tailZ, 59 | initZ, 60 | headZ, 61 | lastZ, 62 | minimumZ, 63 | maximumZ, 64 | foldr1Z, 65 | foldl1Z, 66 | foldl1Z', 67 | atZ, 68 | readZ, 69 | assertZ, 70 | justZ, 71 | rightZ 72 | ) where 73 | 74 | import Control.Error.Util (note, hoistEither) 75 | import Control.Monad (MonadPlus(mzero)) 76 | import Control.Monad.Trans.Except (ExceptT) 77 | import qualified Safe as S 78 | 79 | -- | An assertion that fails in the 'Maybe' monad 80 | assertMay :: Bool -> Maybe () 81 | assertMay = assertZ 82 | 83 | -- | A 'fromRight' that fails in the 'Maybe' monad 84 | rightMay :: Either e a -> Maybe a 85 | rightMay = rightZ 86 | 87 | -- | A 'tail' that fails in the 'Either' monad 88 | tailErr :: e -> [a] -> Either e [a] 89 | tailErr e = note e . S.tailMay 90 | 91 | -- | An 'init' that fails in the 'Either' monad 92 | initErr :: e -> [a] -> Either e [a] 93 | initErr e = note e . S.initMay 94 | 95 | -- | A 'head' that fails in the 'Either' monad 96 | headErr :: e -> [a] -> Either e a 97 | headErr e = note e . S.headMay 98 | 99 | -- | A 'last' that fails in the 'Either' monad 100 | lastErr :: e -> [a] -> Either e a 101 | lastErr e = note e . S.lastMay 102 | 103 | -- | A 'minimum' that fails in the 'Either' monad 104 | minimumErr :: (Ord a) => e -> [a] -> Either e a 105 | minimumErr e = note e . S.minimumMay 106 | 107 | -- | A 'maximum' that fails in the 'Either' monad 108 | maximumErr :: (Ord a) => e -> [a] -> Either e a 109 | maximumErr e = note e . S.maximumMay 110 | 111 | -- | A 'foldr1' that fails in the 'Either' monad 112 | foldr1Err :: e -> (a -> a -> a) -> [a] -> Either e a 113 | foldr1Err e step xs = note e $ S.foldr1May step xs 114 | 115 | -- | A 'foldl1' that fails in the 'Either' monad 116 | foldl1Err :: e -> (a -> a -> a) -> [a] -> Either e a 117 | foldl1Err e step xs = note e $ S.foldl1May step xs 118 | 119 | -- | A 'foldl1'' that fails in the 'Either' monad 120 | foldl1Err' :: e -> (a -> a -> a) -> [a] -> Either e a 121 | foldl1Err' e step xs = note e $ S.foldl1May' step xs 122 | 123 | -- | A ('!!') that fails in the 'Either' monad 124 | atErr :: e -> [a] -> Int -> Either e a 125 | atErr e xs n = note e $ S.atMay xs n 126 | 127 | -- | A 'read' that fails in the 'Either' monad 128 | readErr :: (Read a) => e -> String -> Either e a 129 | readErr e = note e . S.readMay 130 | 131 | -- | An assertion that fails in the 'Either' monad 132 | assertErr :: e -> Bool -> Either e () 133 | assertErr e p = if p then Right () else Left e 134 | 135 | -- | A 'fromJust' that fails in the 'Either' monad 136 | justErr :: e -> Maybe a -> Either e a 137 | justErr e = maybe (Left e) Right 138 | 139 | -- | A 'tail' that fails in the 'ExceptT' monad 140 | tryTail :: (Monad m) => e -> [a] -> ExceptT e m [a] 141 | tryTail e xs = hoistEither $ tailErr e xs 142 | 143 | -- | An 'init' that fails in the 'ExceptT' monad 144 | tryInit :: (Monad m) => e -> [a] -> ExceptT e m [a] 145 | tryInit e xs = hoistEither $ initErr e xs 146 | 147 | -- | A 'head' that fails in the 'ExceptT' monad 148 | tryHead :: (Monad m) => e -> [a] -> ExceptT e m a 149 | tryHead e xs = hoistEither $ headErr e xs 150 | 151 | -- | A 'last' that fails in the 'ExceptT' monad 152 | tryLast :: (Monad m) => e -> [a] -> ExceptT e m a 153 | tryLast e xs = hoistEither $ lastErr e xs 154 | 155 | -- | A 'minimum' that fails in the 'ExceptT' monad 156 | tryMinimum :: (Monad m, Ord a) => e -> [a] -> ExceptT e m a 157 | tryMinimum e xs = hoistEither $ maximumErr e xs 158 | 159 | -- | A 'maximum' that fails in the 'ExceptT' monad 160 | tryMaximum :: (Monad m, Ord a) => e -> [a] -> ExceptT e m a 161 | tryMaximum e xs = hoistEither $ maximumErr e xs 162 | 163 | -- | A 'foldr1' that fails in the 'ExceptT' monad 164 | tryFoldr1 :: (Monad m) => e -> (a -> a -> a) -> [a] -> ExceptT e m a 165 | tryFoldr1 e step xs = hoistEither $ foldr1Err e step xs 166 | 167 | -- | A 'foldl1' that fails in the 'ExceptT' monad 168 | tryFoldl1 :: (Monad m) => e -> (a -> a -> a) -> [a] -> ExceptT e m a 169 | tryFoldl1 e step xs = hoistEither $ foldl1Err e step xs 170 | 171 | -- | A 'foldl1'' that fails in the 'ExceptT' monad 172 | tryFoldl1' :: (Monad m) => e -> (a -> a -> a) -> [a] -> ExceptT e m a 173 | tryFoldl1' e step xs = hoistEither $ foldl1Err' e step xs 174 | 175 | -- | A ('!!') that fails in the 'ExceptT' monad 176 | tryAt :: (Monad m) => e -> [a] -> Int -> ExceptT e m a 177 | tryAt e xs n = hoistEither $ atErr e xs n 178 | 179 | -- | A 'read' that fails in the 'ExceptT' monad 180 | tryRead :: (Monad m, Read a) => e -> String -> ExceptT e m a 181 | tryRead e str = hoistEither $ readErr e str 182 | 183 | -- | An assertion that fails in the 'ExceptT' monad 184 | tryAssert :: (Monad m) => e -> Bool -> ExceptT e m () 185 | tryAssert e p = hoistEither $ assertErr e p 186 | 187 | -- | A 'fromJust' that fails in the 'ExceptT' monad 188 | tryJust :: (Monad m) => e -> Maybe a -> ExceptT e m a 189 | tryJust e m = hoistEither $ justErr e m 190 | 191 | -- | A 'fromRight' that fails in the 'ExceptT' monad 192 | tryRight :: (Monad m) => Either e a -> ExceptT e m a 193 | tryRight = hoistEither 194 | 195 | -- | A 'tail' that fails using 'mzero' 196 | tailZ :: (MonadPlus m) => [a] -> m [a] 197 | tailZ = maybe mzero return . S.tailMay 198 | 199 | -- | An 'init' that fails using 'mzero' 200 | initZ :: (MonadPlus m) => [a] -> m [a] 201 | initZ = maybe mzero return . S.initMay 202 | 203 | -- | A 'head' that fails using 'mzero' 204 | headZ :: (MonadPlus m) => [a] -> m a 205 | headZ = maybe mzero return . S.headMay 206 | 207 | -- | A 'last' that fails using 'mzero' 208 | lastZ :: (MonadPlus m) => [a] -> m a 209 | lastZ = maybe mzero return . S.lastMay 210 | 211 | -- | A 'minimum' that fails using 'mzero' 212 | minimumZ :: (MonadPlus m) => (Ord a) => [a] -> m a 213 | minimumZ = maybe mzero return . S.minimumMay 214 | 215 | -- | A 'maximum' that fails using 'mzero' 216 | maximumZ :: (MonadPlus m) => (Ord a) => [a] -> m a 217 | maximumZ = maybe mzero return . S.maximumMay 218 | 219 | -- | A 'foldr1' that fails using 'mzero' 220 | foldr1Z :: (MonadPlus m) => (a -> a -> a) -> [a] -> m a 221 | foldr1Z step xs = maybe mzero return $ S.foldr1May step xs 222 | 223 | -- | A 'foldl1' that fails using 'mzero' 224 | foldl1Z :: (MonadPlus m) => (a -> a -> a) -> [a] -> m a 225 | foldl1Z step xs = maybe mzero return $ S.foldl1May step xs 226 | 227 | -- | A 'foldl1'' that fails using 'mzero' 228 | foldl1Z' :: (MonadPlus m) => (a -> a -> a) -> [a] -> m a 229 | foldl1Z' step xs = maybe mzero return $ S.foldl1May' step xs 230 | 231 | -- | A ('!!') that fails using 'mzero' 232 | atZ :: (MonadPlus m) => [a] -> Int -> m a 233 | atZ xs n = maybe mzero return $ S.atMay xs n 234 | 235 | -- | A 'read' that fails using 'mzero' 236 | readZ :: (MonadPlus m) => (Read a) => String -> m a 237 | readZ = maybe mzero return . S.readMay 238 | 239 | -- | An assertion that fails using 'mzero' 240 | assertZ :: (MonadPlus m) => Bool -> m () 241 | assertZ p = if p then return () else mzero 242 | 243 | -- | A 'fromJust' that fails using 'mzero' 244 | justZ :: (MonadPlus m) => Maybe a -> m a 245 | justZ = maybe mzero return 246 | 247 | -- | A 'fromRight' that fails using 'mzero' 248 | rightZ :: (MonadPlus m) => Either e a -> m a 249 | rightZ = either (const mzero) return 250 | -------------------------------------------------------------------------------- /Control/Error/Script.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | {-| 4 | Use this module if you like to write simple scripts with 'Text'-based 5 | errors, but you prefer to use 'ExceptT' to handle errors rather than 6 | @Control.Exception@. 7 | 8 | > import Control.Error 9 | > 10 | > main = runScript $ do 11 | > str <- scriptIO getLine 12 | > n <- tryRead "Read failed" str 13 | > scriptIO $ print (n + 1) 14 | -} 15 | 16 | module Control.Error.Script ( 17 | -- * The Script Monad 18 | Script, 19 | runScript, 20 | scriptIO 21 | ) where 22 | 23 | import Control.Exception (try, SomeException) 24 | import Control.Monad (liftM) 25 | import Control.Monad.IO.Class (MonadIO(liftIO)) 26 | import Control.Monad.Trans.Except (ExceptT(ExceptT), runExceptT) 27 | import Control.Error.Util (errLn) 28 | import Data.EitherR (fmapL) 29 | import Data.Monoid ((<>)) 30 | import Data.Text (Text) 31 | import System.Environment (getProgName) 32 | import System.Exit (exitFailure) 33 | 34 | -- Documentation 35 | import Control.Monad.Trans.Class (lift) 36 | import System.IO (stderr) 37 | 38 | import qualified Data.Text 39 | 40 | -- | An 'IO' action that can fail with a 'Text' error message 41 | type Script = ExceptT Text IO 42 | 43 | {-| Runs the 'Script' monad 44 | 45 | Prints the first error to 'stderr' and exits with 'exitFailure' 46 | -} 47 | runScript :: Script a -> IO a 48 | runScript s = do 49 | e <- runExceptT s 50 | case e of 51 | Left e -> do 52 | let adapt str = Data.Text.pack str <> ": " <> e 53 | errLn =<< liftM adapt getProgName 54 | exitFailure 55 | Right a -> return a 56 | 57 | {-| 'scriptIO' resembles 'lift', except it catches all exceptions and converts 58 | them to 'Text' 59 | 60 | Note that 'scriptIO' is compatible with the 'Script' monad. 61 | -} 62 | scriptIO :: (MonadIO m) => IO a -> ExceptT Text m a 63 | scriptIO = ExceptT 64 | . liftIO 65 | . liftM (fmapL (Data.Text.pack . show)) 66 | . (try :: IO a -> IO (Either SomeException a)) 67 | -------------------------------------------------------------------------------- /Control/Error/Util.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | 3 | -- | This module exports miscellaneous error-handling functions. 4 | 5 | module Control.Error.Util ( 6 | -- * Conversion 7 | -- $conversion 8 | hush, 9 | hushT, 10 | note, 11 | noteT, 12 | hoistMaybe, 13 | hoistEither, 14 | (??), 15 | (!?), 16 | failWith, 17 | failWithM, 18 | 19 | -- * Bool 20 | bool, 21 | 22 | -- * Maybe 23 | (?:), 24 | 25 | -- * MaybeT 26 | maybeT, 27 | just, 28 | nothing, 29 | isJustT, 30 | isNothingT, 31 | 32 | -- * Either 33 | isLeft, 34 | isRight, 35 | fmapR, 36 | AllE(..), 37 | AnyE(..), 38 | 39 | -- * ExceptT 40 | isLeftT, 41 | isRightT, 42 | fmapRT, 43 | exceptT, 44 | bimapExceptT, 45 | 46 | -- * Error Reporting 47 | err, 48 | errLn, 49 | 50 | -- * Exceptions 51 | tryIO, 52 | handleExceptT, 53 | syncIO 54 | ) where 55 | 56 | import Control.Applicative (Applicative, pure, (<$>)) 57 | import Control.Exception (IOException, SomeException, Exception) 58 | import Control.Monad (liftM) 59 | import Control.Monad.Catch (MonadCatch, try) 60 | import Control.Monad.IO.Class (MonadIO(liftIO)) 61 | import Control.Monad.Trans.Except (ExceptT(ExceptT), runExceptT) 62 | import Control.Monad.Trans.Maybe (MaybeT(MaybeT), runMaybeT) 63 | import Data.Monoid (Monoid(mempty, mappend)) 64 | #if MIN_VERSION_base(4,9,0) 65 | import Data.Semigroup 66 | #endif 67 | import Data.Maybe (fromMaybe) 68 | import Data.Text (Text) 69 | import System.IO (stderr) 70 | 71 | import qualified Control.Exception as Exception 72 | import qualified Data.Text.IO 73 | 74 | -- | Fold an 'ExceptT' by providing one continuation for each constructor 75 | exceptT :: Monad m => (a -> m c) -> (b -> m c) -> ExceptT a m b -> m c 76 | exceptT f g (ExceptT m) = m >>= \z -> case z of 77 | Left a -> f a 78 | Right b -> g b 79 | {-# INLINEABLE exceptT #-} 80 | 81 | -- | Transform the left and right value 82 | bimapExceptT :: Functor m => (e -> f) -> (a -> b) -> ExceptT e m a -> ExceptT f m b 83 | bimapExceptT f g (ExceptT m) = ExceptT (fmap h m) 84 | where 85 | h (Left e) = Left (f e) 86 | h (Right a) = Right (g a) 87 | {-# INLINEABLE bimapExceptT #-} 88 | 89 | -- | Upgrade an 'Either' to an 'ExceptT' 90 | hoistEither :: Monad m => Either e a -> ExceptT e m a 91 | hoistEither = ExceptT . return 92 | {-# INLINEABLE hoistEither #-} 93 | 94 | {- $conversion 95 | Use these functions to convert between 'Maybe', 'Either', 'MaybeT', and 96 | 'ExceptT'. 97 | -} 98 | -- | Suppress the 'Left' value of an 'Either' 99 | hush :: Either a b -> Maybe b 100 | hush = either (const Nothing) Just 101 | 102 | -- | Suppress the 'Left' value of an 'ExceptT' 103 | hushT :: (Monad m) => ExceptT a m b -> MaybeT m b 104 | hushT = MaybeT . liftM hush . runExceptT 105 | 106 | -- | Tag the 'Nothing' value of a 'Maybe' 107 | note :: a -> Maybe b -> Either a b 108 | note a = maybe (Left a) Right 109 | 110 | -- | Tag the 'Nothing' value of a 'MaybeT' 111 | noteT :: (Monad m) => a -> MaybeT m b -> ExceptT a m b 112 | noteT a = ExceptT . liftM (note a) . runMaybeT 113 | 114 | -- | Lift a 'Maybe' to the 'MaybeT' monad 115 | hoistMaybe :: (Monad m) => Maybe b -> MaybeT m b 116 | hoistMaybe = MaybeT . return 117 | 118 | -- | Convert a 'Maybe' value into the 'ExceptT' monad 119 | (??) :: Applicative m => Maybe a -> e -> ExceptT e m a 120 | (??) a e = ExceptT (pure $ note e a) 121 | 122 | -- | Convert an applicative 'Maybe' value into the 'ExceptT' monad 123 | (!?) :: Applicative m => m (Maybe a) -> e -> ExceptT e m a 124 | (!?) a e = ExceptT (note e <$> a) 125 | 126 | -- | An infix form of 'fromMaybe' with arguments flipped. 127 | (?:) :: Maybe a -> a -> a 128 | maybeA ?: b = fromMaybe b maybeA 129 | {-# INLINABLE (?:) #-} 130 | 131 | infixr 0 ?: 132 | 133 | {-| Convert a 'Maybe' value into the 'ExceptT' monad 134 | 135 | Named version of ('??') with arguments flipped 136 | -} 137 | failWith :: Applicative m => e -> Maybe a -> ExceptT e m a 138 | failWith e a = a ?? e 139 | 140 | {- | Convert an applicative 'Maybe' value into the 'ExceptT' monad 141 | 142 | Named version of ('!?') with arguments flipped 143 | -} 144 | failWithM :: Applicative m => e -> m (Maybe a) -> ExceptT e m a 145 | failWithM e a = a !? e 146 | 147 | {- | Case analysis for the 'Bool' type. 148 | 149 | > bool a b c == if c then b else a 150 | -} 151 | bool :: a -> a -> Bool -> a 152 | bool a b = \c -> if c then b else a 153 | {-# INLINABLE bool #-} 154 | 155 | {-| Case analysis for 'MaybeT' 156 | 157 | Use the first argument if the 'MaybeT' computation fails, otherwise apply 158 | the function to the successful result. 159 | -} 160 | maybeT :: Monad m => m b -> (a -> m b) -> MaybeT m a -> m b 161 | maybeT mb kb (MaybeT ma) = ma >>= maybe mb kb 162 | 163 | -- | Analogous to 'Just' and equivalent to 'return' 164 | just :: (Monad m) => a -> MaybeT m a 165 | just a = MaybeT (return (Just a)) 166 | 167 | -- | Analogous to 'Nothing' and equivalent to 'mzero' 168 | nothing :: (Monad m) => MaybeT m a 169 | nothing = MaybeT (return Nothing) 170 | 171 | -- | Analogous to 'Data.Maybe.isJust', but for 'MaybeT' 172 | isJustT :: (Monad m) => MaybeT m a -> m Bool 173 | isJustT = maybeT (return False) (\_ -> return True) 174 | {-# INLINABLE isJustT #-} 175 | 176 | -- | Analogous to 'Data.Maybe.isNothing', but for 'MaybeT' 177 | isNothingT :: (Monad m) => MaybeT m a -> m Bool 178 | isNothingT = maybeT (return True) (\_ -> return False) 179 | {-# INLINABLE isNothingT #-} 180 | 181 | -- | Returns whether argument is a 'Left' 182 | isLeft :: Either a b -> Bool 183 | isLeft = either (const True) (const False) 184 | 185 | -- | Returns whether argument is a 'Right' 186 | isRight :: Either a b -> Bool 187 | isRight = either (const False) (const True) 188 | 189 | {- | 'fmap' specialized to 'Either', given a name symmetric to 190 | 'Data.EitherR.fmapL' 191 | -} 192 | fmapR :: (a -> b) -> Either l a -> Either l b 193 | fmapR = fmap 194 | 195 | {-| Run multiple 'Either' computations and succeed if all of them succeed 196 | 197 | 'mappend's all successes or failures 198 | -} 199 | newtype AllE e r = AllE { runAllE :: Either e r } 200 | 201 | #if MIN_VERSION_base(4,9,0) 202 | instance (Semigroup e, Semigroup r) => Semigroup (AllE e r) where 203 | AllE (Right x) <> AllE (Right y) = AllE (Right (x <> y)) 204 | AllE (Right _) <> AllE (Left y) = AllE (Left y) 205 | AllE (Left x) <> AllE (Right _) = AllE (Left x) 206 | AllE (Left x) <> AllE (Left y) = AllE (Left (x <> y)) 207 | #endif 208 | 209 | instance (Monoid e, Monoid r) => Monoid (AllE e r) where 210 | mempty = AllE (Right mempty) 211 | #if !(MIN_VERSION_base(4,11,0)) 212 | mappend (AllE (Right x)) (AllE (Right y)) = AllE (Right (mappend x y)) 213 | mappend (AllE (Right _)) (AllE (Left y)) = AllE (Left y) 214 | mappend (AllE (Left x)) (AllE (Right _)) = AllE (Left x) 215 | mappend (AllE (Left x)) (AllE (Left y)) = AllE (Left (mappend x y)) 216 | #endif 217 | 218 | {-| Run multiple 'Either' computations and succeed if any of them succeed 219 | 220 | 'mappend's all successes or failures 221 | -} 222 | newtype AnyE e r = AnyE { runAnyE :: Either e r } 223 | 224 | #if MIN_VERSION_base(4,9,0) 225 | instance (Semigroup e, Semigroup r) => Semigroup (AnyE e r) where 226 | AnyE (Right x) <> AnyE (Right y) = AnyE (Right (x <> y)) 227 | AnyE (Right x) <> AnyE (Left _) = AnyE (Right x) 228 | AnyE (Left _) <> AnyE (Right y) = AnyE (Right y) 229 | AnyE (Left x) <> AnyE (Left y) = AnyE (Left (x <> y)) 230 | #endif 231 | 232 | instance (Monoid e, Monoid r) => Monoid (AnyE e r) where 233 | mempty = AnyE (Right mempty) 234 | #if !(MIN_VERSION_base(4,11,0)) 235 | mappend (AnyE (Right x)) (AnyE (Right y)) = AnyE (Right (mappend x y)) 236 | mappend (AnyE (Right x)) (AnyE (Left _)) = AnyE (Right x) 237 | mappend (AnyE (Left _)) (AnyE (Right y)) = AnyE (Right y) 238 | mappend (AnyE (Left x)) (AnyE (Left y)) = AnyE (Left (mappend x y)) 239 | #endif 240 | 241 | -- | Analogous to 'isLeft', but for 'ExceptT' 242 | isLeftT :: (Monad m) => ExceptT a m b -> m Bool 243 | isLeftT = exceptT (\_ -> return True) (\_ -> return False) 244 | {-# INLINABLE isLeftT #-} 245 | 246 | -- | Analogous to 'isRight', but for 'ExceptT' 247 | isRightT :: (Monad m) => ExceptT a m b -> m Bool 248 | isRightT = exceptT (\_ -> return False) (\_ -> return True) 249 | {-# INLINABLE isRightT #-} 250 | 251 | {- | 'fmap' specialized to 'ExceptT', given a name symmetric to 252 | 'Data.EitherR.fmapLT' 253 | -} 254 | fmapRT :: (Monad m) => (a -> b) -> ExceptT l m a -> ExceptT l m b 255 | fmapRT = liftM 256 | 257 | -- | Write a string to standard error 258 | err :: Text -> IO () 259 | err = Data.Text.IO.hPutStr stderr 260 | 261 | -- | Write a string with a newline to standard error 262 | errLn :: Text -> IO () 263 | errLn = Data.Text.IO.hPutStrLn stderr 264 | 265 | -- | Catch 'IOException's and convert them to the 'ExceptT' monad 266 | tryIO :: MonadIO m => IO a -> ExceptT IOException m a 267 | tryIO = ExceptT . liftIO . Exception.try 268 | 269 | -- | Run a monad action which may throw an exception in the `ExceptT` monad 270 | handleExceptT :: (Exception e, Functor m, MonadCatch m) => (e -> x) -> m a -> ExceptT x m a 271 | handleExceptT handler = bimapExceptT handler id . ExceptT . try 272 | 273 | 274 | {-| Catch all exceptions, except for asynchronous exceptions found in @base@ 275 | and convert them to the 'ExceptT' monad 276 | -} 277 | syncIO :: MonadIO m => IO a -> ExceptT SomeException m a 278 | syncIO = ExceptT . liftIO . trySync 279 | 280 | trySync :: IO a -> IO (Either SomeException a) 281 | trySync io = (fmap Right io) `Exception.catch` \e -> 282 | case Exception.fromException e of 283 | Just (Exception.SomeAsyncException _) -> Exception.throwIO e 284 | Nothing -> return (Left e) 285 | -------------------------------------------------------------------------------- /Data/EitherR.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | 3 | {-| This module provides 'throwEither' and 'catchEither' for 'Either'. These two 4 | functions reside here because 'throwEither' and 'catchEither' correspond to 'return' 5 | and ('>>=') for the flipped 'Either' monad: 'EitherR'. Additionally, this 6 | module defines 'handleE' as the flipped version of 'catchE' for 'ExceptT'. 7 | 8 | 'throwEither' and 'catchEither' improve upon @MonadError@ because: 9 | 10 | * 'catchEither' is more general than 'catch' and allows you to change the left value's type 11 | 12 | * Both are Haskell98 13 | 14 | More advanced users can use 'EitherR' and 'ExceptRT' to program in an 15 | entirely symmetric \"success monad\" where exceptional results are the norm 16 | and successful results terminate the computation. This allows you to chain 17 | error-handlers using @do@ notation and pass around exceptional values of 18 | varying types until you can finally recover from the error: 19 | 20 | > runExceptRT $ do 21 | > e2 <- ioExceptionHandler e1 22 | > bool <- arithmeticExceptionhandler e2 23 | > when bool $ lift $ putStrLn "DEBUG: Arithmetic handler did something" 24 | 25 | If any of the above error handlers 'succeed', no other handlers are tried. 26 | 27 | If you choose not to typefully distinguish between the error and sucess 28 | monad, then use 'flipEither' and 'flipET', which swap the type variables without 29 | changing the type. 30 | -} 31 | 32 | module Data.EitherR ( 33 | -- * EitherR 34 | EitherR(..), 35 | 36 | -- ** Operations in the EitherR monad 37 | succeed, 38 | 39 | -- ** Conversions to the Either monad 40 | throwEither, 41 | catchEither, 42 | handleEither, 43 | fmapL, 44 | 45 | -- ** Flip alternative 46 | flipEither, 47 | 48 | -- * ExceptRT 49 | ExceptRT(..), 50 | 51 | -- ** Operations in the ExceptRT monad 52 | succeedT, 53 | 54 | -- ** Conversions to the ExceptT monad 55 | handleE, 56 | fmapLT, 57 | 58 | -- ** Flip alternative 59 | flipET, 60 | ) where 61 | 62 | import Control.Applicative (Applicative(pure, (<*>)), Alternative(empty, (<|>))) 63 | import Control.Monad (liftM, ap, MonadPlus(mzero, mplus)) 64 | import Control.Monad.Trans.Class (MonadTrans(lift)) 65 | import Control.Monad.IO.Class (MonadIO(liftIO)) 66 | import Control.Monad.Trans.Except (ExceptT(ExceptT), runExceptT, throwE, catchE) 67 | import Data.Monoid (Monoid(mempty, mappend)) 68 | 69 | import qualified Control.Monad.Trans.Except 70 | 71 | {-| If \"@Either e r@\" is the error monad, then \"@EitherR r e@\" is the 72 | corresponding success monad, where: 73 | 74 | * 'return' is 'throwEither'. 75 | 76 | * ('>>=') is 'catchEither'. 77 | 78 | * Successful results abort the computation 79 | -} 80 | newtype EitherR r e = EitherR { runEitherR :: Either e r } deriving Show 81 | 82 | instance Functor (EitherR r) where 83 | fmap = liftM 84 | 85 | instance Applicative (EitherR r) where 86 | pure = return 87 | (<*>) = ap 88 | 89 | instance Monad (EitherR r) where 90 | return e = EitherR (Left e) 91 | EitherR m >>= f = case m of 92 | Left e -> f e 93 | Right r -> EitherR (Right r) 94 | 95 | instance (Monoid r) => Alternative (EitherR r) where 96 | empty = EitherR (Right mempty) 97 | e1@(EitherR (Left _)) <|> _ = e1 98 | _ <|> e2@(EitherR (Left _)) = e2 99 | EitherR (Right r1) <|> EitherR (Right r2) 100 | = EitherR (Right (mappend r1 r2)) 101 | 102 | instance (Monoid r) => MonadPlus (EitherR r) where 103 | mzero = empty 104 | mplus = (<|>) 105 | 106 | -- | Complete error handling, returning a result 107 | succeed :: r -> EitherR r e 108 | succeed r = EitherR (return r) 109 | 110 | -- | 'throwEither' in the error monad corresponds to 'return' in the success monad 111 | throwEither :: e -> Either e r 112 | throwEither e = runEitherR (return e) 113 | 114 | -- | 'catchEither' in the error monad corresponds to ('>>=') in the success monad 115 | catchEither :: Either a r -> (a -> Either b r) -> Either b r 116 | e `catchEither` f = runEitherR $ EitherR e >>= \a -> EitherR (f a) 117 | 118 | -- | 'catchEither' with the arguments flipped 119 | handleEither :: (a -> Either b r) -> Either a r -> Either b r 120 | handleEither = flip catchEither 121 | 122 | -- | Map a function over the 'Left' value of an 'Either' 123 | fmapL :: (a -> b) -> Either a r -> Either b r 124 | fmapL f = runEitherR . fmap f . EitherR 125 | 126 | -- | Flip the type variables of 'Either' 127 | flipEither :: Either a b -> Either b a 128 | flipEither e = case e of 129 | Left a -> Right a 130 | Right b -> Left b 131 | 132 | -- | 'EitherR' converted into a monad transformer 133 | newtype ExceptRT r m e = ExceptRT { runExceptRT :: ExceptT e m r } 134 | 135 | instance (Monad m) => Functor (ExceptRT r m) where 136 | fmap = liftM 137 | 138 | instance (Monad m) => Applicative (ExceptRT r m) where 139 | pure = return 140 | (<*>) = ap 141 | 142 | instance (Monad m) => Monad (ExceptRT r m) where 143 | return e = ExceptRT (throwE e) 144 | m >>= f = ExceptRT $ ExceptT $ do 145 | x <- runExceptT $ runExceptRT m 146 | runExceptT $ runExceptRT $ case x of 147 | Left e -> f e 148 | Right r -> ExceptRT (return r) 149 | 150 | instance (Monad m, Monoid r) => Alternative (ExceptRT r m) where 151 | empty = ExceptRT $ ExceptT $ return $ Right mempty 152 | e1 <|> e2 = ExceptRT $ ExceptT $ do 153 | x1 <- runExceptT $ runExceptRT e1 154 | case x1 of 155 | Left l -> return (Left l) 156 | Right r1 -> do 157 | x2 <- runExceptT $ runExceptRT e2 158 | case x2 of 159 | Left l -> return (Left l) 160 | Right r2 -> return (Right (mappend r1 r2)) 161 | 162 | instance (Monad m, Monoid r) => MonadPlus (ExceptRT r m) where 163 | mzero = empty 164 | mplus = (<|>) 165 | 166 | instance MonadTrans (ExceptRT r) where 167 | lift = ExceptRT . ExceptT . liftM Left 168 | 169 | instance (MonadIO m) => MonadIO (ExceptRT r m) where 170 | liftIO = lift . liftIO 171 | 172 | -- | Complete error handling, returning a result 173 | succeedT :: (Monad m) => r -> ExceptRT r m e 174 | succeedT r = ExceptRT (return r) 175 | 176 | -- | 'catchE' with the arguments flipped 177 | handleE :: (Monad m) => (a -> ExceptT b m r) -> ExceptT a m r -> ExceptT b m r 178 | handleE = flip catchE 179 | 180 | -- | Map a function over the 'Left' value of an 'ExceptT' 181 | #if MIN_VERSION_base(4,8,0) 182 | fmapLT :: Functor m => (a -> b) -> ExceptT a m r -> ExceptT b m r 183 | fmapLT = Control.Monad.Trans.Except.withExceptT 184 | #else 185 | fmapLT :: (Monad m) => (a -> b) -> ExceptT a m r -> ExceptT b m r 186 | fmapLT f = runExceptRT . fmap f . ExceptRT 187 | #endif 188 | 189 | -- | Flip the type variables of an 'ExceptT' 190 | flipET :: (Monad m) => ExceptT a m b -> ExceptT b m a 191 | flipET = ExceptT . liftM flipEither . runExceptT 192 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, 2013, Gabriella Gonzalez 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright notice, 9 | this list of conditions and the following disclaimer in the documentation 10 | and/or other materials provided with the distribution. 11 | * Neither the name of Gabriella Gonzalez nor the names of other contributors 12 | may be used to endorse or promote products derived from this software 13 | without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | { mkDerivation, base, exceptions, safe, stdenv, text, transformers 2 | , transformers-compat 3 | }: 4 | mkDerivation { 5 | pname = "errors"; 6 | version = "2.3.0"; 7 | src = ./.; 8 | libraryHaskellDepends = [ 9 | base exceptions safe text transformers transformers-compat 10 | ]; 11 | description = "Simplified error-handling"; 12 | license = stdenv.lib.licenses.bsd3; 13 | } 14 | -------------------------------------------------------------------------------- /errors.cabal: -------------------------------------------------------------------------------- 1 | Name: errors 2 | Version: 2.3.0 3 | Cabal-Version: >=1.8.0.2 4 | Build-Type: Simple 5 | Tested-With: GHC == 7.8.4, GHC == 7.10.2, GHC == 8.0.1 6 | License: BSD3 7 | License-File: LICENSE 8 | Copyright: 2012, 2013 Gabriella Gonzalez 9 | Author: Gabriella Gonzalez 10 | Maintainer: GenuineGabriella@gmail.com 11 | Bug-Reports: https://github.com/Gabriella439/Haskell-Errors-Library/issues 12 | Synopsis: Simplified error-handling 13 | Description: 14 | The one-stop shop for all your error-handling needs! Just import 15 | "Control.Error". 16 | . 17 | This library encourages an error-handling style that directly uses the type 18 | system, rather than out-of-band exceptions. 19 | Category: Control, Error Handling 20 | extra-source-files: CHANGELOG.md 21 | Source-Repository head 22 | Type: git 23 | Location: https://github.com/Gabriella439/Haskell-Errors-Library 24 | 25 | Library 26 | Build-Depends: 27 | base >= 4.7 && < 5 , 28 | exceptions >= 0.6 && < 0.11, 29 | text < 2.2 , 30 | transformers >= 0.2 && < 0.7 , 31 | transformers-compat >= 0.4 && < 0.8 32 | if impl(ghc <= 7.6.3) 33 | Build-Depends: 34 | safe >= 0.3.3 && < 0.3.10 35 | else 36 | Build-Depends: 37 | safe >= 0.3.3 && < 0.4 38 | Exposed-Modules: 39 | Control.Error, 40 | Control.Error.Safe, 41 | Control.Error.Script, 42 | Control.Error.Util, 43 | Data.EitherR 44 | -------------------------------------------------------------------------------- /release.nix: -------------------------------------------------------------------------------- 1 | let 2 | config = { 3 | packageOverrides = pkgs: { 4 | haskellPackages = pkgs.haskellPackages.override { 5 | overrides = haskellPackagesNew: haskellPackagesOld: { 6 | errors = haskellPackagesNew.callPackage ./default.nix { }; 7 | }; 8 | }; 9 | }; 10 | }; 11 | 12 | pkgs = 13 | import { inherit config; }; 14 | 15 | in 16 | { inherit (pkgs.haskellPackages) errors; 17 | } 18 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | (import ./release.nix).errors.env 2 | -------------------------------------------------------------------------------- /stack.yaml: -------------------------------------------------------------------------------- 1 | resolver: lts-7.11 2 | --------------------------------------------------------------------------------