
Some examples of what might happen:
If you have more than one possible exception in your code, you don't
know which one you will get.
It can vary between compilers, optimization levels, program runs, or
even evaluating the same expression within one program.
If you have code that have both an infinite loop and an exception you
don't know if you'll get the loop or the exception.
Breaking the deterministic behaviour can lead to strange consequences,
because the compiler relies on it.
For instance, the following code
let x = someExpression
print x
print x
could print different values for x the two times you print it.
(This is somewhat unlikely, but could happen when evaluating in
parallel with ghc, because there is a small window where two threads
might start evaluating x and later update x with two different
values.)
-- Lennart
On Wed, Mar 25, 2009 at 11:39 AM, Xiao-Yong Jin
Jonathan Cast
writes: On Tue, 2009-03-24 at 23:13 -0700, Donn Cave wrote:
Quoth Duncan Coutts
: You must not do this. It breaks the semantics of the language.
Other people have given practical reasons why you should not but a theoretical reason is that you've defined a non-continuous function. That is impossible in the normal semantics of pure functional languages. So you're breaking a promise which we rely on.
Could you elaborate a little, in what sense are we (?) relying on it?
I actually can't find any responses that make a case against it on a really practical level - I mean, it seems to be taken for granted that it will work as intended,
It shouldn't be.
Consider:
loop = loop blam = error "blam" notReallyTry = unsafePerformIO . try . evaluate
Now, normally, we have, for all x, y,
x `seq` y `seq` x = y `seq` x
But we clearly do *not* have this for x = blam, y = loop, since the equality isn't preserved by notReallyTry:
notReallyTry $ blam `seq` loop `seq` blam = Left (ErrorCall "blam") notReallyTry $ loop `seq` blam = loop
Now, say a compiler sees the definition
foo x y = x `seq` y `seq` x
in one module, and then in a later one
expectToBeTotal = notReallyTry $ foo blam loop
? What happens if the compiler, while compiling foo, notices that x is going to be evaluated eventually anyway, and decides against forcing it before y?
What if foo was written as
foo (!x) (!y) = x
? Which order are the evaluations performed in? In a purely functional language, it doesn't matter; but all of a sudden with impure operations like notReallyTry popping up, it does.
Could you elaborate more about why this kind of breakage wouldn't happen if 'try' is used in an IO monad as intended?
Thanks. -- c/* __o/* <\ * (__ */\ < _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe