0

所以过去几天我一直在玩 Haskell,我决定对斐波那契数列做一个基本定义。所以我写了这段代码:

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)

我得到了同样的错误。

4

3 回答 3

3

您应该fib在外部定义main,而不是在其中定义。然后您应该从 中删除至少一个dos main

于 2016-05-04T20:14:58.427 回答
3

问题是您试图在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到您想要的函数。

于 2016-05-06T11:32:28.867 回答
1

您还可以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)
于 2016-05-06T12:17:33.160 回答