Haskell, отсутствующие скобки, компилируется, но входит в бесконечный цикл - PullRequest
1 голос
/ 15 октября 2019

У меня есть случай, когда пропущенные скобки на 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, где он должен остановиться и выдать ошибку, верно?

1 Ответ

8 голосов
/ 15 октября 2019
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 ... начинается со следующей строки и имеет отступ, равный той же самой сумме, что и предыдущая, так что это следующая привязка для конструкции 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

В in в разделе let может быть только одно выражение , поэтому правило отступа не применяется, и эти две строки анализируются как одно выражение, fib_n_minus_2 + fib_n_minus_1.

В заключение,ваш код вызывает сам себя без уменьшения аргумента n, вызывая бесконечную рекурсию.

...