Haskell 中列表生成的奇怪结果

Strange result of List generation in Haskell

Ranges in Haskell (GHCi) 可以很清楚为什么 [2, 2..20] 生成无限列表。

下一个值是相同的,这就是这段代码产生无限列表的原因。

而且看起来它并不关心限制,因为 [2, 2..2] 也会生成无限列表。

问题:

为什么下面的代码 [2, 2..(-20)] 生成空列表?

简而言之:这是预期的行为。

[x, y..z] 表达式是 enumFromThenTo x y zenumFromThenTo :: a -> a -> a -> [a] 的语法糖。

对于 Integers 它的实现方式如下:

instance  Enum Integer  where
    # ...
    enumFromThenTo x y lim = enumDeltaToInteger x (y-x) lim

所以它会调用 enumDeltaToInteger 2 0 (-20)enumDeltaToInteger is implemented with [src]:

enumDeltaToInteger :: Integer -> Integer -> Integer -> [Integer]
enumDeltaToInteger x delta lim
  | <b>delta >= 0 = up_list x delta lim</b>
  | otherwise  = dn_list x delta lim

所以它被认为是一个up_list,并且up_list会增加直到它达到大于lim的值:

up_list :: Integer -> Integer -> Integer -> [Integer]
up_list x0 delta lim = go (x0 :: Integer)
                    where
                        go x | <b>x > lim   = []</b>
                             | otherwise = x : go (x+delta)

Haskell'10 report on the Enum class中是这样描述的:

The sequence enumFromThenTo e1 e2 e3 is the list [e1,e1 + i,e1 + 2i,…e3], where the increment, i, is e2 − e1. If the increment is positive or zero, the list terminates when the next element would be greater than e3; the list is empty if e1 > e3. If the increment is negative, the list terminates when the next element would be less than e3; the list is empty if e1 < e3.

所以文档说如果"step"是零个或多个,并且e1 > e3,那么结果是空列表。

不过确实是"tricky"的情况。我个人同意使用 0 作为 "step" 的特例是有意义的(尽管我本身并不是说这比使用 up_list 实现更有利)。然而,事情就是这样定义的。