[clean-list] Clean in the Real World
Marco Kesseler
m.wittebrood@mailbox.kun.nl
Tue, 16 Dec 2003 21:04:13 +0100
>
>> You will:
>> (a) be able to apply equational reasoning within your program, in the
>> sense that if an exception occurs within foo, it will always deliver
>> the same result (baz), because it will always throw the same
>> exception, by virtue of the compiler generating a fixed evaluation
>> order for bar. If no exception occurs, everything will be as usual
>> and bar gets returned (but also see below).
>> (b) have compiler optimisations both in bar and baz, as it does not
>> matter which exception gets thrown in bar, as long as it is the same
>> one each time within a single program.
>
>I think you've missed the point here. Yes, you can still use equational
>reasoning in your system, but there are now fewer equations which are
>valid. For example, previously I had the equation
>
> a + b = b + a
>
>but now this doesn't apply. If you don't put the exception catcher in a
>nondeterminism monad (or similar), then your language ends up with fewer
>equational properties. This is precisely what we went to great lengths
>to avoid in Haskell.
Commutativity is NOT a property of all functions. '-' is not
commutative. '+' is not commutative because it uses the '+' symbol.
Commutativity can only be established after inspecting the function
definition.
Say that '+' has been defined like:
(+) a b = add a b.
'add' is a primitive operation that is strict in its arguments. It
first evaluates arg 1, then evaluates arg 2, and then adds them. All
of these steps may throw exceptions. Kind of a real world thing (for
all of you who wonder about this thread's subject).
'+' remains commutative here: no exception thrown inside (a + b) will
_ever_ influence the value of (a + b), as all exceptions will just
pass up to higher levels. These higher levels will _not_ be able to
establish the value of (a + b). They only know that some exception
was thrown while evaluating it.
Now suppose that we add a general catch to the '+' definition. Just
for the sake of the argument, because this is probably pointless for
a function like '+'.
(+) a b
= add a b
catch _ = NotANumber /* map any exception to this special value */
Now, '+' is _still_ commutative, because any exception maps to the
same value. Either everything goes well, and the value of (a + b)
gets computed, or something goes wrong, and NotANumber gets returned.
This happens for (a + b) and (b + a) alike.
We take the definition of (+) one step further:
(+) a b
= add a b
catch DivideByZero = NotANumber /* the only exception that we
handle */
catch e = throw e /* we pass all other exceptions to higher
levels */
We have now entered the twilight zone. In most cases, '+' will behave
the same as in the case were it has no handlers at all. Only if a
division by zero gets thrown first it will deliver NotANumber. This
means that for some a and b, (a + b) may deliver NotAnumber, while (b
+ a) may not deliver any value at all, because another exception got
thrown first. Is '+' still commutative? I don't know. For the values
I can check it is, but for the others? Let's assume it is not,
because I am in a good mood.
So, let's REALLY break commutativity!
(+) a b
= add a b
catch DivideByZero = NotANumber
catch _ = AVeryBigValue /* Sad */
Okay, so now we have defined a non-commutative '+'. Do we need
exceptions for that? No. If I want, I can define a non-commutative
'+' in Clean today. How about:
(+) a b = a - b.
I may well have missed the point, but I somehow doubt that this was it.
regards,
Marco
>_______________________________________________
>clean-list mailing list
>clean-list@cs.kun.nl
>http://www.cs.kun.nl/mailman/listinfo/clean-list