Repair to floating point enumerations?

Malcolm Wallace Malcolm.Wallace at cs.york.ac.uk
Wed Oct 15 05:41:25 EDT 2008


Dear Haskell-Primers (and libraries).

Recently, Phil Wadler has pointed out a weird anomaly in the Haskell'98
Prelude, regarding numeric enumerations for Floats/Doubles:

    Prelude> [0, 0.3 .. 1.1]
    [0.0,0.3,0.6,0.899999,1.2]

What is odd is that the last value of the list is much larger than the
specified termination value.  But this is exactly as specified by the
Haskell'98 Report.

    http://haskell.org/onlinereport/basic.html#sect6.3.4

    "For Float and Double, the semantics of the enumFrom family is given
    by the rules for Int above, except that the list terminates when the
    elements become greater than e3+i/2 for positive increment i, or
    when they become less than e3+i/2 for negative i.

We have discussed this question (and related ones, such as whether Float
and Double belong in the Enum class at all) several times before, and I
do not wish to rehash all of those points again e.g.:

    http://www.cse.unsw.edu.au/~dons/haskell-1990-2000/msg07289.html
    http://www.haskell.org/pipermail/haskell/2001-October/008218.html
    http://www.haskell.org/pipermail/haskell/2002-October/010607.html

Phil proposes that, although retaining the instances of Enum for Float
and Double, we simplify the definitions of the numericEnumFrom family:

  numericEnumFromThenTo   :: (Fractional a, Ord a) => a -> a -> a -> [a]
  numericEnumFrom         =  iterate (+1)
  numericEnumFromThen n m =  iterate (+(m-n)) n
  numericEnumFromTo n m   =  takeWhile (<= m) (numericEnumFrom n)
  numericEnumFromThenTo n m p = takeWhile (<= p) (numericEnumFromThen n m)

The particular feature of note is that the odd fudge factor of (1/2 *
the increment) is removed.  The inexact nature of floating point numbers
would therefore cause a specification like

    [ 0.0, 0.1 .. 0.3 ]

to yield the sequence

    [ 0.0, 0.1, 0.2 ]

that is, to omit the upper bound, because (3 * 0.1) is actually
represented as 0.30000000000004, strictly greater than 0.3.

Phil argues that this behaviour is more desirable: "the simple fix is
that the user must add a suitable epsilon to the upper bound.  The key
word here is *suitable*.  The old definitions included completely
bizarre and often highly unsuitable choices of epsilon."

This proposal seems to me to improve the consistency of the enumeration
syntax across both the integral and floating types.  Some users may
still be surprised, but the surprise will be easier to explain.

I am bringing this question to the attention of all who are interested
in Haskell Prime, because it seems like a sensible and well-reasoned
change.  Discussion on whether to adopt this proposal for H' is welcome.

But as maintainer and bug-fixer of the Haskell'98 Report, I have also
been asked whether we should make this change retrospectively to the
Haskell'98 language (as a "typo").  Since it involves not merely an
ordinary library function, but a Prelude function, and moreover a
function that is used in the desugaring of syntax, it is less clear to
me whether to alter Haskell'98.

Thoughts?

Regards,
    Malcolm


More information about the Libraries mailing list