Хаскелл говорит, что у моей гвардии есть ошибка разбора
Итак, я играл с Хаскеллом последние пару дней и решил, что сделаю базовое определение последовательности Фибоначчи. Итак, я написал этот код:
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
к функции, которую вы хотите.