An attempt was made to evaluate an element of an
array that had not been initialized.

ErrorCall

The ErrorCall exception is thrown
by error. The String
argument of ErrorCall is the string
passed to error when it was
called.

ExitException

The ExitException exception is
thrown by System.exitWith (and
System.exitFailure). The
ExitCode argument is the value passed to
System.exitWith. An unhandled
ExitException exception in the main
thread will cause the program to be terminated with the
given exit code.

NoMethodError

An attempt was made to invoke a class method which has
no definition in this instance, and there was no default
definition given in the class declaration. GHC issues a
warning when you compile an instance which has missing
methods.

PatternMatchFail

A pattern matching failure. The
String argument should contain a
descriptive message including the function name, source file
and line number.

RecSelError

A field selection was attempted on a constructor that
doesn't have the requested field. This can happen with
multi-constructor records when one or more fields are
missing from some of the constructors. The
String argument gives the location of the
record selection in the source program.

RecConError

An attempt was made to evaluate a field of a record
for which no value was given at construction time. The
String argument gives the location of the
record construction in the source program.

RecUpdError

An attempt was made to update a field in a record,
where the record doesn't have the requested field. This can
only occur with multi-constructor records, when one or more
fields are missing from some of the constructors. The
String argument gives the location of the
record update in the source program.

AssertionFailed

This exception is thrown by the
assert operation when the condition
fails. The String argument contains the
location of the assertion in the source program.

Asynchronous exceptions. These are described in more
detail in Section 5.12.7. The
types of asynchronous exception are:

StackOverflow

The current thread's stack exceeded its limit.
Since an exception has been raised, the thread's stack
will certainly be below its limit again, but the
programmer should take remedial action
immediately.

HeapOverflow

The program's heap is reaching its limit, and
the program should take action to reduce the amount of
live data it has[3][4].

ThreadKilled

This exception is raised by another thread
calling killThread (see Section 3.2), or by the system
if it needs to terminate the thread for some
reason.

From the IO monad, exceptions may be
thrown using ioError (from module
IO):

ioError :: IOError -> IO a

(recall that IOError is a synonym for
Exception.

You may be wondering what the difference between these two
functions is, after all the type of ioError is
just an instance of the type of throw, so you
could use throw everywhere and forget about
ioError, right? This is mostly true, but there
is one subtle difference between the two functions:

The simplest version is catch. It
takes a single argument, runs it, and if an exception is raised
the "handler" is executed passing the value of the exception.
Otherwise, the result is returned as normal. For example:

Note that due to Haskell's unspecified evaluation order, an
expression may return one of several possible exceptions: consider
the expression error "urk" + 1 `div` 0. Does
catch execute the handler passing
ErrorCall "urk", or ArithError
DivideByZero?

The answer is "either": catch makes a
non-deterministic choice about which exception to catch. If you
call it again, you might get a different exception back. This is
ok, because catch is an IO
computation.

The function catchJust takes an extra
argument which is an exception predicate, a
function which selects which type of exceptions we're interested
in. The full set of exception predicates is given below:

Any other exceptions which aren't matched by the predicate
are re-raised, and may be caught by an enclosing
catch or
catchJust.

NOTE: The Prelude also exports a function
called catch which has the same type as
Exception.catch, the difference being that the
Prelude version only catches the IO and user
families of exceptions (as required by Haskell 98). We recommend
either hiding the Prelude version of
catch when importing
Exception, or importing
Exception qualified, to avoid
name-clashes.

The difference is that instead of executing a handler when
an exception is caught, these functions return an
Either result, with Right a
indicating success, and Left e indicating that
exception e was raised.

Because the Exception datatype isn't
extensible, we added an interface for throwing and catching
exceptions of type Dynamic (see Section 5.11), which allows exception values of any type
in the Typeable class to be thrown and caught.

bracket works as follows: it executes
its first argument ("open"), then its third argument, followed
finally by its second argument ("close"). If the third argument
happened to raise an exception, then the close operation will
still be performed, and the exception will be re-raised.

This means that in the example above the file will always be
closed, even if an error occurs during processing.

The arguments to bracket are in this
order so that we can partially apply it, like:

withFile name = bracket (openFile name) hClose

The bracket_ function is a
variant of bracket that throws away the
result of the open, and finally is an even
simpler version where we just want some closing code.

Asynchronous exceptions are so-called because they arise due
to external influences, and can be raised at any point during
execution. StackOverflow and
HeapOverflow are two examples of
system-generated asynchronous exceptions.

The primary source of asynchronous exceptions, however, is
throwTo, from the Concurrent
library (see Section 3.2):

throwTo :: ThreadId -> Exception -> IO ()

throwTo allows one running thread to
raise an arbitrary exception in another thread. The exception is
therefore asynchronous with respect to the target thread, which
could be doing anything at the time it receives the exception.
Great care should be taken with asynchronous exceptions; it is all
too easy to introduce race conditions by the over zealous use of
throwTo.

There are two functions which allow a thread to control the
delivery of asynchronous exceptions during critical
sections:

block :: IO () -> IO ()
unblock :: IO () -> IO ()

Applying block to a computation will
execute that computation with asynchronous exceptions
blocked. That is, any thread which
attempts to raise an exception in the current thread will be
blocked until asynchronous exceptions are enabled again. There's
no need to worry about re-enabling asynchronous exceptions; that's
done automatically on exiting the scope of
block.

To re-enable asynchronous exceptions inside the scope of
block, unblock can be
used. It scopes in exactly the same way, so on exit from
unblock asynchronous exception delivery will
be disabled again.

For some examples of the use of these functions, see the
definitions of finally and
bracket in the sources to the
Exception module.

There's an implied block around every
exception handler in a call to one of the
catch family of functions. This is because
that's what you want most of the time - it eliminates a common
race condition in starting an exception handler, because there
may be no exception handler on the stack to handle another
exception if one arrives immediately. If asynchronous
exceptions are blocked on entering the handler, though, we have
time to install a new exception handler before being
interrupted. If this weren't the default, you'd have to write
something like

block (
catch (unblock (...))
(\e -> handler)
)

If you need to unblock asynchronous exceptions again in
the exception handler, just use
unblock as normal.

Note that try and friends
don't have a similar default, because there
is no exception handler in this case. If you want to use
try in an asynchronous-exception-safe way,
you'll need to use block.

Some operations are interruptible,
which means that they can receive asynchronous exceptions even
in the scope of a block. Any function
which may itself block is defined as interruptible; this
includes takeMVar, and most I/O-performing
operations. The reason for having interruptible operations is
so that we can write things like

block (
a <- takeMVar m
catch (unblock (...))
(\e -> ...)
)

if the takeMVar wasn't interruptible,
then this particular combination could lead to deadlock, because
the thread itself would be blocked in a state where it can't
receive any asynchronous exceptions. With
takeMVar interruptible, however, we can be
safe in the knowledge that the thread can receive exceptions
right up until the point when the takeMVar
succeeds. Similar arguments apply for other interruptible
operations like IO.openFile.