error (empty) → 0.1.0.0
raw patch · 4 files changed
+190/−0 lines, 4 filesdep +basedep +text
Dependencies added: base, text
Files
- CHANGELOG.md +6/−0
- LICENSE +20/−0
- error.cabal +44/−0
- src/Data/Error.hs +120/−0
+ CHANGELOG.md view
@@ -0,0 +1,6 @@+# Revision history for error++## 0.1.0.0 -- 2021-06-26++* Initial version. More or less feature complete, + unless we decide we need extra helper functions.
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2021 Profpatsch <mail@profpatsch.de>+MIT LICENSE++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ error.cabal view
@@ -0,0 +1,44 @@+cabal-version: 2.4+name: error+version: 0.1.0.0++synopsis: The canonical error type++-- A longer description of the package.+description: A canonical `Error` type, which provides a way to turn an error string into an `Error`, add context to an `Error`, and pretty print the `Error` for displaying it to users.++category: Data, Error Handling++-- A URL where users can report bugs.+homepage: https://github.com/Profpatsch/error+bug-reports: https://github.com/Profpatsch/error/issues++license: MIT+license-file: LICENSE++author: Profpatsch+maintainer: Profpatsch <mail@profpatsch.de>+copyright: 2021 Profpatsch++extra-source-files:+ CHANGELOG.md+ , LICENSE++library+ hs-source-dirs: src+ default-language: Haskell2010+ exposed-modules:+ Data.Error+ build-depends:+ base >= 4.8.0.0 && < 5+ , text >= 0.1++ -- Modules included in this executable, other than Main.+ -- other-modules:++ -- LANGUAGE extensions used by modules in this package.+ -- other-extensions:++source-repository head+ type: git+ location: https://github.com/Profpatsch/error.git
+ src/Data/Error.hs view
@@ -0,0 +1,120 @@+{-# LANGUAGE OverloadedStrings #-}+module Data.Error+ ( Error,+ newError,+ addContext,+ prettyError,+ unwrapError,+ expectError,+ )+where++import Data.Function ((&))+import Data.Text (Text)+import qualified Data.Text as Text++-- | The canonical @Error@ type.+--+-- It can be+--+-- * created from a human-readable error message ('newError')+-- * more semantic context can be added to an existing @Error@ ('addContext')+-- * pretty-printed (`prettyError`)+newtype Error = Error [Text]++-- | Create an ad-hoc 'Error' from an error message.+newError :: Text -> Error+newError msg = Error [msg]++-- | Add a higher-level context to an 'Error'.+--+-- For example, your code hits a “file not found” I/O exception.+-- Instead of propagating it unseen, you catch it and annotate it with 'addContext',+-- and describe why you wanted to open the file in the first place:+--+-- @+-- addContext "Trying to open config file"+-- $ newError "file not found: ./foo"+-- @+--+-- This way, when a user see the error, they will understand better what happened:+--+-- @+-- "Trying to open config file: file not found: ./foo"+-- @+--+-- See 'prettyError'.+addContext :: Text -> Error -> Error+addContext e (Error es) = Error $ e : es++-- | Pretty print the error.+--+-- It will print all context messages, starting with the outermost.+--+-- Example:+--+-- @+-- prettyError $ newError "file not found: ./foo"+--+-- ==> "file not found: ./foo"+--+-- prettyError+-- $ addContext "Trying to open config file"+-- $ newError "file not found: ./foo"+--+-- ==> "Trying to open config file: file not found: ./foo"+-- @+prettyError :: Error -> Text+prettyError (Error es) = Text.intercalate ": " es++-- | Return the value from a potentially failing computation.+--+-- Abort with the 'Error's message if it was a 'Left'.+--+-- Panic: if Error+--+-- Example:+--+-- @+-- unwrapError $ Left (newError "oh no!")+--+-- ==> *** Exception: oh no!+--+-- unwrapError $ Right 42+--+-- ==> 42+-- @+unwrapError :: Either Error p -> p+unwrapError e = case e of+ Left err -> error (prettyError err & Text.unpack)+ Right a -> a++-- | Return the value from a potentially failing computation.+--+-- Abort with the error message if it was an error.+--+-- The text message is added to the 'Error' as additional context before aborting.+--+-- Panic: if Error+--+-- Example:+--+-- @+-- exceptError "something bad happened" $ Left (newError "oh no!")+--+-- ==> *** Exception: something bad happened: oh no!+--+-- exceptError $ Right 42+--+-- ==> 42+-- @+expectError :: Text -> Either Error p -> p+expectError context e = case e of+ Left err ->+ error+ ( err+ & addContext context+ & prettyError+ & Text.unpack+ )+ Right a -> a