
On Wed, 2009-03-25 at 07:39 -0400, Xiao-Yong Jin wrote:
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?
It would. But it would happen in IO, which is allowed to be non-deterministic. Pure Haskell is not allowed to be non-deterministic. jcc