I\'ve just started learning Haskell and found a strange thing.
Let we have a list:
ghci> [0,2..5]
[0,2,4]
It has 3 elements. Whe
It's due to the implementation of Enum
for Float
and Double
:
> [0,2..5] :: [Float]
[0.0,2.0,4.0,6.0]
It's not map
doing it, but Float
. Specifically, if you call enumFromThenTo 0 2 5 :: [Float]
, you'll get the same list. You'll see the same results for Double
.
This is hinted at in the haskell report, but the behavior is definitely non-obvious. Essentially, it comes down to the implementation of numericEnumFromThenTo
(we're getting into some Haskell internals here), which is used by the Enum Float
instance:
numericEnumFromThenTo n n' m = takeWhile p (numericEnumFromThen n n')
where
p | n' >= n = (<= m + (n' - n) / 2)
| otherwise = (>= m + (n' - n) / 2)
numericEnumFromThen n m = iterate (+ (m - n)) n
So you have numericEnumFromThen 0.0 2.0
generating the list [0.0,2.0,4.0,6.0,8.0,...]
, then you do takeWhile p
on that, which in this case is equivalent to the function \x -> x <= 5.0 + (2.0 - 0.0) / 2
, or more simply \x -> x <= 6.0
, which is why 6.0
is included in the output list of [0.0,2.0..5.0]
.
I can't explain why it's implemented this way, that's pretty baffling to me too, but hopefully I've answered the how for its implementation.