-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Gregory Crosswhite
committed
Dec 3, 2009
1 parent
4cf7da4
commit 9b19057
Showing
3 changed files
with
129 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
#--unknown-language--@+leo-ver=4-thin | ||
#--unknown-language--@+node:gcross.20091203120301.1652:@shadow README | ||
#--unknown-language--@@language text | ||
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. | ||
#--unknown-language--@nonl | ||
#--unknown-language--@-node:gcross.20091203120301.1652:@shadow README | ||
#--unknown-language--@-leo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters