Using Haskell ranges: why does displaying a floating point function within a range make it return an additional element?

I know that floats can lead to odd behavior in ranges due to their inaccurate nature. I would expect the possibility of inaccurate values. For example: [0.1,0.3..1] can 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 loss accuracy, however, I get an additional element:

 ghci> [0.1,0.3..1] [0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999] 

This is strange but explained here . I could get around this, I suppose:

 ghci> [0.1,0.3..0.99] [0.1,0.3,0.5,0.7,0.8999999999999999] 

But so rude. Perhaps there is a cleaner way. For this simple example, of course, I could just use the range [0.1,0.3..0.9] , and that's all right.

But in a more complex example, I cannot quickly find out (or am not trying to figure out if I am lazy), the exact upper bound I should use. So, I just make a whole series 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] 

While the non-floating function does not perform:

 ghci> map (*1) [1,3..10] [1,3,5,7,9] 

Although this seems unlikely, I thought that maybe some lazy rating was in the game, and first tried to evaluate the range rating:

 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 a literal list instead of a 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] 

This is not just a mapping:

 ghci> last [1,3..10] 9 ghci> 1.0 * (last [1,3..10]) 11.0 

How can applying a function to the result of a range affect the actual estimated result of that range?

+7
floating-point haskell range
source share
1 answer

I answered this myself when I wrote.

Haskell uses type inference, so when it sees that a floating-point function is displayed above the list (or used in an element of this list, as in my example, using the latter), it will output the type of this list to be a floating point and therefore evaluate range as if it were [1,3..10] :: [Float] instead of what I intended, that is [1,3..10] :: [Int]

At this point, he uses the Float rules to enumerate, as described in the post I linked to in the question .

The expected behavior can be enforced as follows:

 ghci> map (\x -> (fromIntegral x) / 10) ([1,3..10]::[Int]) [0.1,0.3,0.5,0.7,0.9] 

Based on the output of the Haskell type, we can refuse from ::[Int] , since fromIntegral forces our lambda expression to have the correct type:

 ghci> :t (\x -> (fromIntegral x) / 10) (\x -> (fromIntegral x) / 10) :: (Fractional a, Integral a1) => a1 -> a 
+11
source share

All Articles