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!
The map() function takes two parameters namely a list and the function to be applied on each element in the list and returns a new list as the output. The map() function is available in Data. Map module in Haskell programming language.
There is no call stack in Haskell. Instead we find a pattern matching stack whose entries are essentially case expressions waiting for their scrutinee to be evaluated enough that they can match a constructor (WHNF).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With