You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell递归与无限循环问题:求√2迭代函数异常分析

解析Haskell中计算√2的两个函数无限循环的原因

你写的三个函数都是基于牛顿迭代法计算√2的实现,其中squareRootTwo能正常终止,而squareRootTwoA和squareRootTwoB陷入无限循环,核心原因都是名字遮蔽(Name Shadowing)导致的递归变量错误,具体分析如下:

1. squareRootTwoA的问题

函数定义里的where n=n是典型的自引用名字遮蔽:

squareRootTwoA guess n
| n == 0 = guess
| otherwise = squareRootTwoA ((guess + 2/guess) / 2) (n-1) where n=n

这里的where子句重新定义了局部变量n,让它等于自身——这是一个无限递归的定义,没有任何实际值。此时函数里所有用到n的地方(包括条件判断n == 0和递归参数n-1),都会优先使用这个局部的n,而非函数参数传入的n。

因为局部n永远无法被求值为一个具体的整数,条件n == 0永远不成立,递归会一直进行下去,最终陷入无限循环。

2. squareRootTwoB的问题

let n = n-1同样犯了名字遮蔽的错误:

squareRootTwoB guess n
| n == 0 = guess
| otherwise = let n = n-1 in squareRootTwoB ((guess + 2/guess) / 2) n

let子句里定义的局部n,右边的n引用的是这个刚定义的局部变量,而非函数参数的n。这就导致n = n-1变成了自引用的无限递归定义,永远无法得到一个递减的整数值。

递归调用时传递的n始终是这个未正确求值的局部变量,条件n == 0永远无法满足,自然会无限循环。

对比正确的squareRootTwo

正确的函数没有做任何局部变量遮蔽,递归时直接使用参数n进行递减:

squareRootTwo guess n
| n == 0 = guess
| otherwise = squareRootTwo ((guess + 2/guess) / 2) (n-1)

每次递归都会把参数n减1,直到n变为0,触发终止条件,递归正常结束。

内容的提问来源于stack exchange,提问作者Anik kanti sikder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 08:00:05