如果我在GHCI上输入[1/0..1/0],我将获得Infinite Infinity.为什么?

k4v*_*vin 19 haskell infinity

我无法理解Haskell中范围的以下行为.枚举1到1给我一个只包含1的列表,2到2给我一个列表,其中只包含2,如下所示.

Prelude> [1..1]
[1]
Prelude> [2..2]
[2]
Run Code Online (Sandbox Code Playgroud)

但是将无穷大枚举为无穷大给了我一个长度无限且所有元素都是无穷大的列表,如下所示.

Prelude> [1/0..1/0]
[Infinity,Infinity,Infinity,Infinity,Infinity,Infinity,Interrupted.
Run Code Online (Sandbox Code Playgroud)

我知道无限是一个不被视为数字的概念,但是这种行为的合理性是什么呢?

Tik*_*vis 31

Haskell Double(使用时的默认值/)遵循IEEE 754标准的浮点数,它定义了Infinity行为的方式.这就是为什么1/0Infinity.

通过这个标准(并且,公平地,通过逻辑)Infinity + 1 == Infinity,以及每次只添加的Enum实例.Double1

这是另一个迹象,表明该Enum实例Double并非完全格式良好,并且不符合我们通常对Enum实例的期望.因此,根据经验,您应该避免使用..浮点数:即使了解它的工作原理,也会让其他人阅读您的代码时感到困惑.作为混淆行为的另一个例子,请考虑:

Prelude> [0.1..1]
[0.1,1.1]
Run Code Online (Sandbox Code Playgroud)

如果你想进入很多关于更多的细节Enum实例Double,您可以通过这个阅读相当漫长的Haskell咖啡厅线程.


dfe*_*uer 13

路易斯·沃瑟曼和吉洪Jelvis均表示,基本的问题是,NumEnum为实例FloatDouble怪异的,真是不应该存在的.事实上,这个Enum类本身很奇怪,因为它试图同时服务于几个不同的目的,没有一个很好 - 它可能最好被认为是历史事故和方便,而不是类型类应该是什么样子的好例子.在很大程度上,NumIntegral班级也是如此.使用这些类中的任何一个时,必须密切关注您正在操作的特定类型.

enumFromTo浮点方法是基于以下功能:

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

所以2 <= 1+1/2错误的,但由于浮点的怪异,infinity <= infinity + 1/2真的.

正如Tikhon Jelvis所指出的,通常最好不要使用Enum浮点数的任何方法,包括数值范围.