[Haskell-cafe] Justification for Ord inheriting from Eq?

Jacques Carette carette at mcmaster.ca
Fri Apr 7 09:43:52 EDT 2006



Robert Dockins wrote:
>> The behaviour of NaN actually makes perfect sense when you realise that
>> it is Not a Number.  Things that are not numbers are incomparable with
>> things that are.
>>
>> Yes, NaN can be of type Float.  But it's not a Float.
>
> If you take that tack, then you have to concede that the type system 
> isn't doing what it should (keeping me from having something 
> not-a-float where I expect a float).  Any way you slice it, its an 
> unfortunate situation.
>
> I'd personally rather that any operation generating NaN raises an 
> exception, a la divide by 0 at Int.  I think (although I'm not sure) 
> that the floating point infinities play nice wrt equality and 
> ordering, so getting rid of NaN would restore at least _some_ 
> semblance of proper algebraic behavior to the floating point 
> representations.  (And the FFI already has CFloat/CDouble, so you 
> should use those when you really need to actually do something with 
> NaN generated by external code, and CFloat/CDobule should not be 
> members of Eq and Ord).
>
> Or at the very least, attempting to compare NaN using (==) or (<) and 
> friends should raise an exception, rather than just returning broken 
> results.
>
> Rob Dockins

The IEEE 754 standard explicitly specifies that complete implementations 
can have either or both 'signalling' NaNs and 'quiet' NaNs.  It appears 
that current Haskell implementations have chosen to go with quiet NaNs, 
which is very surprising indeed, as that does go "against" the type 
system.  Signalling NaNs are more consistent with the rest of Haskell's 
semantics.

However, it is also important to note that IEEE 754 also mandates 'trap 
handlers' for signalling NaNs, so that implementors may choose (even at 
run-time, on a per-instance basis) what to do with any given occurence 
of NaN.  In particular, it is possible to resume the computation with a 
_value_ being substituted in for that NaN.  These 'trap handlers' are 
also in there for division-by-zero, so that one may _choose_ to return 
either infinity or raise an actual exception.

If one reads the standard (IEEE 754) carefully enough, it is possible to 
'pick' an implementation of it which actually fits in with Haskell 
fairly well.  Yes, the standard is explicitly written to have *choices* 
in it for implementors.  The current implementation is generally 
standard-compliant, but does not seem to 'pick' a path of 
least-resistance wrt the rest of Haskell.

Jacques


More information about the Haskell-Cafe mailing list