Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursion and infinite loops problem in Haskell

I have three functions in Haskell. All of them are meant to be perform √2 based on an initial guess for n iterations.

  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
    

The first function (squareRootTwo) is working fine. In ghci:

ghci> squareRootTwo 1.0 5   
1.414213562373095

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

But the second and the third function aren't working at all. They just frezees. I had to press (ctrl + c) to stop this in VS Code terminal. Now, I understand maybe it's creating a recursion and falls into a infinite loop. But, I don't understand how it's creating a infinite loop. Because the way both programs are written, to me it seems like it's not creating a infinite loop.

Since I'm new to the Haskell, I just don't understand why is this happening.

like image 766
Anik kanti sikder Avatar asked Feb 27 '26 13:02

Anik kanti sikder


1 Answers

Your definitions are equivalent to the following:

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

You see that the integer argument in the recursive call has in both cases nothing at all to do with the original value n, it's a completely new variable that just happens to have the same name and shadows the old n. And a definition like n = n-1 is of course circular, it's an equation that can't possibly be fulfilled (other languages are mathematically lying to you when they execute this as a statement).

The way to achieve what you attempted is to explicitly give the new version a different name:

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'
like image 177
leftaroundabout Avatar answered Mar 01 '26 05:03

leftaroundabout