以下Haskell代码没有终止,有人可以解释一下原因吗?感谢。
f = let x = 10 in let x = x * x in x
我认为翻译首先绑定x:10, 然后将x * x计算为100并绑定x:100, 环境变成x:100, 然后整个表达式评估为100
但是,此代码不会终止。
答案 0 :(得分:6)
在评估let foo = bar in baz
形式的let语句时,foo
在评估bar
时已绑定到bar
- 这是定义是递归的,如果有的话外部绑定具有相同的名称,它只是被忽略,因为它不再在范围内。
在评论中,您询问为什么不这样做,然后收到有关查找x
失败的错误。原因是x
的查找不会失败。 Haskell知道x
等于x * x
,这就是查找产生的内容。
因此,在评估x
时,会将其替换为其定义x * x
。要评估它,然后用其定义替换x
中的第一个,产生x * x * x
,然后x * x * x * x
等等,无限制地使用。
您可能想知道为什么允许值以这种方式递归,所以这里的示例实际上很有用,并且不会导致无限循环:let xs = 42 : xs in take 2 xs
生成结果[42, 42]
。此处xs
已扩展为42 : xs
,然后42 : 42 : xs
,然后停止,因为take 2
只需要前两个元素,因此它就会停止。
当然,当rhs是一个函数时,很明显,定义是递归的很有用:let fac = \n -> if n = 0 then 1 else n * fac (n-1)
- 在这里你显然希望fac
引用自身而不是之前的定义fac
。