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

Ani*_*der 3 recursion haskell infinite-loop

我在 Haskell 中有三个函数。所有这些都旨在基于 n 次迭代的初始猜测来执行 \xe2\x88\x9a2 。

\n
    \n
  1. \n
    squareRootTwo :: Double -> Integer -> Double\nsquareRootTwo guess n\n| n == 0 = guess\n| otherwise = squareRootTwo ((guess + 2/guess) / 2) (n-1)\n
    Run Code Online (Sandbox Code Playgroud)\n
  2. \n
  3. \n
    squareRootTwoA :: Double -> Integer -> Double\nsquareRootTwoA guess n\n| n == 0 = guess\n| otherwise = squareRootTwoA ((guess + 2/guess) / 2) (n-1) where n=n\n
    Run Code Online (Sandbox Code Playgroud)\n
  4. \n
  5. \n
    squareRootTwoB :: Double -> Integer -> Double\nsquareRootTwoB guess n\n| n == 0 = guess\n| otherwise = let n = n-1 in squareRootTwoB ((guess + 2/guess) / 2) n\n
    Run Code Online (Sandbox Code Playgroud)\n
  6. \n
\n

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

\n
ghci> squareRootTwo 1.0 5   \n1.414213562373095\n\nghci> squareRootTwoA 1.0 5\nNo response\nghci> squareRootTwoB 1.0 5\nNo response\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

由于我是 Haskell 的新手,我只是不明白为什么会发生这种情况。

\n

lef*_*out 7

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

squareRootTwoA :: Double -> Integer -> Double
squareRootTwoA guess n
  | blurb == 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
Run Code Online (Sandbox Code Playgroud)

您会看到,递归调用中的整数参数在这两种情况下都与原始值没有任何关系n,它是一个全新的变量,只是碰巧具有相同的名称并隐藏了旧的变量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'
Run Code Online (Sandbox Code Playgroud)