Haskell Says My Guard Has A Parse Error

327 Views Asked by At

So I've been playing with Haskell the past couple of days, and I decided I'd make a basic definition of the Fibonacci sequence. So I wrote this code:

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) }

And I get an error message saying:

4:17: parse error on input `|'

I suspected tab errors, so I tried every whitespace fix I could find, but I just can't find what's wrong!

EDIT: So I did what people suggested, and I have this code now:

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)

And I'm getting the same error.

3

There are 3 best solutions below

0
On BEST ANSWER

You can also define fib locally to main outside of the do block. Do bear in mind that do is syntactic sugar for the use of various monadic binding functions, and so the syntax accepted within it is not quite the same as that accepted outside it. And, in fact, your main doesn't even require the do block because you just call print rather than chaining any IO actions together.

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

Or you could use where:

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

They're the same, the question is just where the local binding actually goes. let..in gives you a new block where the new bindings are in scope, while where makes its bindings available in the scope of the function it's attached to.

If, as seems eventually likely, you do want a do block as well so you can do multiple IO actions, you can just put that in place of the call to print, like so:

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)
3
On

You should define fib outside of main, not inside it. And then you should remove at least one of the dos from main.

0
On

The problem is that you are trying to define the function within do block without actually using any construct for defining things (like let).

Try defining the function outside the block:

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)

If you insist on defining the function locally (inside the expression that is formed by statements of the do block):

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)

Notice how let is used to bind a new variable fib to the function you want.