Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If I enter [1/0..1/0] on GHCI I am getting Infinite Infinity. Why?

I can't understand the following behavior of ranges in Haskell. Enumerating 1 to 1 gives me a list contain only 1, and 2 to 2 gives me a list contain only 2 as given below.

Prelude> [1..1]
[1]
Prelude> [2..2]
[2]

But enumerating infinity to infinity gives me a list which is infinite in length and all the elements are infinity, as shown below.

Prelude> [1/0..1/0]
[Infinity,Infinity,Infinity,Infinity,Infinity,Infinity,Interrupted.

I am aware that Infinity is a concept not to be treated as a number, but what justifies that behavior ?

like image 225
Kavin Eswaramoorthy Avatar asked Feb 06 '15 18:02

Kavin Eswaramoorthy


3 Answers

Haskell's Double (the default you get when using /) follows the IEEE 754 standard for floating point numbers, which defines how Infinity behaves. This is why 1/0 is Infinity.

By this standard (and, to be fair, by logic), Infinity + 1 == Infinity, and the Enum instance for Double just adds 1 each time.

This is another sign that the Enum instance for Double is not entirely well-formed and does not conform to the expectations we usually have for Enum instances. So, as a rule of thumb, you should probably avoid using .. for floating point numbers: even if you understand how it works, it will be confusing for others reading your code. As another example of confusing behavior, consider:

Prelude> [0.1..1]
[0.1,1.1]

If you want to get into a lot more details about the Enum instance for Double, you can read through this pretty lengthy Haskell-cafe thread.

like image 113
Tikhon Jelvis Avatar answered Oct 15 '22 06:10

Tikhon Jelvis


As Luis Wasserman and Tikhon Jelvis have indicated, the basic problem is that the Num and Enum instances for Float and Double are weird, and really should not exist at all. In fact, the Enum class itself is pretty weird, as it attempts to serve several different purposes at once, none of them well—it is probably best considered a historical accident and a convenience rather than a good example of what a typeclass should look like. The same is true, to a significant extent, of the Num and Integral classes. When using any of these classes, you must pay close attention to the specific types you are operating on.

The enumFromTo methods for floating point are based on the following function:

numericEnumFromTo :: (Ord a, Fractional a) => a -> a -> [a]
numericEnumFromTo n m = takeWhile (<= m + 1/2) (numericEnumFrom n)

So 2 <= 1+1/2 is false, but because of the weirdness of floating point, infinity <= infinity + 1/2 is true.

As Tikhon Jelvis indicates, it's generally best not to use any Enum methods, including numeric ranges, with floating point.

like image 33
dfeuer Avatar answered Oct 15 '22 04:10

dfeuer


I believe the implementation of [a..b] continues incrementing a by one until it is greater than b. This is never going to happen with infinity, so it goes forever.

I believe your code will probably default to Double the way you've written it, which has well-defined semantics for infinity. IIRC, Haskell follows http://en.wikipedia.org/wiki/IEEE_floating_point.

like image 41
Louis Wasserman Avatar answered Oct 15 '22 05:10

Louis Wasserman