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

Haskell missing parentheses compiles but enters infinite loop

我有一个 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

当我编译它时一切正常,但是当我运行 生成的程序时它卡住了。这是为什么?我想象编译器解析 fib n, 然后继续看-2 fib_n_minus_1应该停在什么地方报错是吧?

fib_n_minus_2 = fib n-2

表示

fib_n_minus_2 = (fib n)-2

而不是

fib_n_minus_2 = fib (n-2)

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

这不会被解析为 (fib n) -2 fib_n_minus1 ...,因为 fib_n_minus1 ... 从下一行开始并且缩进与前一行完全相同的数量,所以它是下一个 binding 用于 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

letin部分只能有一个表达式,所以缩进规则不适用,解析这两行作为一个表达式,fib_n_minus_2 + fib_n_minus_1.

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