On Friday 01 October 2004 16:43, John Goerzen wrote: > One of the most important features of a modern language is, to me, > exceptions. I have found very little coverage of exceptions in Haskell, > what what coverage there was seemed to be centered on I/O.
There's three things one might call exceptions in Haskell: 1) IOErrors result from IO operations and can be caught in the IO monad. 2) Exceptions result from pure or IO code and can be caught in the IO monad. They are raised by calling raise (in pure code) or raiseIO (in IO code). They are also raised by pattern match failure, calls to error and things like division by zero. They are non-deterministic in the following sense: The expression '(raise exn1) + (raise exn2) :: Int' may raise either exception 'exn1' or exception 'exn2' depending on choice of compiler, optimization options, environment settings, current time of day, phase of moon, etc. It is because of this non-determinism that exceptions can _only_ be caught in the IO monad. Another consequence is that exceptions are not very useful for reporting errors in user input where determinism, reporting errors before starting a long computation, being able to report multiple errors, etc are useful. 3) Error values can be distinguished using the Maybe or Either types and/or using monads. For example, parsing command line arguments might yield: Right 42 or Left "Error: can't parse '42.0' - integer expected" The advantage of this approach is that the type system tracks where errors can propagate to so you can be confident that error checking is being performed _before_ spending 3 days computing a result and not when you go to write the answer. The disadvantage is that it is a bit tedious - but monads, lifting, etc. help a lot with this. In the following, I'll tak exclusively about the 2nd type (since the other two are obvious). > 1. Can exceptions be used in "pure" functions (outside of monads?) They can be raised in pure functions but can only be caught in IO functions. (If you simply want to change what exception is reported, that can be done in pure code.) > 2. How are these exceptions caught and handled aside from using bracket? There is a catch function with type: catch :: IO a -> (Exception -> IO a) -> IO a Built on top of this, are functions to do things like try-finally. One of my favourites is 'bracket' which takes an initial action, a final action and a middle action (in that order) and makes sure that the final action is performed even if the middle action fails. For example: bracket (open "/etc/passwd") hClose $ \ h -> do cs <- hGetContents h mapM crack (lines cs) The strange order of the arguments is to put the initial action (opening the file) next to the final action (closing the file) - which is often a good thing. > 3. Can I define my own exception types? Sadly, no. There is only one 'exception type'. You can use dynamics and encode new kinds of exceptions as Strings but that isn't very satisfactory. > 4. Can I write code that can catch and handle multiple different > exception types from a single block of code? You use standard Haskell pattern matching so, yes, you can catch multiple kinds of exceptions. They're not different types though. > 5. Is there anything different about working with exceptions in monads? Use raiseIO instead of raise to raise exceptions. > 6. Can I get a stack trace from ghc or hugs if an exception is never > caught and thus causes the program to terminate? Sadly, no. -- Alastair Reid _______________________________________________ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe