Exceptions, was Re: Hardware dependency

Adrian Hey ahey@iee.org
Mon, 01 Jun 1998 07:02:07 +0100 (BST)


After a long message about exception handling...
On Sun 17 May, I wrote:
> Anybody got any better ideas?

Well, if anybody does have any better ideas they obviously want to keep
them secret:-) I think I'll describe an exception handling system that I have
actually implemented. I'm not sure whether or not it would be possible
(let alone desirable) to do something similar in Clean. You'll probably all
think this is one of the worst hacks ever, but please don't laugh to much,
its the only way out of the 'black hole' of program abortion I could
think of and implement reasonably easily. Basically it goes like this..

Instead of having an abort function, have a 'trap' function instead.
In Clean I suppose the type of this function would be..
     trap :: (*World ->*World) -> a
What trap does is take a user definable 'ReStart' function as an argument
and resets the stack and begins executing the ReStart function
(much as Clean currently starts with Start).

But the problem with this is...

Its not really any better than aborting, virtually all information about
current program state and what it was doing just prior to the trap has
been lost. You could pass some information as an additional curried
argument to the ReStart function, but not much. So to get around this I used
a global mutable 'program state' variable which could be set and read as
part of the IO system. I suppose in Clean you could have something like
      setState :: ProgStateType -> *World -> *World
or perhaps (in the case of Clean), one of the Clean sub-worlds would be
a more appropriate place. (I'm not really all that familiar with the
Clean IO system yet.)

But the problem with this is..

In a lazy language, you couldn't be certain that the expression that caused
the exception wasn't part of the program state. If it was, then reducing
this expression later would result in a trap, and later on another trap
and later on another trap ... To avoid this it is necessary for the
'setState' function to go and look for traps before the state update
is made. The easy way to do this is to completely evaluate the new state
expression first, but its not very lazy. Its one saving grace is that
it's still 'top down' reduction, but done eagerly (in the sense that it
evaluates expressions that may not be required for program output).

But the problem with this is..

It will only work if the state evaluation terminates. If the state
expression contains things like 'infinite lists' etc.. (which are so
often used in lazy languages) then we've got a problem. Perhaps it
wouldn't be too much to ask of programmers to avoid this (after all,
if you try using the same tricks in ML you've got the same problem).
I suppose you could argue that even these would eventually terminate with
an exception of some kind when heap space was exhausted, but this might
take a _very_ long time in some circumstances. 
 
And this is where I got stuck.

Perhaps it really isn't possible to have sensible exception handling in a
lazy language. If this sort of scheme causes all these problems then
I'm tempted to say one might as well just give up and use strict evaluation
with ML style exception handling. The only way out of this particular hole
that I can think of would be to implement some kind of scheme like the one
I suggested in my previous message (but I haven't figured out a way to do this
easily). This would allow 'infinite' expressions, provided you knew that they
could never result in an exception.

I suppose I could repeat the question..
> Anybody got any better ideas?

or is everybody quite happy to have their programs abort :-(
Perhaps there's a better way to do this in Clean.

Regards,
-- 
Adrian Hey