Haskell范围表示法生成列表。输出结果出乎意料。

23

我在我的课程中遇到了一个练习题,导致我对 [2, 2 .. 2] 的输出产生困惑。为什么输入 [2, 2 .. 2] 会生成一个由 2 组成的“无限”列表?

我的理解是,这个符号表示的意思是第一个元素是起始边界,第二个元素是数字之间的“间隔”,最后一个元素是列表的结束,也就是当达到这个数字时停止。

如果我的推理是正确的,那么为什么表达式 [2, 2 .. 2] 不输出 [2] 呢?


我认为 Haskell 可能会这样计算:

  1. 当打印列表的第一个元素时,它等于最后一个元素,因此停止。
  2. 或者,如果第一个元素没有与“外部”边界进行比较,那么输出将为 [2, 2],因为当将前一个数字(在我们的例子中是起始边界 2)加零时,我们已经到达了结束点,因此停止。

显然我错误地理解了符号的工作原理,那么 Haskell 是如何计算这个表达式的呢?


@Robert Harvey,我很好奇你为什么要撤销这些标签。那个符号更为人所知的是范围符号,而“点-点-符号”是一个新标签。我可以理解重新添加“点-点-符号”标签的可能原因,但我无法理解为什么你要删除“范围”标签。 - luqui
@luqui: range 可以意味着任何东西。我将标签更改为 range-notation 并添加了一个标签维基。 - Robert Harvey
2个回答

39

这种记法旨在模仿数学中写简单序列的方式。第二个元素不是步长,而实际上是列表的第二个元素。其余部分则从那里进行线性外推。示例:

[1,2..10] = [1,2,3,4,5,6,7,8,9,10]
[1,3..10] = [1,3,5,7,9]
[4,3..0]  = [4,3,2,1,0]
[0,5..]   = [0,5,10,15,20,25,30,35...  -- infinite
[1,1..]   = [1,1,1,1,1,1,1,1,1,1,1...  -- infinite
< p > [2,2..2]无限的原因是列表中没有任何一个值大于右端点(终止条件)。如果你想要步长为2,应该写成[2,4..2],这将得到预期的输出[2]。(所以我猜在所有情况下它都不是实际的第二个列表元素,但你可以看到这种逻辑)< /p >

1
太好了,伙计,解释得非常好,特别是“无限”,因为列表中没有任何一个值比右端点更大,这正是我最困惑的地方。祝一切顺利。 - Carlos
这是我理解它的关键:“如果你想要步长为2,你应该写成[2,4..2]”。从2开始,线性增加但在下一个元素大于2之前停止,这只需要1个元素。 - Nick Sweeting

27
基本上是因为标准规定了这样做。[e1,e2 .. e3]展开为enumFromThenTo e1 e2 e3
Haskell '98的第6.3.4节中报告如下:
枚举序列enumFromThenTo e1 e2 e3是列表[ e1, e1+i, e1+2i, ... e3],其中增量i为e2-e1。如果增量为正数或零,则列表在下一个元素大于e3时终止;如果e1>e3,则列表为空。如果增量为负,则列表在下一个元素小于e3时终止;如果e1<e3,则列表为空。
下一个元素永远不会大于2。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接