The Exception library provides an interface for raising and catching both built-in and user defined exceptions.
Exceptions are defined by the following (non-abstract) datatype:
data Exception
= IOException IOError -- IO exceptions (from 'fail')
| ArithException ArithError -- Arithmetic exceptions
| ErrorCall String -- Calls to 'error'
| NoMethodError String -- A non-existent method was invoked
| PatternMatchFail String -- A pattern match failed
| NonExhaustiveGuards String -- A guard match failed
| RecSelError String -- Selecting a non-existent field
| RecConError String -- Field missing in record construction
| RecUpdError String -- Record doesn't contain updated field
| AssertionFailed String -- Assertions
| DynException Dynamic -- Dynamic exceptions
| ExternalException ExtError -- External exceptions
instance Eq Exception
instance Ord Exception
instance Show Exception
data ArithError
= Overflow
| Underflow
| LossOfPrecision
| DivideByZero
| Denormal
instance Eq ArithError
instance Ord ArithError
instance Show ArithError
data ExtError
= StackOverflow
| HeapOverflow
| ThreadKilled
instance Eq ExtError
instance Ord ExtError
instance Show ExtError
An implementation should raise the appropriate exception when one of the above conditions arises. Note: GHC currently doesn't generate the arithmetic or the external exceptions.
Exceptions may be thrown explicitly from anywhere:
throw :: Exception -> a
Exceptions may be caught and examined in the IO
monad:
catch :: IO a -> (Exception -> IO a) -> IO a
catchIO :: IO a -> (IOError -> IO a) -> IO a
catchArith :: IO a -> (ArithError -> IO a) -> IO a
catchError :: IO a -> (String -> IO a) -> IO a
getException :: a -> IO (Maybe Exception)
getExceptionIO :: IO a -> IO (Either Exception a)
Each of the functions catchIO
, catchArith
, and
catchError
only catch a specific type of exception. All other
exceptions are effectively re-thrown. An uncaught exception will
normally cause the program to terminate, with the offending exception
displayed.
Note that catchIO
is identical to IO.catch
. The
implementation of IO
errors in GHC and Hugs uses exceptions for
speed.
Also, don't forget to import Prelude hidiing (catch)
when using
this library, to avoid the name clash between Exception.catch
and
IO.catch
.
The getException
function is useful for evaluating a non-IO typed
value and testing for exceptions. getException
evaluates its
first argument (as if you'd applied seq
to it), returning
Just <exception>
if an exception was raised, or
Nothing
otherwise. Note that due to Haskell's unspecified
evaluation order, an expression may return one of several possible
exceptions: consider the expression error "urk" + 1
0/. Does
getException
return Just (ErrorCall "urk")
or Just
(ArithError DivideByZero)
? The answer is "either": getException
makes a non-deterministic choice about which exception to return. If
you call it again, you might get a different exception back. This is
ok, because getException
is an IO computation.
getExceptionIO
is the equivalent function for IO
computations
--- it runs its first argument, and returns either the return value or
the exception if one was raised. Passing a value of type IO a
to
getException
won't work, because the IO
type is represented
by a function, and getException
will only evaluate its argument
to head normal form, hence the IO
computation won't be
performed. Use getExceptionIO
instead.
Because the Exception
datatype isn't extendible, we added an
interface for throwing and catching exceptions of type Dynamic
(see Section
Dynamic), which allows
exception values of any type in the Typeable
class to be thrown
and caught.
throwDyn :: Typeable exception => exception -> b
catchDyn :: Typeable exception => IO a -> (exception -> IO a) -> IO a
The catchDyn
function only catches exceptions of the required
type; all other exceptions are re-thrown as with catchIO
and
friends above.