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

时间:2015-02-06 18:30:51

标签: haskell infinity

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

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

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

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

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

3 个答案:

答案 0 :(得分:31)

Haskell的Double(使用/时获得的默认值)遵循IEEE 754 standard的浮点数,它定义了Infinity的行为方式。这就是1/0Infinity的原因。

通过此标准(并且,为了公平,通过逻辑),Infinity + 1 == InfinityEnum的{​​{1}}实例每次只添加Double

这是另一个迹象,表明1 Enum实例的格式不完整,并且不符合我们通常对Double个实例的期望。因此,根据经验,您应该避免使用Enum来表示浮点数:即使了解它是如何工作的,对于其他读取代码的人也会感到困惑。作为混淆行为的另一个例子,请考虑:

..

如果您想进入很多有关Prelude> [0.1..1] [0.1,1.1] Enum个实例的详细信息,可以通读pretty lengthy Haskell-cafe thread

答案 1 :(得分:13)

正如Luis Wasserman和Tikhon Jelvis所指出的,基本问题是NumEnum的{​​{1}}和Float个实例很奇怪,真的不应该存在。事实上,Double类本身很奇怪,因为它试图同时服务于几个不同的目的,没有一个很好 - 它可能最好被认为是历史事故和方便而不是一个很好的例子类型类似乎应该是这样的。 EnumNum类在很大程度上也是如此。使用这些类中的任何一个时,必须密切关注您正在操作的特定类型。

浮点的Integral方法基于以下函数:

enumFromTo

所以numericEnumFromTo :: (Ord a, Fractional a) => a -> a -> [a] numericEnumFromTo n m = takeWhile (<= m + 1/2) (numericEnumFrom n) false ,但由于浮点的怪异,2 <= 1+1/2 true

正如Tikhon Jelvis所指出的,通常最好不要使用浮点数的任何infinity <= infinity + 1/2方法,包括数值范围。

答案 2 :(得分:3)

我相信[a..b]的实施会继续将a递增1,直到它大于b。这种情况永远不会发生在无穷大,所以它永远存在。

我相信你的代码可能会以你编写它的方式默认为Double,它具有明确定义的无穷大语义。 IIRC,Haskell跟随http://en.wikipedia.org/wiki/IEEE_floating_point