views:

156

answers:

2

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.

+8  A: 

Indent then and else lines one level more. However things may change Conditionals and do-notation.

Yasir Arsanukaev
It solved the issue, 10x!
Drakosha
+10  A: 

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".

Travis Brown