parsinghaskellsyntax-errorindentation

Is indentation in Haskell like in Python?


I just started learning Haskell and I briefly read through some of the indentation rules and it seems to me that Haskell behaves just like Python when it comes to indentation (I might be wrong). Anyway, I tried to write a tail recursive fibonacci function and I keep getting an indentation error and I don't know where I indented my code wrong.

ERROR message:

F1.hs:6:9: error:
    parse error (possibly incorrect indentation or mismatched brackets)
  |
6 |         |n<=1 = b   |         ^

Code:

fib :: Integer -> Integer
fib n = fib_help n 0 1
    where fib_help n a b
        |n<=1 = b
        |otherwise fib_help (n-1) b (a+b)

Note: I am writing the code in Notepad++ and I have changed the settings so that when I TAB it created 4 whitespaces instead of a tab character (like it should be I guess)


Solution

  • No, Haskell indentation is not like Python.

    Haskell is not about indentation levels, it's all about making things line up with other things.

        where fib_help n a b
    

    In this example you have where, and the following token is not {. This activates layout mode (i.e. whitespace sensitive parsing). The next token (fib_help) sets the start column for the following block:

        where fib_help n a b
    --        ^
    --        | this is "column 0" for the current block
    

    The next line is:

            |n<=1 = b
    

    The first token (|) is indented less than "column 0", which implicitly closes the block.

    Your code is parsed as if you had written

    fib n = fib_help n 0 1
        where { fib_help n a b }
    
            |n<=1 = b
            |otherwise fib_help (n-1) b (a+b)
    

    This is several syntax errors: The where block is missing a =, and you can't start a new declaration with |.

    Solution: Indent everything that should be part of the where block more than the first token after where. For example:

    fib n = fib_help n 0 1
        where fib_help n a b
                |n<=1 = b
                |otherwise = fib_help (n-1) b (a+b)
    

    Or:

    fib n = fib_help n 0 1
        where
        fib_help n a b
            |n<=1 = b
            |otherwise = fib_help (n-1) b (a+b)
    

    Or:

    fib n = fib_help n 0 1 where
        fib_help n a b
            |n<=1 = b
            |otherwise = fib_help (n-1) b (a+b)