[Haskell-cafe] Use unsafePerformIO to catch Exception?

Jonathan Cast jonathanccast at fastmail.fm
Wed Mar 25 02:49:32 EDT 2009

On Tue, 2009-03-24 at 23:13 -0700, Donn Cave wrote:
> Quoth Duncan Coutts <duncan.coutts at worc.ox.ac.uk>:
> > 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.


    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.


More information about the Haskell-Cafe mailing list