[clean-list] Clean in the Real World

Marco Kesseler m.wittebrood@mailbox.kun.nl
Tue, 16 Dec 2003 00:23:07 +0100


>On Mon, Dec 15, 2003 at 03:02:25PM +0100, Marco Kesseler wrote:
>> Apart from that, the same non-deterministic effects will occur in the 
>> Monadic solution. The fact that this is theoretically allowed may not 
>> help the average programmer in reasoning about his program.
>> 
>> (which does _not_ imply that I am against soundness)
>> 
>> And then, there is still the possibility to enforce catch statements 
>> to always deliver the same constant expression on any exception.
>
>(Disclaimer: I haven't read the Imprecise Exceptions paper.)
>I think I understand why one might want to put exception handling in
>a monad. Because, to preserve equational reasoning, with the existence
>of non-deterministic exceptions such as e.g. InputOutputException (disk
>full, network disconnected, etc.), it is not even
>enough to say that a catch statement must not expose
>anything about the exception that has occurred. It must _also_
>be able to reproduce the same value, if it it returns a value,
>as the guarded expression would have if it _could_ have returned!

The imprecise exception paper distinguises three types of exceptions:
* disaster-type, like dividision by zero.
* alternative return, like when you throw an exception to indicate 
that some search has failed.
* asynchronous exceptions, like "ctrl-C", or the I/O exceptions you 
mention above.

The whole discussion until now does not have to do with the 
asychronous exceptions. These are - by their very nature - related to 
I/O and thus indeed belong to either I/O Monad or a unique "World" 
state (well, in my view anyway).

The other two types - i.e. the synchronous ones - have the property 
that they can be "replayed". They will happen again, if you evaluate 
the same expression in exactly the same way. 

The problem now is, that a compiler (for a functional language) does 
not always have to evaluate the same expression in the same way. So 
depending on the evaluation order that the compiler chooses, the 
result of catching an exception may differ if you write down the same 
expression twice.

To come back to your remark: in case of a synchronous exception, 
there is no "real" return value, and there never will be, as the 
exception will always happen. So the catch statement is free to 
choose whatever value it wants.

>This implies that if a non-deterministic exception can possibly be
>thrown from a guarded expression, there are _only_ three possible
>"action outcomes" a handler can decide between:
>
>1. Retry evaluation
>2. Abort program entirely
>3. Throw an exception (possibly the same one that it has caught, 
>possibly not)
>
>(Retry, Abort, or Throw)
>
>Right? It cannot return a value other than through (1) since this would
>violate equational reasoning. I think that is clear.
>
>While Bertrand Meyer (not a functional-ist per se, but an advocate 
>of rigorous
>exception handling) might be happy with this tortuous arrangement, I
>personally am not. It seems too limiting (what about user interaction?)
>So it seems sensible to put _some_ exception handling in a
>non-referentially-transparent part of the system, which in the context
>of pure languages like Clean implies either (as a prior
>post suggested) in a separate process, or in a monad. I don't think
>uniqueness typing really works for this application, because of cases
>in which exceptions could occur all over the place, and therefore you'd
>have to pass around an exception-recording "World" state _everywhere_ -
>which rather changes the semantics of your program, as I previously argued.

This "trap" is basically the same for Monads, which is why I really 
want to avoid such a solution.

>Of course, if you want to sensibly deal with out of memory exceptions or
>such things, they certainly can occur all over the place, in general.

Out-of-memory exceptions, and stack overflows are actually not of the 
"replay" kind, so they can certainly not be handled by the solution 
that I proposed. It is also not clear (to me) how they should be 
handled if they were part of the IO Monad or the Unique World: (a) 
you need some memory to actually execute a handler and (b) you cannot 
manipulate the heap or the stack from within Clean or Haskell.

Marco

>-- 
>Robin
>
>"it's FREE and we get the ability to modify the source code ourselves,
>something that is extremely dangerous to do, was discredited decades ago..."
> - Howard Strauss writing in Syllabus magazine
>  http://www.syllabus.com/article.asp?id=8460
>