Drop "zero or plus" section of the description
[packages/mtl.git] / Control / Monad / Except.hs
1 {-# LANGUAGE CPP #-}
2 {- |
3 Module : Control.Monad.Error
4 Copyright : (c) Michael Weber <michael.weber@post.rwth-aachen.de> 2001,
5 (c) Jeff Newbern 2003-2006,
6 (c) Andriy Palamarchuk 2006
7 License : BSD-style (see the file LICENSE)
8
9 Maintainer : libraries@haskell.org
10 Stability : experimental
11 Portability : non-portable (multi-parameter type classes)
12
13 [Computation type:] Computations which may fail or throw exceptions.
14
15 [Binding strategy:] Failure records information about the cause\/location
16 of the failure. Failure values bypass the bound function,
17 other values are used as inputs to the bound function.
18
19 [Useful for:] Building computations from sequences of functions that may fail
20 or using exception handling to structure error handling.
21
22 [Example type:] @'Data.Either' String a@
23
24 The Error monad (also called the Exception monad).
25 -}
26
27 {-
28 Rendered by Michael Weber <mailto:michael.weber@post.rwth-aachen.de>,
29 inspired by the Haskell Monad Template Library from
30 Andy Gill (<http://web.cecs.pdx.edu/~andy/>)
31 -}
32 module Control.Monad.Except
33 (
34 -- * Monads with error handling
35 MonadError(..),
36 -- * The ErrorT monad transformer
37 ExceptT(ExceptT),
38 Except,
39
40 runExceptT,
41 mapExceptT,
42 withExceptT,
43 runExcept,
44 mapExcept,
45 withExcept,
46
47 module Control.Monad,
48 module Control.Monad.Fix,
49 module Control.Monad.Trans,
50 -- * Example 1: Custom Error Data Type
51 -- $customErrorExample
52
53 -- * Example 2: Using ExceptT Monad Transformer
54 -- $ExceptTExample
55 ) where
56
57 import Control.Monad.Error.Class
58 import Control.Monad.Trans
59 import Control.Monad.Trans.Except
60 ( ExceptT(ExceptT), Except, except
61 , runExcept, runExceptT
62 , mapExcept, mapExceptT
63 , withExcept, withExceptT
64 )
65
66 import Control.Monad
67 import Control.Monad.Fix
68
69 #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ < 707
70 import Control.Monad.Instances ()
71 #endif
72
73 {- $customErrorExample
74 Here is an example that demonstrates the use of a custom error data type with
75 the 'throwError' and 'catchError' exception mechanism from 'MonadError'.
76 The example throws an exception if the user enters an empty string
77 or a string longer than 5 characters. Otherwise it prints length of the string.
78
79 >-- This is the type to represent length calculation error.
80 >data LengthError = EmptyString -- Entered string was empty.
81 > | StringTooLong Int -- A string is longer than 5 characters.
82 > -- Records a length of the string.
83 > | OtherError String -- Other error, stores the problem description.
84 >
85 >-- Converts LengthError to a readable message.
86 >instance Show LengthError where
87 > show EmptyString = "The string was empty!"
88 > show (StringTooLong len) =
89 > "The length of the string (" ++ (show len) ++ ") is bigger than 5!"
90 > show (OtherError msg) = msg
91 >
92 >-- For our monad type constructor, we use Either LengthError
93 >-- which represents failure using Left LengthError
94 >-- or a successful result of type a using Right a.
95 >type LengthMonad = Either LengthError
96 >
97 >main = do
98 > putStrLn "Please enter a string:"
99 > s <- getLine
100 > reportResult (calculateLength s)
101 >
102 >-- Wraps length calculation to catch the errors.
103 >-- Returns either length of the string or an error.
104 >calculateLength :: String -> LengthMonad Int
105 >calculateLength s = (calculateLengthOrFail s) `catchError` Left
106 >
107 >-- Attempts to calculate length and throws an error if the provided string is
108 >-- empty or longer than 5 characters.
109 >-- The processing is done in Either monad.
110 >calculateLengthOrFail :: String -> LengthMonad Int
111 >calculateLengthOrFail [] = throwError EmptyString
112 >calculateLengthOrFail s | len > 5 = throwError (StringTooLong len)
113 > | otherwise = return len
114 > where len = length s
115 >
116 >-- Prints result of the string length calculation.
117 >reportResult :: LengthMonad Int -> IO ()
118 >reportResult (Right len) = putStrLn ("The length of the string is " ++ (show len))
119 >reportResult (Left e) = putStrLn ("Length calculation failed with error: " ++ (show e))
120 -}
121
122 {- $ExceptTExample
123 @'ExceptT'@ monad transformer can be used to add error handling to another monad.
124 Here is an example how to combine it with an @IO@ monad:
125
126 >import Control.Monad.Except
127 >
128 >-- An IO monad which can return String failure.
129 >-- It is convenient to define the monad type of the combined monad,
130 >-- especially if we combine more monad transformers.
131 >type LengthMonad = ExceptT String IO
132 >
133 >main = do
134 > -- runExceptT removes the ExceptT wrapper
135 > r <- runExceptT calculateLength
136 > reportResult r
137 >
138 >-- Asks user for a non-empty string and returns its length.
139 >-- Throws an error if user enters an empty string.
140 >calculateLength :: LengthMonad Int
141 >calculateLength = do
142 > -- all the IO operations have to be lifted to the IO monad in the monad stack
143 > liftIO $ putStrLn "Please enter a non-empty string: "
144 > s <- liftIO getLine
145 > if null s
146 > then throwError "The string was empty!"
147 > else return $ length s
148 >
149 >-- Prints result of the string length calculation.
150 >reportResult :: Either String Int -> IO ()
151 >reportResult (Right len) = putStrLn ("The length of the string is " ++ (show len))
152 >reportResult (Left e) = putStrLn ("Length calculation failed with error: " ++ (show e))
153 -}