Ticket #1059: error.diff

File error.diff, 10.7 KB (added by Andriy, 7 years ago)

The patch

Line 
1
2New patches:
3
4[Converted the module documentation to Haddock format. Per Jeff Newbern's gracious permission included relevant information from his cool tutorial "All About Monads" http://www.nomaware.com/monads/. Added examples for custom error type, ErrorT. Use String instead of [Char].
5Andriy Palamarchuk <apa3a@yahoo.com>**20070115222741] {
6hunk ./Control/Monad/Error.hs 4
7------------------------------------------------------------------------------
8--- |
9--- Module      :  Control.Monad.Error
10--- Copyright   :  (c) Michael Weber <michael.weber@post.rwth-aachen.de>, 2001
11--- License     :  BSD-style (see the file libraries/base/LICENSE)
12---
13--- Maintainer  :  libraries@haskell.org
14--- Stability   :  experimental
15--- Portability :  non-portable (multi-parameter type classes)
16---
17--- The Error monad.
18---
19--- Rendered by Michael Weber <mailto:michael.weber@post.rwth-aachen.de>,
20---     inspired by the Haskell Monad Template Library from
21---     Andy Gill (<http://www.cse.ogi.edu/~andy/>)
22---
23------------------------------------------------------------------------------
24+{- |
25+Module      :  Control.Monad.Error
26+Copyright   :  (c) Michael Weber <michael.weber@post.rwth-aachen.de> 2001,
27+      (c) Jeff Newbern 2003-2006,
28+      (c) Andriy Palamarchuk 2006
29+License     :  BSD-style (see the file libraries/base/LICENSE)
30+
31+Maintainer  :  libraries@haskell.org
32+Stability   :  experimental
33+Portability :  non-portable (multi-parameter type classes)
34hunk ./Control/Monad/Error.hs 15
35+[Computation type:] Computations which may fail or throw exceptions.
36+
37+[Binding strategy:] Failure records information about the cause\/location
38+of the failure. Failure values bypass the bound function,
39+other values are used as inputs to the bound function.
40+
41+[Useful for:] Building computations from sequences of functions that may fail
42+or using exception handling to structure error handling.
43+
44+[Zero and plus:] Zero is represented by an empty error and the plus operation
45+executes its second argument if the first fails.
46+
47+[Example type:] @'Data.Either' String a@
48+
49+The Error monad (also called the Exception monad).
50+-}
51+
52+{-
53+  Rendered by Michael Weber <mailto:michael.weber@post.rwth-aachen.de>,
54+  inspired by the Haskell Monad Template Library from
55+    Andy Gill (<http://www.cse.ogi.edu/~andy/>)
56+-}
57hunk ./Control/Monad/Error.hs 45
58+  -- * Example 1: Custom Error Data Type
59+  -- $customErrorExample
60+
61+  -- * Example 2: Using ErrorT Monad Transformer
62+  -- $ErrorTExample
63hunk ./Control/Monad/Error.hs 66
64--- ---------------------------------------------------------------------------
65--- class MonadError
66---
67---    throws an exception inside the monad and thus interrupts
68---    normal execution order, until an error handler is reached}
69---
70---    catches an exception inside the monad (that was previously
71---    thrown by throwError
72-
73+-- | An exception to be thrown.
74+-- An instance must redefine at least one of 'noMsg', 'strMsg'.
75hunk ./Control/Monad/Error.hs 69
76+  -- | Creates an exception without a message.
77+  -- Default implementation is @'strMsg' \"\"@.
78hunk ./Control/Monad/Error.hs 72
79+  -- | Creates an exception with a message.
80+  -- Default implementation is 'noMsg'.
81hunk ./Control/Monad/Error.hs 76
82-       noMsg    = strMsg ""
83-       strMsg _ = noMsg
84+noMsg    = strMsg ""
85+strMsg _ = noMsg
86hunk ./Control/Monad/Error.hs 79
87-instance Error [Char] where
88+-- | A string can be thrown as an error.
89+instance Error String where
90hunk ./Control/Monad/Error.hs 87
91+{- |
92+The strategy of combining computations that can throw exceptions
93+by bypassing bound functions
94+from the point an exception is thrown to the point that it is handled.
95+
96+Is parameterized over the type of error information and
97+the monad type constructor.
98+It is common to use @'Data.Either' String@ as the monad type constructor
99+for an error monad in which error descriptions take the form of strings.
100+In that case and many other common cases the resulting monad is already defined
101+as an instance of the 'MonadError' class.
102+You can also define your own error type and\/or use a monad type constructor
103+other than @'Data.Either' String@ or @'Data.Either' IOError@.
104+In these cases you will have to explicitly define instances of the 'Error'
105+and\/or 'MonadError' classes.
106+-}
107hunk ./Control/Monad/Error.hs 104
108+  -- | Is used within a monadic computation to begin exception processing.
109hunk ./Control/Monad/Error.hs 106
110-       catchError :: m a -> (e -> m a) -> m a
111+
112+  {- |
113+  A handler function to handle previous errors and return to normal execution.
114+  A common idiom is:
115+
116+  > do { action1; action2; action3 } `catchError` handler
117+
118+  where the @action@ functions can call 'throwError'.
119+  Note that @handler@ and the do-block must have the same return type.
120+  -}
121+  catchError :: m a -> (e -> m a) -> m a
122hunk ./Control/Monad/Error.hs 152
123--- ---------------------------------------------------------------------------
124--- Our parameterizable error monad, with an inner monad
125+{- |
126+The error monad transformer. It can be used to add error handling to other
127+monads.
128hunk ./Control/Monad/Error.hs 156
129-newtype ErrorT e m a = ErrorT { runErrorT :: m (Either e a) }
130+The @ErrorT@ Monad structure is parameterized over two things:
131+
132+ * e - The error type.
133+
134+ * m - The inner monad.
135+
136+Here are some examples of use:
137hunk ./Control/Monad/Error.hs 164
138--- The ErrorT Monad structure is parameterized over two things:
139---     * e - The error type.
140---     * m - The inner monad.
141+> -- wraps IO action that can throw an error e
142+> type ErrorWithIO e a = ErrorT e IO a
143+> ==> ErrorT (IO (Either e a))
144+>
145+> -- IO monad wrapped in StateT inside of ErrorT
146+> type ErrorAndStateWithIO e s a = ErrorT e (StateT s IO) a
147+> ==> ErrorT (StateT s IO (Either e a))
148+> ==> ErrorT (StateT (s -> IO (Either e a,s)))
149+-}
150+
151+newtype ErrorT e m a = ErrorT { runErrorT :: m (Either e a) }
152hunk ./Control/Monad/Error.hs 176
153--- Here are some examples of use:
154---
155---   type ErrorWithIO e a = ErrorT e IO a
156---     ==> ErrorT (IO (Either e a))
157---
158---   type ErrorAndStateWithIO e s a = ErrorT e (StateT s IO) a
159---     ==> ErrorT (StateT s IO (Either e a))
160---     ==> ErrorT (StateT (s -> IO (Either e a,s)))
161---
162hunk ./Control/Monad/Error.hs 274
163+{- $customErrorExample
164+Here is an example that demonstrates the use of a custom 'Error' data type with
165+the 'ErrorMonad'\'s 'throwError' and 'catchError' exception mechanism.
166+The example throws an exception if the user enters an empty string
167+or a string longer than 5 characters. Otherwise it prints length of the string.
168+
169+>-- This is the type to represent length calculation error.
170+>data LengthError = EmptyString  -- Entered string was empty.
171+>          | StringTooLong Int   -- A string is longer than 5 characters.
172+>                                -- Records a length of the string.
173+>          | OtherError String   -- Other error, stores the problem description.
174+>
175+>-- We make LengthError an instance of the Error class
176+>-- to be able to throw it as an exception.
177+>instance Error LengthError where
178+>  noMsg    = OtherError "A String Error!"
179+>  strMsg s = OtherError s
180+>
181+>-- Converts LengthError to a readable message.
182+>instance Show LengthError where
183+>  show EmptyString = "The string was empty!"
184+>  show (StringTooLong len) =
185+>      "The length of the string (" ++ (show len) ++ ") is bigger than 5!"
186+>  show (OtherError msg) = msg
187+>
188+>-- For our monad type constructor, we use Either LengthError
189+>-- which represents failure using Left LengthError
190+>-- or a successful result of type a using Right a.
191+>type LengthMonad = Either LengthError
192+>
193+>main = do
194+>  putStrLn "Please enter a string:"
195+>  s <- getLine
196+>  reportResult (calculateLength s)
197+>
198+>-- Wraps length calculation to catch the errors.
199+>-- Returns either length of the string or an error.
200+>calculateLength :: String -> LengthMonad Int
201+>calculateLength s = (calculateLengthOrFail s) `catchError` Left
202+>
203+>-- Attempts to calculate length and throws an error if the provided string is
204+>-- empty or longer than 5 characters.
205+>-- The processing is done in Either monad.
206+>calculateLengthOrFail :: String -> LengthMonad Int
207+>calculateLengthOrFail [] = throwError EmptyString
208+>calculateLengthOrFail s | len > 5 = throwError (StringTooLong len)
209+>                        | otherwise = return len
210+>  where len = length s
211+>
212+>-- Prints result of the string length calculation.
213+>reportResult :: LengthMonad Int -> IO ()
214+>reportResult (Right len) = putStrLn ("The length of the string is " ++ (show len))
215+>reportResult (Left e) = putStrLn ("Length calculation failed with error: " ++ (show e))
216+-}
217+
218+{- $ErrorTExample
219+@'ErrorT'@ monad transformer can be used to add error handling to another monad.
220+Here is an example how to combine it with an @IO@ monad:
221+
222+>import Control.Monad.Error
223+>
224+>-- An IO monad which can return String failure.
225+>-- It is convenient to define the monad type of the combined monad,
226+>-- especially if we combine more monad transformers.
227+>type LengthMonad = ErrorT String IO
228+>
229+>main = do
230+>  -- runErrorT removes the ErrorT wrapper
231+>  r <- runErrorT calculateLength
232+>  reportResult r
233+>
234+>-- Asks user for a non-empty string and returns its length.
235+>-- Throws an error if user enters an empty string.
236+>calculateLength :: LengthMonad Int
237+>calculateLength = do
238+>  -- all the IO operations have to be lifted to the IO monad in the monad stack
239+>  liftIO $ putStrLn "Please enter a non-empty string: "
240+>  s <- liftIO getLine
241+>  if null s
242+>    then throwError "The string was empty!"
243+>    else return $ length s
244+>
245+>-- Prints result of the string length calculation.
246+>reportResult :: Either String Int -> IO ()
247+>reportResult (Right len) = putStrLn ("The length of the string is " ++ (show len))
248+>reportResult (Left e) = putStrLn ("Length calculation failed with error: " ++ (show e))
249+-}
250+
251}
252
253Context:
254
255[Added Haddock documentation. Converted the module documentation to Haddock format. Per Jeff Newbern's permission included parts his tutorial "All About Monads" http://www.nomaware.com/monads/.
256Andriy Palamarchuk <apa3a@yahoo.com>**20061218165621]
257[add boilerplate Setup.hs
258Ross Paterson <ross@soi.city.ac.uk>**20060928231525]
259[use Control.Monad.Instances from base
260Ross Paterson <ross@soi.city.ac.uk>**20060410112533]
261[Add -fallow-undecidable-instances to some Control.Monad modules
262simonpj@microsoft.com**20060209121334
263 
264 I have recently tightened up GHC's implementation of the coverage
265 condition.  As a result some of the Control.Monad modules are rejected.
266 
267 Example:
268   class (Monad m) => MonadReader r m | m -> r where
269   instance (Monoid w, MonadReader r m) => MonadReader r (WriterT w m)
270 Here, fv(Writer w m) is not a superset of fv(r).
271 
272 The flag allows it.  I wonder if it's possible to use these modules
273 to send the type cheker into a loop.
274 
275 
276]
277[TAG Initial conversion from CVS complete
278John Goerzen <jgoerzen@complete.org>**20060112154134]
279Patch bundle hash:
280c6c1462ef1551bf85f5e505aaafbf26177a1c14b