Ok, @Henning Makholm already said this in his comment, but he didn't explain why this actually is a better solution.
First thing to say: when dealing with floating-point, we must always be aware of the possible rounding errors. When we write [0.0, 0.1 .. 1.0]
we must be aware that all these numbers, except for the first one, will not be at the exact places of tenths. Where we need this kind of certainty, we must not use floats at all.
But of course there are many applications where we're content with reasonable certainy, but need high-speed. That's where floats are great. One possible application of such a list would be a simple trapezoid numerical integration:
trIntegrate f l r s = sum [ f x | x<-[l,(l+s)..r] ] * s - (f(l)+f(r))*s/2
let's test this: trIntegrate ( \x -> exp(x + cos(sqrt(x) - x*x)) ) 1.0 3.0 0.1
=> 25.797334337026466
compared to 25.9144 an error of less than one percent. Not exact of course, but that's inherent to the integration method.
Suppose now that float ranges were defined to always terminate when crossing the right border. Then, it would be possible (but we can't be certain about it!) that only 20 values rather than 21 are calculated in the sum, because the last value of x
happens to be 3.000000something. We can simulate this
bad_trIntegrate f l r s = sum [ f x | x<-[l,(l+s)..(r-s)] ] * s - (f(l)+f(r))*s/2
then we get
bad_trIntegrate ( \x -> exp(x + cos(sqrt(x) - x*x)) ) 1.0 3.0 0.1
=> 21.27550564546988
urgh!
This has nothing to do with hiding the problems with floating point. It's just a method to help the programmer getting around these problems easier. In fact, the counterintuitive result of [1, 3 .. 10] :: Float
helps to remember these problems!