Opened 13 years ago

Last modified 4 years ago

#123 new modification

Fix Ord so Ord Double and Ord Float make sense

Reported by: Ian Lynagh Owned by: none
Priority: normal Milestone:
Version: Keywords:
Cc: Meta Owner:
State: discussion Section: N/A or multiple
Related Tickets:

Description

Consider:

let n = 0/0 :: Double in (n `compare` n, n < n, n == n, n > n)

In GHC and YHC this gives

(GT,False,False,False)

while in hugs it gives

(EQ,False,False,False)

Neither of these is very satisfactory, as I would expect

x `compare` y === EQ   =>   (x == y) === True
x `compare` y === GT   =>   (x > y) === True

and it's even less pleasant that the implementations differ for no good reason.

The Haskell report isn't currently very helpful on how comparing exceptional Doubles should behave, as it doesn't even say you need to have NaN etc:

http://haskell.org/onlinereport/basic.html#sect6.4
The results of exceptional conditions (such as overflow or 
underflow) on the fixed-precision numeric types are undefined; an
implementation may choose error (_|_, semantically), a truncated
value, or a special value such as infinity, indefinite, etc.

Four possible solutions to the problem have been proposed. While Haskell' would presumably continue not to legislate what implementations should do in this case, some of the solutions require changes to the report, so we do need to discuss it in the context of Haskell'.

The possible solutions are:

  • compare should raise an exception (Haskell' doesn't need to be changed)
  • compare, (<), (>), etc should raise an exception (Haskell' doesn't need to be changed)
  • There should be no Ord instance for Float and Double (changes needed for Haskell')
  • Add an Incomparable constructor to Ordering (changes needed for Haskell')

Change History (4)

comment:1 Changed 13 years ago by Ian Lynagh

Extract of http://www.haskell.org/pipermail/libraries/2007-March/007224.html :

Another potentially attractive option is to recast Eq as being only a  
PER (remove the reflexivity assumption) and allow Ord to be a partial  
order.   Or maybe:

class PEq a where { (==) (/=) :: a -> a -> Bool }
class PEq a => Eq a

class POrd a where { compare :: ....; (<=) :: ...; etc }
class POrd a => Ord a


so we introduce new classes with the relaxed semantics and make Ord/ 
Eq subclasses with no new operations.

(still need to decide what compare should do in the POrd of Double)

comment:2 Changed 13 years ago by Ian Lynagh

http://www.haskell.org/pipermail/libraries/2007-March/007226.html :

I have another proposal: make different types.

People who want integers have the choice of Int (or Int64, etc) for performance
or Integer for stronger algebraic guarantees.

I suggest Double be split into types with different guarantees:
  One that avoids "error" (and has weird NaN / Inf behavior)
  Another that avoids having or propagating NaN/Inf by always throwing an error.
  And perhaps an IEEE type with specific Nan/Inf behavior ?

So (0.0/0.0 :: Double) is NaN and (0.0/0.0 :: FiniteDouble) is an error.

The same applies to Float/FiniteFloat:

newtype FiniteDouble = FiniteDouble Double
newtype FiniteFloat = FiniteDouble Float

comment:3 Changed 4 years ago by Herbert Valerio Riedel

Milestone:

moving non-milestoned many year old legacy tickets out of the way

comment:4 Changed 4 years ago by Herbert Valerio Riedel

Priority: majornormal

Set default priority (as this confuses Trac otherwise)

Note: See TracTickets for help on using tickets.