Application letters at the Haskell workshop: suggestion
Alastair David Reid
reid@cs.utah.edu
17 Sep 2001 20:13:04 -0600
Marcin 'Qrczak' Kowalczyk <qrczak@knm.org.pl> writes:
> Parsec [uses some variant of the error monad] and similar things. It
> tries to generate reasonable messages of the form "expecting foo,
> found bar" or "unexpected bar" annotated with source position,
> making use of labels of higher level syntactic constructs inserted
> in the grammar as well as individual characters matched.
I think this illustrates an important point about different approaches
to exception handling.
Parsing is a great example of where error monads are useful:
1) You expect the errors to be the common case instead of the
very unlikely case (so you're willing to expend quite a bit
of effort to handle them well).
Typecheckers also fit into this category.
2) You really care about what the error message looks like.
3) Your code is either all machine generated (e.g., by happy)
or you use combinators (e.g., >>= and return) so it is easy
to thread the error monad through and to be consistent about
doing it.
In these case, I think error monads are the best choice.
The Hugs/GHC exception catching that Andy Moran described is aimed at
situations where these don't apply. Cases include:
1) Your program has to manipulate some real world (and stateful)
object and it is not considered acceptable to leave it in some
confused state. Examples include leaving windows open when a GUI
equipped program crashes, a control system (like the joystick in a
plane or controls in a lift) that suddenly stops responding, leaving
a database in an inconsistent state, etc.
2) You write a library (e.g., Fran, HGL, etc.) where (hopefully)
carefully written library code (which can be as full of error
checks as you want) has to invoke user code and, somehow, recover
and, either keep going or shut down cleanly.
3) Someone gives you a great library but their code doesn't use the
error monad (or whatever) because the code was developed for a
less demanding execution environment. The library is large and
rewriting it is daunting.
4) You think you've used the error monad consistently and avoided
calling all those "unsafe" Prelude functions like "head", "tail",
"minimum", and "div" but you've got no good way of checking and
you want your code to be robust.
5) You really don't care much which exception you get - as long
as you get one.
I think the two approaches complement each other rather well (but, of
course, I'm biased...).
--
Alastair Reid reid@cs.utah.edu http://www.cs.utah.edu/~reid/