It's nice to have SOME way of handling exceptions, but...

> The implementation does not keep sets of exceptional values,
> of course.  It simply propagates the first one it trips
> over to the nearest enclosing handler.

One argument that can be made in favour of a generalised more IEEE-like
mechanism is that it is usually such a pain to handle an exception that
propagates like this that one most often does not bother to handle it
properly (i.e. try to continue with the task, which is usually the best
thing to do; user hitting 'break' or 'esc' excepted, but those are not
'exceptions' in this sense).  And in many cases, using some reasonable
'continuation value' (which have already been specified and widely
implemented for f.p. arithmetic) and a set of notes on exceptions that
have occurred, is sufficient and gives a nicer behaviour of the program.

Say that the application is to produce a simple function curve, for a
function given as argument, so only the type is known and no other
properties.  Say that it does this by computing a list of pairs later to
be turned into a nice-looking graph.  Say also that overflows occur, or
out-of-domain-errors occur.  Having these errors propagate up to an IO
monad or similar for handling, then having to restart, in the handler,
the graph calculation at the appropriate place is much more difficult to
handle (and is likely not to be done, or to be done in a buggy way) than
just plodding on as if (nearly) nothing out of the ordinary happened.  I
don't think that this situation is so exotic that one can safely ignore
it.  Indeed this behaviour has been specified as the default behaviour
for IEEE f.p.  And it is usually better to let the application continue
as normal, as long as no very critical error has occurred.  (Note that
not even divide-by-zero is considered critical in the IEEE world. It
does not even return a NaN, unless the numerator is also zero (or a
NaN).)

What one would need to do to obtain this, not that I'm suggesting it
very strongly, would be to generalise the IEEE model of exceptions from
f.p. arithmetic to values in general, including adding
Not-a-Proper-Value (NaPV) values to each non-f.p. datatype.  

A value of Haskell type T can be
         one of the values we know and love 
               (bottom, or constructor, or function,
                depending on T),
               or NaPV (except for f.p. datatypes
                which already have NaN values)

        AND, implicitly,  it has a set of exception values
        (this set is bottom if the value part is bottom).

Strict operations would propagate exceptions and NaPV values.
Certain predefined functions would be allowed to "read", or "replace"
the exception set part, something like:

add_exceptions :: a -> Exceptions -> a

where the Exceptions would be built into the result, and

read_and_clear_exceptions :: a -> (a -> Exceptions -> b) -> b

where the function argument would be given the value with cleared
Exceptions part, and as a second argument, the given Exceptions part.
And all is purely functional... (Unless I missed something.)

Yes, I have been ignoring performance issues.  Generating and keeping
Exceptions values around everywhere can be very taxing.  It would be
helpful to have an easy way of saying that the Exceptions part need not
be built-into the value (effectively clearing it, though the proper
Exceptions are propagated), changing the underlying datatype and
delaying the building-in.  It still may not be easy to get this very
efficient.  Indeed in the imperative (and IEEE arithmetic)world it is
never built-in, but one has one exceptions value per thread 'on the
side' (limited to arithmetic exceptions). (One such value per process is
not sufficient these days when multi-threaded processes are used.)

                        /kent k


Reply via email to