[Haskell-cafe] Re: Exception handling in numeric computations

Jonathan Cast jonathanccast at fastmail.fm
Thu Mar 26 14:28:13 EDT 2009


On Thu, 2009-03-26 at 14:23 -0400, Xiao-Yong Jin wrote:
> Henning Thielemann <lemming at henning-thielemann.de> 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




More information about the Haskell-Cafe mailing list