I know that floats can lead to odd behavior in ranges due to their imprecise nature.
I would expect the possibility of imprecise values. For instance:
[0.1,0.3..1]
might give [0.1,0.3,0.5,0.7,0.8999999999999999]
instead of [0.1,0.3,0.5,0.7,0.9]
In addition to the precision loss, however, I get an extra element:
ghci> [0.1,0.3..1]
[0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999]
This is weird, but explained here. I could work around it like this, I suppose:
ghci> [0.1,0.3..0.99]
[0.1,0.3,0.5,0.7,0.8999999999999999]
But that's kind of gross. Maybe there's a cleaner way. For this simple example, of course, I could just use the range [0.1,0.3..0.9]
and everything is fine.
But in a more complex example, I may not quickly know (or care to figure out, if I'm lazy) the exact upper bound I should use. So, I'll just make a range of integers and then divide by 10, right? Nope:
ghci> map (/10) [1,3..10]
[0.1,0.3,0.5,0.7,0.9,1.1]
Any floating point function seems to cause this behavior:
ghci> map (*1.0) [1,3..10]
[1.0,3.0,5.0,7.0,9.0,11.0]
Whereas a non-floating function doesn't:
ghci> map (*1) [1,3..10]
[1,3,5,7,9]
While it seems unlikely, I thought that maybe some lazy evaluation was at play, and tried to force evaluation of the range first:
ghci> let list = [1,3..10] in seq list (map (*1.0) list)
[1.0,3.0,5.0,7.0,9.0,11.0]
Obviously, using the literal list instead of the range works fine:
ghci> map (*1.0) [1,3,5,7,9]
[1.0,3.0,5.0,7.0,9.0]
ghci> let list = [1,3,5,7,9] in seq list (map (*1.0) list)
[1.0,3.0,5.0,7.0,9.0]
It isn't just mapping either:
ghci> last [1,3..10]
9
ghci> 1.0 * (last [1,3..10])
11.0
How does applying a function to the result of a range can impact the actual evaluated result of that range?