
On Thu, 2009-03-26 at 14:23 -0400, Xiao-Yong Jin wrote:
Henning Thielemann
writes: On Thu, 26 Mar 2009, Xiao-Yong Jin wrote:
So I have another question. Is the following function safe and legitimate?
safeDiv :: (Exception e, Integral a) => a -> a -> Either e a safeDiv x y = unsafePerformIO . try . evaluate $ div x y
I believe it should be okay to use this 'safeDiv'. What do
I think that question is wrong way around. The real question is, why do you want to solve your problem using unsafePerformIO?
I just want to know, from a theoretical point of view, whether this 'safeDiv' in above definition is the same as
safeDiv' :: (Exception e, Integral a) => a -> a -> Either e a safeDiv' _ 0 = Left e safeDiv' x y = Right $ div x y
You need some sort of type case here to make sure your first case matches only if e is the right type for divide-by-zero errors (too lazy to look it up atm). Alternatively, you could replace your type variable e with the actual exception type you want, here and in the unsafePerformIO version. Other than that, I think the imprecise exceptions paper guarantees that these two functions are equivalent (albeit unwisely: see below).
For the question why do I want to do that, I am not sure. I guess if the function which has an error call inside is provided by other library package, and I don't have a clear and easy way to tell whether the function will make the error call or not, it would be easy just to make a wrapper like that.
It might be easy, but if you didn't have a lot of insight into the function's behavior, then it would be difficult to tell whether it's really going to call error or whether it's going to go off into an infinite loop. (Consider the (slow) definition x ^ n | n == 0 = 1 | n < 0 = error "Negative exponents require ^^" | otherwise = x * x ^ (n - 1) Now consider what happens if the library function forgets the second case. Your wrapper isn't safe anymore!) I can see only two cases where a library function could call error sometimes, and you wouldn't have a good feel for when: a) The function is calling error on exceptions. You should bug the library author to put the function into an exception monad instead. Devil-may-care users can use either (error . show) id to turn exceptions into errors. b) The function has explicit pre-conditions, which you don't understand. You shouldn't pass arguments to a function that violate its pre-conditions (ever!); if you don't understand those preconditions well enough to test them in Haskell code, you might not understand them well enough to make sure your code is calling the function correctly. So you might want to study the preconditions a little more.
It's also a possible situation that I don't know how to test the input to a foreign function call.
FFI calls cannot throw Haskell exceptions. jcc