
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. jcc