缺少括号的Haskell会编译但进入无限循环

Ore*_*lom 1 syntax haskell parentheses

我有一种情况,Haskell缺少括号可以很好地编译,但进入无限循环。这是我的代码,其中的工作版本已被注释掉:

$ cat main.hs
fib :: Int -> Int
fib 0 = 1
fib 1 = 1
fib n =
  let
    fib_n_minus_2 = fib n-2
    -- fib_n_minus_2 = fib (n-2)
    fib_n_minus_1 = fib (n-1)
  in
    fib_n_minus_2+
    fib_n_minus_1

main :: IO ()
main = putStrLn $ show $ fib 7
Run Code Online (Sandbox Code Playgroud)

当我编译它时,一切都很好,但是当我运行生成的程序时,它被卡住了。这是为什么?我想象编译器会进行解析fib n,然后继续查看-2 fib_n_minus_1应该在哪里停止并发出错误,对吗?

chi*_*chi 8

fib_n_minus_2 = fib n-2
Run Code Online (Sandbox Code Playgroud)

手段

fib_n_minus_2 = (fib n)-2
Run Code Online (Sandbox Code Playgroud)

并不是

fib_n_minus_2 = fib (n-2)
Run Code Online (Sandbox Code Playgroud)

请注意,这(fib n)-2是一个完全有效的表达式。

(fib n) -2 fib_n_minus1 ...由于fib_n_minus1 ...从下一行开始并缩进了与前一行完全相同的数量,因此未进行解析,因此它是该构造的下一个绑定let

实际上,您可以假装在实际解析开始之前,缩进用于在绑定周围插入显式花括号,并在它们之间插入分号,如下所示:

 let {
    fib_n_minus_2 = fib n-2 ;
    -- fib_n_minus_2 = fib (n-2)
    fib_n_minus_1 = fib (n-1)
    }
  in
    fib_n_minus_2+
    fib_n_minus_1
Run Code Online (Sandbox Code Playgroud)

在该in部分中let,只能有一个表达式,因此缩进规则不适用,并且这两行被解析为一个表达式fib_n_minus_2 + fib_n_minus_1

总之,您的代码在不减少参数的情况下调用自身n,从而导致了无限递归。