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.
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.
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.
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.
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".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With