[Haskell-cafe] Use unsafePerformIO to catch Exception?
wren ng thornton
wren at freegeek.org
Mon Mar 23 22:10:41 EDT 2009
Xiao-Yong Jin wrote:
> Hi,
>
> I just feel it is not comfortable to deal with exceptions
> only within IO monad, so I defined
>
>> tryArith :: a -> Either ArithException a
>> tryArith = unsafePerformIO . try . evaluate
>[...]
>
> However, I guess unsafePerformIO definitely has a reason for
> its name. As I read through the document in
> System.IO.Unsafe, I can't convince myself whether the use of
> 'tryArith' is indeed safe or unsafe.
>
> I know there have been a lot of discussion around
> unsafePerformIO, but I still can't figure it out by myself.
> Can someone share some thoughts on this particular use of
> unsafePerformIO? Is it safe or not? And why?
This use of unsafePerformIO is safe, because the original expression
you're given is pure[1]. The evaluate lifts the pure value into IO in
order to give evaluation-ordering guarantees, though otherwise has no
effects. The unsafePerformIO voids those effects, since it makes the
value pure again and thus it does not need to grab the RealWorld baton.
Note that the correctness argument assumes the value is indeed pure.
Some idiot could have passed in (unsafePerformIO launchTheMissiles),
which is not safe and the impurity will taint anything that uses it
(tryArith, (+1), whatever). But it's the unsafePerformIO in this
expression which is bad, not the one in tryArith.
tryArith is basically the same as a function I have in my personal
utility code:
http://community.haskell.org/~wren/wren-extras/Control/Exception/Extras.hs
The safely function is somewhat different in that it's a combinator for
making *functions* safe, rather than making *expressions* safe as
tryArith does. This is necessary because exceptional control flow (by
definition) does not honor the boundaries of expressions, but rather
attaches semantics to the evaluation of functions. Thus safely is more
safe because it ensures you can't force the exception prematurely via
sharing:
> let x = 5`div`0 in
> ... seq x ... tryArith x -- too late to catch it! oops.
Whereas with safely we'd have:
> let f y = safely (div y) in
> let x = 5 `f` 0 in
> ... seq x ... x -- doesn't matter where f or x are used.
[1] Ha! If it were _pure_ then it wouldn't be throwing exceptions, now
would it :)
--
Live well,
~wren
More information about the Haskell-Cafe
mailing list