绑定变量时Haskell中的无限循环
下面的Haskell代码没有终止,有人能解释一下原因吗?谢谢绑定变量时Haskell中的无限循环,haskell,Haskell,下面的Haskell代码没有终止,有人能解释一下原因吗?谢谢 f = let x = 10 in let x = x * x in x 我想口译员先绑定x:10, 然后计算x*x到100并绑定x:100, 环境变成x:100, 然后整个表达式的计算结果为100 但是,此代码不会终止。当计算baz中形式为let foo=bar的let语句时,foo在计算bar时已绑定到bar——即定义是递归的,如果存在同名的外部绑定,它只是被忽略,因为它不再在范围内 在一条评论中,您询问了为什么不查找x失败的原
f = let x = 10 in let x = x * x in x
我想口译员先绑定x:10,
然后计算x*x到100并绑定x:100,
环境变成x:100,
然后整个表达式的计算结果为100
但是,此代码不会终止。当计算baz中形式为
let foo=bar的let语句时,foo
在计算bar
时已绑定到bar
——即定义是递归的,如果存在同名的外部绑定,它只是被忽略,因为它不再在范围内
在一条评论中,您询问了为什么不查找x
失败的原因。原因是查找x
不会失败。Haskell知道x
等于x*x
,所以这就是查找产生的结果
因此,当计算x
时,它将替换为其定义x*x
。评估它然后用它的定义替换第一个x
s,产生x*x*x
,然后x*x*x
,依此类推
您可能想知道为什么允许值以这种方式递归,因此这里有一个实际有用的示例,它不仅会导致无限循环:让xs=42:xs在take 2 xs中生成结果[42,42]
。这里,xs
扩展为42:xs
,然后42:42:xs
,然后它停止,因为take 2
只需要前两个元素,所以它停止
当然,当rhs是一个函数时,很明显,定义是递归的非常有用:let fac=\n->如果n=0,那么1 else n*fac(n-1)
-这里你显然希望fac
引用它自己,而不是之前对fac
的定义,让表达式是递归的,所以当你有让x=x*x
时,它都是相同的x
,而不是来自外部作用域的。如果是相同的,为什么它不报告错误,因为x
的查找失败?递归定义是Haskell的许多方面的核心,例如映射f[]=[];映射f(x:xs)=fx:mapfxs
。我们希望=
右侧的映射的实例与=
左侧的映射的实例相同。甚至还有一个函数fix
,它被定义为fix f=let x=f x in x
,它实际上可以产生有价值的结果,一个微不足道的函数是fix(1:)
,这会创建一个无限长的1
s延迟列表,反复引用相同的1
,这样它就不会在RAM中爆炸。你是说这是无限的,因为x=x*x
的延迟计算?我认为如果您首先在x=x*x
的RHS中计算x
,那么就没有问题了。但是,如果您首先计算x=x*x
而没有首先计算RHS中的x
,x
绑定到x*x
,那么在x*x
中计算x
将导致此非终止,对吗?为什么会被否决?投票结束似乎也很不合理。我明白了,这正是我所想的。我可以把这看作是Haskell的惰性计算吗?似乎环境允许将非值绑定到变量。@xwang:是的,在严格的语言中,递归值定义是不可能的(除了一些特殊情况,如使用数据构造函数的循环定义,OCaml中的rec xs=42::xs
就是一个例子)。