尽管在GHCi下,list
会无限循环,但使用GHC编译的二进制文件能够检测到循环并报错。如果你进行编译和运行,即:
list = 1 : tail list
main = print list
如果出现以下错误信息,则表示程序已经终止:
Loop: <<loop>>
它对您的primes
示例执行相同的操作。
正如其他人所指出的,GHC无法检测所有可能的循环。如果可以,那么它将解决停机问题,这可能会使Haskell更受欢迎。
它返回错误(或“卡住”)而不是返回[1,1]
的原因是因为表达式:
list = 1 : tail list
Haskell语言中定义了底值语义,它赋予表达式一个值,这个值是“bottom”(或“error”或符号_|_
),就像head [1,2,3]
的值一样是1
。
(严格来说,list
的值是1 : _|_
,几乎等于底值。这是@Justin Li在评论中谈到的问题。我在下面尝试解释了为什么它有这个值。)
虽然您可能看不出一个返回底值的程序或表达式的用途,也看不出在基础上分配非底值语义的危害,但Haskell社区的大多数人(语言设计者、编译器开发者和经验丰富的用户)会不同意您的看法,因此不要期望与他们取得太多进展。
至于您提出的具体新语义,它们不清楚。为什么list
的值不等于[1]
?我认为当我输入“生成器”以获取元素n=1(从零开始索引,因此第二个元素)并评估tail list
时,结束于元素n-1=0的list
是[1]
,它的尾巴等于[]
,所以我应该得到以下结果,对吧?
list = 1 : tail list
= 1 : tail [1]
= 1 : []
= [1]
为什么值(几乎)是底部
根据标准 Haskell 的语义(但请参见末尾的注释),这就是为什么 list
的值(几乎)是底部的原因。
作为参考,tail
的定义实际上是:
tail l = case l of _:xs -> xs
[] -> error "ack, you dummy!"
让我们尝试使用Haskell语义“完全”评估list
:
-- evaluating `list` using definition of `list`
list = 1 : tail list
-- evaluating `tail list` using definition of `tail`
list = 1 : case list of _:xs -> xs
...
-- evaluating case construct requires matching `list` to
-- a pattern, this requires evaluation of `list` using its defn
list = 1 : case (1 : tail list) of _:xs -> xs
...
-- case pattern match succeeds
list = 1 : let xs = tail list in xs -- just to be clear
= 1 : tail list
-- awesome, now all we need to do is evaluate:
list = 1 : tail list
-- ummm, Houston, we have a problem
最后的无限循环是导致该表达式被称为“几乎底部”的原因。
注意:实际上有几种不同的Haskell语义,不同的计算Haskell表达式值的方法。黄金标准是@luqui答案中描述的指示性语义。我上面使用的语义,最多可以被视为Haskell报告中描述的一种“非正式语义”,但足以得到正确的答案。
[1,1]
是完全无意义的,因为例如[1,32132132]
同样有效。 - AJFlist = 1: tail list
,即list = 1:t,其中t = tail list
,那么t
是什么?它是t = tail list = tail (1: t) = t
。即使从方程推导中得出t = t
对于任何值的t
都是显然有效的,但这实际上并没有说明t
的任何特定值,因此没有理由给它任何特定的值。尝试打印list
可能会导致[1,***错误:检测到黑洞***
或[1,
并陷入无限循环。将列表关闭为[1]
意味着t = []
,这也是不合理的(因此,从方程推导的角度来看,这是错误的)。 - Will Nesslet (a,b,c,d) = (b,1,d,c)
必须选择a=b=1
,但有无限多种选择c,d
。由于我们无法一般地解决停机问题,唯一明智的选择是c=d=bottom
,其中bottom
是非终止/无限递归/无限循环。 - chi