0

With Ghc/Ghci, version 8.8.4, I get this:

[0,2..3] evaluates to [0,2], while [0.0,2..3] evaluates to [0.0,2.0,4.0]

What is going on?

1 Answers1

1

[a, b..c] is syntactic sugar for enumFromThenTo a b c, so we should look at its definition for Double:

instance  Enum Double  where
    succ x         = x + 1
    pred x         = x - 1
    toEnum         =  int2Double
    fromEnum       =  fromInteger . truncate   -- may overflow
    enumFrom       =  numericEnumFrom
    enumFromTo     =  numericEnumFromTo
    enumFromThen   =  numericEnumFromThen
    enumFromThenTo =  numericEnumFromThenTo

It just uses numericEnumFromThenTo, which is defined as:

numericEnumFromThen     :: (Fractional a) => a -> a -> [a]
numericEnumFromThen n m = go 0
  where
    step = m - n
    -- See Note [Numeric Stability of Enumerating Floating Numbers]
    go !k = let !n' = n + k * step
             in n' : go (k + 1)

numericEnumFromThenTo   :: (Ord a, Fractional a) => a -> a -> a -> [a]
numericEnumFromThenTo e1 e2 e3
    = takeWhile predicate (numericEnumFromThen e1 e2)
                                where
                                 mid = (e2 - e1) / 2
                                 predicate | e2 >= e1  = (<= e3 + mid)
                                           | otherwise = (>= e3 + mid)

So, numericEnumFromThen ([a, b..]) simply repeatedly adds a step to a starting point, which is pretty intuitive. However, numericEnumFromThenTo is a bit special: it actually stops after you pass the end value by more than half the step. It does not stop immediately after reaching the end value. This was probably made to deal with floating point imprecision, but it does lead to some weird behavior like you see here.

Aplet123
  • 33,825
  • 1
  • 29
  • 55