Why does map return an additional element when using ranges in Haskell?

别等时光非礼了梦想. 提交于 2019-12-01 17:09:54

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!