-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Composable error messages. -- -- This philosophy behind this package is that it is often better to find -- out all of the errors that have occured in a computation and report -- them simultaneously, rather than aborting as soon as the first error -- is encountered. Towards this end, this module supplies a type of -- combinable error messages so that all of the errors from -- subcomputations can be gathered and presented together. @package error-message @version 1.0 -- | This philosophy behind this package is that it is often better to find -- out all of the errors that have occured in a computation and report -- them simultaneously, rather than aborting as soon as the first error -- is encountered. Towards this end, this module supplies a type of -- combinable error messages so that all of the errors from -- subcomputations can be gathered and presented together. -- -- The following provides an example of how these can be used: -- --
-- sqrtWithError :: Float -> Either ErrorMessage Float
-- sqrtWithError x
-- | x < 0
-- = leftErrorMessageText
-- ("Error computing the square root of " ++ (show x) ++ ":")
-- "Square roots cannot be taken of negative numbers."
-- | otherwise
-- = Right (sqrt x)
--
-- sumWithError :: Either ErrorMessage Float -> Either ErrorMessage Float -> Either ErrorMessage Float
-- sumWithError (Left error1) (Left error2) = Left (error1 `mappend` error2)
-- sumWithError (Left error) _ = Left error
-- sumWithError _ (Left error) = Left error
-- sumWithError (Right value1) (Right value2) = Right (value1 + value2)
--
-- showSumOrErrorOf :: Float -> Float -> String
-- showSumOrErrorOf x y =
-- case sumWithError (sqrtWithError x) (sqrtWithError y) of
-- Right value -> "The value is " ++ show value
-- Left error -> show . formatErrorMessage $ error
--
--
-- The result of showSumOrErrorOf (-1) (-2) is the string,
--
-- -- Error computing the square root of -1: -- Square roots cannot be taken of negative numbers. -- Error computing the square root of -2: -- Square roots cannot be taken of negative numbers. ---- -- whereas the result of showSumOrErrorOf (-1) (-1) is the -- string, -- --
-- Error computing the square root of -1: -- Square roots cannot be taken of negative numbers. ---- -- Note how the error message only appears once; this is because the -- process of combining the error messages automatically eliminates all -- identical headings under the assumption that they came from the same -- original computation, as was the case here. -- -- Currently, the definition of sumWithError is largely -- boilerplate. Happily, the Haskell community has done a lot of work to -- identify patterns such as these and to write libraries that allow us -- to express them concisely. In particular, a standard trick when -- working with errors like this is to express the calculation as a -- Monad, such as by using the following definition: -- --
-- sumWithError_2 argument1 argument2 = do -- value1 <- argument1 -- value2 <- argument2 -- return (value1 + value2) ---- -- Or, even more concisely: -- --
-- sumWithError_3 = liftM2 (+) ---- -- Unfortunately though, neither of these definitions have the same -- semantics as the original sumWithError, as using both we get -- the following error message for showSumOrErrorOf (-1) (-2): -- --
-- Error computing the square root of -1: -- Square roots cannot be taken of negative numbers. ---- -- That is, we have lost the second of the two error messages. The reason -- for this is that Monad-style error processing expresses the -- computation as a sequence, and gives up as soon as it sees any error. -- In this case of sumWithError, however, the evaluation of the -- second argument can proceed even if there was an error in the first -- argument. Thus, rather than using a Monad pattern, we use an -- Applicative pattern: -- --
-- sumWithError_4 = liftA2 (+) ---- -- Now both error messages are displayed. module Data.ErrorMessage newtype ErrorMessage ErrorMessage :: Map String Doc -> ErrorMessage unwrapErrorMessage :: ErrorMessage -> Map String Doc -- | The function errorMessage takes a heading and a body and -- produce an ErrorMessage object from them; this can be considered to be -- a thin wrapper around Data.Map.singleton. errorMessage :: String -> Doc -> ErrorMessage -- | The function errorMessageText is similar to the function -- errorMessage, but for the body it takes a String instead -- of a Doc. It is provided for convenience. errorMessageText :: String -> String -> ErrorMessage -- | Use this function when you want to create an error message from a -- multi-line string. -- -- Although one could alternatively use errorMessageText, if one -- were to do this then one would only see only the first line of be -- indented when the error message is formatted for output. For example, -- --
-- errorMessageText "A poem:" "Roses are red.\nViolets are blue." ---- -- produces the following (formatted) error message: -- --
-- A poem: -- Roses are red. -- Violets are blue. ---- -- The reason for this is because the line breaks are not known to the -- Doc combinators, and so the indentation is not handled -- properly. The function errorMessageTextFromMultilineString -- takes care of this for you. For example, -- --
-- errorMessageTextFromMultilineString "A poem:" "Roses are red.\nViolets are blue." ---- -- produces the following (formatted) error message: -- --
-- A poem: -- Roses are red. -- Violets are blue. --errorMessageTextFromMultilineString :: String -> String -> ErrorMessage -- | Since one usually wants to return not just an ErrorMessage, but a -- value of the form Left error_message, the function -- leftErrorMessage is provided as a convenience; it creates the -- error message, and then wraps it inside of Left. leftErrorMessage :: String -> Doc -> Either ErrorMessage a -- | The function leftErrorMessageText is errorMessageText -- composed with the Left constructor for convenience. leftErrorMessageText :: String -> String -> Either ErrorMessage a -- | The function leftErrorMessageTextFromMultilineString is -- errorMessageTextFromMultilineString composed with the -- Left constructor for convenience. leftErrorMessageTextFromMultilineString :: String -> String -> Either ErrorMessage a -- | This function takes an ErrorMessage and formats it into a -- Doc. It does this by converting the headings into text -- objects, merging them with their respective bodies (the latter having -- been indented by four spaces), and then concatenating the result. formatErrorMessage :: ErrorMessage -> Doc -- | This is the utility function used by formatErrorMessage to -- format a Doc given a heading and a body; it indents the body by -- four spaces and then appends it after the heading. formatMessageWithHeading :: String -> Doc -> Doc -- | This function takes a list of values which might contain errors and -- returns either a list of the errors found in the values or the full -- list of results. Note that there is no restriction on the type of the -- errors. gatherResultsOrErrors :: [Either e a] -> Either [e] [a] -- | This function is similar to gatherResultsOrErrors, but instead -- of returning a list of errors it combines them into a single error. -- Note that only restriction on the type of the error is that it be an -- instance of Monoid, so this operation is not limited to -- ErrorMessages but could also be used for, say, Docs, as -- in the following example: -- --
-- dictionary_mapping_words_to_lengths :: [(String,Int)]
-- dictionary_mapping_words_to_lengths =
-- [("foo",3)
-- ,("bar",3)
-- ]
--
-- getWordLengthsOrError :: [String] -> Either ErrorMessage [Int]
-- getWordLengthsOrError =
-- mapLeft
-- (errorMessage
-- "Error looking up the following words in the dictionary:"
-- )
-- .
-- gatherResultsOrError
-- .
-- map lookupAndReturnResultOrError
--
--
-- The function call
--
-- -- getWordLengthsOrError ["foo","apple","cat","bar"] ---- -- results in the following error message: -- --
-- Error looking up the following words in the dictionary: -- apple -- cat --gatherResultsOrError :: (Monoid e) => [Either e a] -> Either e [a] instance Monoid Doc instance Error Doc instance Monoid ErrorMessage instance Error ErrorMessage instance (Monoid e, Error e, Monad m) => Applicative (ErrorT e m) instance (Monoid e) => Applicative (Either e)