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. When I use map
with this list I get 3 element as output, for example:
ghci> map (+ 1) [0,2..5]
[1,3,5]
ghci> map (* 2) [0,2..5]
[0,4,8]
ghci> map (`div` 2) [0,2..5]
[0,1,2]
But when I use fractional division I get 4 elements in output list:
ghci> map (/ 2) [0,2..5]
[0.0,1.0,2.0,3.0]
ghci> length (map (/ 2) [0,2..5])
4
Could you please explain why map
may return more elements then it was?
Thank you!
It's due to the implementation of
Enum
forFloat
andDouble
:It's not
map
doing it, butFloat
. Specifically, if you callenumFromThenTo 0 2 5 :: [Float]
, you'll get the same list. You'll see the same results forDouble
.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 theEnum Float
instance:So you have
numericEnumFromThen 0.0 2.0
generating the list[0.0,2.0,4.0,6.0,8.0,...]
, then you dotakeWhile 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 why6.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.