[Haskell-cafe] instance Enum Double considered not entirely great?

Daniel Fischer daniel.is.fischer at googlemail.com
Sun Sep 25 22:41:54 CEST 2011

On Sunday 25 September 2011, 19:20:52, Chris Smith wrote:
> Would it be an accurate summary of this thread that people are asking
> for (not including quibbles about naming and a few types):

Not quite, I'm afraid.

> class Ord a => Enum a where
>     succ :: a -> a
>     pred :: a -> a
>     fromEnum :: a -> Int(eger)
>     toEnum :: Int(eger) -> a
> -- No instance for Float/Double

I'm not in favour of introducing an Ord constraint here.

data WeekDay
    = Sunday

data Month
    = January

an Ord instance would be dubious, but Enum is plenty fine.

> class Ord a => Range a where
>     rangeFromTo :: a -> a -> [a] -- subsumes Ix.range / Enum.enumFromTo
>     rangeFromThenTo :: a -> a -> a -> [a]
>     inRange   :: (a, a) -> a -> Bool
> -- Does have instances for Float/Double.  List ranges desugar to this.
> -- Also has instances for tuples

Don't mix range and arithmetic sequences. I want arithmetic sequences for 
Double, Float and Rational, but not range.
(For Float and Double one could implement range [all values between the 
given bounds, in increasing order, would be the desired/expected semantics 
for that, I think?], but I'm rather sure that's not what one does normally 
want, and for Rational, you can't even implement it.)

Also, I doubt whether rangeFromThenTo is a useful addition to range, I 
don't see how it would be natural for tuples. (The Ix instance for tuples 
doesn't use the lexicographic ordering, but the box-partial order - 
presumably so would the Range instance, so the 'distance' between two 
tuples would depend on the given bounds. Using the box-partial order is 
fine for range, but seems weird for blahFromThenTo.)

> class Range a => InfiniteRange a where -- [1]
>     rangeFrom :: a -> [a]
>     rangeFromThen :: a -> a -> [a]
> -- Has instances for Float/Double
> -- No instances for tuples
> class Range a => Ix a where
>     index     :: (a, a) -> a -> Int
>     rangeSize :: (a, a) -> Int
> -- Again no instances for Float/Double.  Having an instance here implies
> -- that the rangeFrom* are "complete", containing all 'inRange' values

Ho Hum. So Range would continue the same ambiguity/confusion that started 
this thread, albeit in mitigated form.

Separating range from arithmetic (or 'fixed-step-size') sequences is 
cleaner (we'd lose default methods anyway, you need Enum or Num && Ord for 
them, but we now have numericEnumFrom* to make Enum instances for Num types 
easier, we could move the current default methods out of the class to have 
enumEnumFrom* so that writing instances for Enum types would be easier).

> class (RealFrac a, Floating a) => RealFloat a where
>     ... -- existing stuff
>     (.<.), (.<=.), (.>.), (.>=.), (.==.) :: a -> a -> Bool
>         -- these are IEEE semantics when applicable
> instance Ord Float where ... -- real Ord instance where NaN has a place

Yes. I have pondered leaving Eq and Ord for Double and Float as is and 
providing a newtype wrapper with container/sort-safe instances, but that'd 
be cumbersome, people wouldn't know they exist and (when) they have to use 
them, urk.
Also, although it's a change in behaviour, it doesn't badly break backwards 
compatibility., as far as I can see (I hope x /= x isn't heavily used as a 
NaN test).
So yes, definitely yes.

> There would be the obvious properties stated for types that are
> instances of both Enum and Range, but this allows for non-Enum types to
> still be Range instances.
> If there's general agreement on this, then we at least have a proposal,
> and one that doesn't massively complicate the existing system.  The next
> step, I suppose would be to implement it in an AltPrelude module and
> (sadly, since Enum is changing meaning) a trivial GHC language
> extension.  Then the real hard work of convincing more people to use it
> would start.  If that succeeds, the next hard work would be finding a
> compatible way to make the transition...
> I'm not happy with InfiniteRange, but I imagine the alternative (runtime
> errors) won't be popular in the present crowd.

More information about the Haskell-Cafe mailing list