Haskell:为什么将变量的尾部重新分配给它自己的变量会出现问题?
假设您有一个包含以下列表的变量:
Prelude> arr = [1,2,3,4,5]
你也是,
Prelude> arr
[1,2,3,4,5]
Prelude> arr = tail arr
Prelude> arr
为什么编译器现在冻结了?我试图在递归中实现这个代码语句,但这种现象阻止了我的递归正常工作——它不断返回一个空列表错误。
回答
在 Haskell 中,变量总是在它自己定义的范围内。你可能想要的是这个
Prelude> arr1 = [1,2,3,4,5]
Prelude> arr1
[1,2,3,4,5]
Prelude> arr2 = tail arr1
Prelude> arr2
[2, 3, 4, 5]
但是当你写的时候arr = tail arr,REPL 忘记了之前的定义,arr并定义了一个新的,它等于它自己的尾巴。然后你做
Prelude> arr
Haskell 出现并将其评估为tail arr,并将tail其参数评估为WHNF,因此要识别tail arr,我们需要知道 的形状arr,当然,tail arr。所以要知道arr,我们需要知道arr。因此,arr是底部,一个非终止值。之前的定义无关紧要。
如果您尝试在 Haskell 源文件(与命令行交互环境相反)中执行此操作,则会收到编译器错误,因为在同一范围内重新绑定现有名称是不正确的。这只是 REPL 的一项功能,您可以出于测试目的这样做。
- I'd remark that it _is_ possible to re-use variable names in GHCi, you just can't refer to the old values inside the new definition. But this works: `> let arr = [1..5]`; `arr`⇒[1,2,3,4,5]; `let arr = tail it`; `arr`⇒[2,3,4,5]