
Hi Duncan and all,
On Wed, Mar 25, 2009 at 3:52 AM, Duncan Coutts
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