Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

strange error in haskell about indentation of if-then-else

I have the following code:

foo :: Int -> [String] -> [(FilePath, Integer)] -> IO Int
foo _ [] _ = return 4
foo _ _ [] = return 5
foo n nameREs pretendentFilesWithSizes = do
  result <- (bar n (head nameREs) pretendentFilesWithSizes)
  if result == 0
  then return 0 --  <========================================== here is the error
  else foo n (tail nameREs) pretendentFilesWithSizes

I get an error on the line with the comment above, the error is:

aaa.hs:56:2:
    parse error (possibly incorrect indentation)

I'm working with emacs, there's no spaces, and i do not understand what did i do wrong.

like image 441
Drakosha Avatar asked May 31 '10 19:05

Drakosha


People also ask

Is Haskell indentation sensitive?

No, Haskell indentation is not like Python. Haskell is not about indentation levels, it's all about making things line up with other things. The first token ( | ) is indented less than "column 0", which implicitly closes the block.

Is Haskell indentation Based?

Intermediate HaskellHaskell relies on indentation to reduce the verbosity of your code. Despite some complexity in practice, there are really only a couple fundamental layout rules.

What is a parse error in Haskell?

Haskell has what I would consider to be 3 different types of errors: parse errors, definition errors, & type errors. Parse errors occur when we have broken a formatting rule or some convention enforced by the compiler. Once we fix all of those we will get definition errors.


1 Answers

This is explained in the "if-within-do" section of the Wikibooks article on Haskell indentation.

The problem is that to the do-desugarer, the then and else lines look like new statements:

do { first thing
   ; if condition
   ; then foo
   ; else bar
   ; third thing }

Indenting the then and else lines will solve the problem.

UPDATE: Since this is tagged beginner, I'll also note that something like the following would generally be considered more idiomatic in Haskell:

foo :: Int -> [String] -> [(FilePath, Integer)] -> IO Int
foo _ [] _ = return 4
foo _ _ [] = return 5
foo n (r:rs) filesWithSizes = bar n r filesWithSizes >>= checkZero
  where
    checkZero :: Int -> IO Int
    checkZero 0 = return 0
    checkZero _ = foo n rs filesWithSizes

This does exactly the same thing as your foo, but it avoids the do sugar and uses pattern matching instead of head and tail and the if-then-else control structure. Informally, the >>= here says "take the output of bar... out of its IO wrapper and run it through checkZero, returning the result".

like image 166
Travis Brown Avatar answered Oct 26 '22 22:10

Travis Brown