Хаскелл говорит, что у моей гвардии есть ошибка разбора

Итак, я играл с Хаскеллом последние пару дней и решил, что сделаю базовое определение последовательности Фибоначчи. Итак, я написал этот код:

main = do
    fib :: (Integral a) => Int -> Int
    fib x
        | x == 0 = 0
        | x == 1 = 1
        | x >= 2 = fib (x - 2) + fib (x - 1)
    do { print (fib 5) }

И я получаю сообщение об ошибке:

4:17: parse error on input `|'

Я подозревал ошибки табуляции, поэтому я пробовал все исправления пробелов, которые только мог найти, но я просто не могу найти, что не так!

РЕДАКТИРОВАТЬ: Итак, я сделал то, что предложили люди, и у меня есть этот код сейчас:

fib :: (Integral a) => Int -> Int
main = do
    fib x
        | x == 0 = 0
        | x == 1 = 1
        | x >= 2 = fib (x - 2) + fib (x - 1)
    print (fib 5)

И я получаю ту же ошибку.

3 ответа

Решение

Вы также можете определить fib локально main за пределами do блок. Имейте в виду, что do является синтаксическим сахаром для использования различных монадических функций связывания, и поэтому синтаксис, принятый внутри него, не совсем совпадает с синтаксисом, принятым за его пределами. И, на самом деле, ваш main даже не требует do заблокировать, потому что вы просто позвоните print вместо того, чтобы приковать IO действия вместе.

main = let
         fib x | x == 0 = 0
               | x == 1 = 1
               | x >= 2 = fib (x - 2) + fib (x + 1)
       in
         print (fib 5)

Или вы могли бы использовать where:

main = print (fib 5)
       where
         fib x | x == 0 = 0
               | x == 1 = 1
               | x >= 2 = fib (x - 2) + fib (x + 1)

Они одинаковые, вопрос только в том, куда на самом деле идет локальная привязка. let..in дает вам новый блок, где новые привязки находятся в области видимости, в то время как where делает его привязки доступными в рамках функции, к которой он прикреплен.

Если, как кажется, в конечном счете, вероятно, вы хотите do блок, так что вы можете сделать несколько IO действия, вы можете просто поставить это вместо вызова print, вот так:

main = let
         fib x | x == 0 = 0
               | x == 1 = 1
               | x >= 2 = fib (x - 2) + fib (x + 1)
       in
         do print (fib 5)
            print (fib 6)

Вы должны определить fib вне mainне внутри. И тогда вы должны удалить хотя бы один из doс из main,

Проблема в том, что вы пытаетесь определить функцию внутри do блок без использования какой-либо конструкции для определения вещей (например, let).

Попробуйте определить функцию вне блока:

fib :: (Integral a) => Int -> Int
fib x | x == 0 = 0
      | x == 1 = 1
      | x >= 2 = fib (x - 2) + fib (x - 1)

main = print (fib 5)

Если вы настаиваете на определении функции локально (внутри выражения, которое формируется операторами do блок):

main = do
    let
        fib :: (Integral a) => Int -> Int
        fib x | x == 0 = 0
              | x == 1 = 1
              | x >= 2 = fib (x - 2) + fib (x - 1)
    print (fib 5)

Обратите внимание, как let используется для привязки новой переменной fib к функции, которую вы хотите.

Другие вопросы по тегам