[Haskell] Better Exception Handling
Scott Turner
p.turner at computer.org
Wed Nov 24 11:21:58 EST 2004
On 2004 November 23 Tuesday 10:51, John Goerzen wrote:
> > for pure functions, returning Either Error Result is the way to go.
> One example: I've written an FTP client library. For every operation,
> there are several possible outcomes... mainly: success, low-level
> network error, or server error.
>
> Having to pick apart an Either from every command to CD, set transfer
> types, etc. would get so tedious that the code would, I think, become
> spaghetti fast.
The way to deal with those kinds of details is to use Either in a monad. I'm
skeptical of the need for dynamic scope in conventional exception handling,
so I took a shot at this problem, with satisfying results. (I'm not keen on
dynamic typing for that matter, but don't know of a nice way to avoid it.)
Excerpts are below. The full sample code is at
http://pkturner.org/exception.tar
The Haskell Main module using the FTP library is comparable to your Python
example.
main = runException $ do
ftp("ftp.kernel.org")
( cwd "pub/linux/kernel/v2.4"
`except` (\(ErrorPerm e) -> lift $ do
putStrLn ("caught temp error in cwd: " ++ e)
exitWith (ExitFailure 2))
)
retrbinary "RETR ChangeLog-2.4.13"
(\block -> write block)
quit
`except` (\(ErrorPerm e) -> lift $ do
putStrLn ("Permissions error " ++ e)
exitWith (ExitFailure 2))
`except` (\(ErrorTemp e) -> lift $ do
putStrLn ("Temporary error, please try again later" ++ e)
exitWith (ExitFailure 1))
`except` (\(ErrorFTP e) -> lift $ do
putStrLn ("Other FTP error" ++ e)
exitWith (ExitFailure 2))
`except` (\(ErrorAll e) -> lift $ do
putStrLn ("Non-FTP error" ++ e)
exitWith (ExitFailure 3))
Also, the FTP module demonstrates that it's straightforward to add new classes
of errors in the exception hierarchy.
data ErrorPerm = ErrorPerm String
deriving (Typeable)
instance Hierarchical ErrorPerm where
parent (ErrorPerm msg) = Parent $ ErrorFTP msg
data ErrorTemp = ErrorTemp String
deriving (Typeable)
instance Hierarchical ErrorTemp where
parent (ErrorTemp msg) = Parent $ ErrorFTP msg
data ErrorFTP = ErrorFTP String
deriving (Typeable)
instance Hierarchical ErrorFTP where
parent (ErrorFTP msg) = Parent $ ErrorAll msg
type FTP = Exception IO
ftp :: String -> FTP ()
ftp str = if take 3 str == "ftp"
then lift (return ())
else raise $ ErrorPerm ("ftp " ++ str)
More information about the Haskell
mailing list