[Haskell-cafe] Use unsafePerformIO to catch Exception?

Benja Fallenstein benja.fallenstein at gmail.com
Wed Mar 25 13:14:04 EDT 2009


Hi Duncan and all,

On Wed, Mar 25, 2009 at 3:52 AM, Duncan Coutts
<duncan.coutts at worc.ox.ac.uk> wrote:
> On Mon, 2009-03-23 at 08:11 -0400, Xiao-Yong Jin wrote:
>> > tryArith :: a -> Either ArithException a
>> > tryArith = unsafePerformIO . try . evaluate
>
> 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.
...
> Of course your tryArith only tests for certain kinds of _|_ value, but
> in principle the problem is the same.

That's not *quite* how the semantics of Haskell exceptions are
defined, actually, unless I'm misunderstanding something or the
thinking about it has changed since the original paper on the topic:

Simon Peyton Jones, Alastair Reid, Tony Hoare, Simon Marlow, Fergus
Henderson: "A semantics for imprecise exceptions." SIGPLAN Conference
on Programming Language Design and Implementation, 1999.

http://www.haskell.org/~simonmar/papers/except.ps.gz

In the semantics given by that paper, the value of an expression of type Int is

(a) an actual number, or
(b) a set of exceptions that the expression might raise when evaluated, or
(c) bottom, which means: when evaluated, the expression may not
terminate, or may terminate and raise some arbitrary exception.

(The semantic ordering is: everything is larger than bottom; a set of
expressions A is larger than a set of expressions B iff A is a proper
subset of B; numbers are not comparable to sets.)

tryArith is still noncontinuous, though, and nondeterministic, too. Consider:

divzero = 1/0
overflow = 2**10000000
loop = loop - 1

* What is (tryArith (divzero + overflow))? The denotational value of
(divzero + overflow) is the set {DivideByZero, Overflow}, so tryArith
can return either (Left DivideByZero) or (Left Overflow) --
nondeterminism.

* What is (tryArith (overflow + loop))? The denotational value of
(overflow + loop) is bottom, so tryArith can theoretically return any
arithmetic exception, or propagate any non-arithmetic exception, or
loop forever. In practice, of course, it will either return (Left
Overflow), or loop forever, or error out if the compiler notices the
loop. However, this still means that it *may* return (Left Overflow)
even though the semantical value of (overflow + loop) is bottom, which
means that the function is not monotone and thus not continuous.

All the best,
- Benja


More information about the Haskell-Cafe mailing list