Haskell 中的递归和无限循环问题

问题描述 投票:0回答:1

我在 Haskell 中有三个函数。所有这些都旨在基于 n 次迭代的初始猜测来执行 √2。 (1)

squareRootTwo :: Double -> Integer -> Double
squareRootTwo guess n
| n == 0 = guess
| otherwise = squareRootTwo ((guess + 2/guess) / 2) (n-1)

(2)

squareRootTwoA :: Double -> Integer -> Double
squareRootTwoA guess n
| n == 0 = guess
| otherwise = squareRootTwoA ((guess + 2/guess) / 2) (n-1) where n=n

(3)

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

第一个函数(squareRootTwo)工作正常。在 ghci 中:

ghci> squareRootTwo 1.0 5   
1.414213562373095

ghci> squareRootTwoA 1.0 5
No response
ghci> squareRootTwoB 1.0 5
No response

但是第二个和第三个功能根本不起作用。他们只是冻结了。我必须按 (ctrl + c) 在 VS Code 终端中停止此操作。 现在,我明白它可能正在创建递归并陷入无限循环。但是,我不明白它是如何创建无限循环的。因为这两个程序的编写方式,对我来说,它似乎没有创建无限循环。

由于我是 Haskell 的新手,我只是不明白为什么会发生这种情况。如果有人帮助我理解为什么会发生这种情况,那就太好了。谢谢。

haskell recursion infinite-loop
1个回答
0
投票

您的定义等同于以下内容:

squareRootTwoA :: Double -> Integer -> Double
squareRootTwoA guess n
  | n == 0 = guess
  | otherwise = squareRootTwoA ((guess + 2/guess) / 2) (blurb-1)
 where blurb = blurb

squareRootTwoB :: Double -> Integer -> Double
squareRootTwoB guess n
  | n == 0 = guess
  | otherwise = let blurb = blurb-1
                in squareRootTwoB ((guess + 2/guess) / 2) blurb

您会看到,递归调用中的整数参数在这两种情况下都与原始值没有任何关系

n
,它是一个全新的变量,只是碰巧具有相同的名称和shadows旧的
n
。像
n = n-1
这样的定义当然是循环的,它是一个不可能满足的方程(当其他语言将其作为语句执行时,它们在数学上对你撒谎)。

实现您尝试的方法是明确为新版本指定不同的名称:

squareRootTwoA :: Double -> Integer -> Double
squareRootTwoA guess n
  | n == 0 = guess
  | otherwise = squareRootTwoA ((guess + 2/guess) / 2) (n'-1)
 where n' = n

squareRootTwoB :: Double -> Integer -> Double
squareRootTwoB guess n
  | n == 0 = guess
  | otherwise = let n' = n-1
                in squareRootTwoB ((guess + 2/guess) / 2) n'
© www.soinside.com 2019 - 2024. All rights reserved.