Why parse error? Indentation?

19,782

Solution 1

The main indendation rule in Haskell is that if you want to continue a definition on another line, it has to be further indented than the the thing you're defining. In this case the guards for your add function are less indented, so that's what the compiler is complaining about.

Disregarding the other errors in your code, the indentation should be something like this:

addNums key num = add [] key num
    where add res a:as b:bs
            | a == [] = res
            | otherwise = add res:(a+b) as bs

Also note that the exact amount of indentation does not matter, only the indentation of the continuing lines relative to the thing being defined.

Another syntactic problem with your code is that you seem to have misunderstood the precedence rules of Haskell. In Haskell, function application binds tighter than any operator, so add res a:as b:bs is parsed as (add res a):(as b):bs, while you meant add res (a:as) (b:bs).

The final problems are type errors. The (:) operator has the type a -> [a] -> [a], which means that it takes an element and a list, and produces a list. In your code res:(a+b), you appear to have this reversed, as res is a list and a+b is the element. Since there is no operator in Haskell to append a single element to the end of a list, you'll have to use the list concatenation operator (++) :: [a] -> [a] -> [a] instead: res ++ [a+b].

You're also comparing the element a to the list [] in your guard. This is probably not what you meant, and the pattern (a:as) would not match if the list was empty. The easiest solution to this is to add another pattern instead of your guard.

Putting all of this together, this code should hopefully do what you intended:

addNums key num = add [] key num
    where add res [] _ = res
          add res (a:as) (b:bs) = add (res ++ [a+b]) as bs

P.S. Repeatedly appending to the end of a list is not very efficient. In fact, it's O(n2). You might want to add to the front instead and reverse the list when you're done. This is O(n).


References:

Solution 2

The indentation error arises, because you need to indent the pattern guards in the where-clause at least as far as the first definition (add in your case).

Besides that, the code still doesn't compile, because of type errors. I.e a isn't a list, so a == [] doesn't typecheck. Additionally, you need more parenthesis (for pattern matching the list and for the argument to add).

Did you maybe mean something like this:

addNums key num = add [] key num
    where add res (a:as) (b:bs)
            | as == [] = res
            | otherwise = add (res ++ [a+b]) as bs

Edit: By the way, I guess you really want to do the following:

addNums key num = add [] key num
    where add res (a:as) (b:bs)
           | as == [] = res ++ [a+b]
           | otherwise = add (res ++ [a+b]) as bs

If that's the case, you could even write: addNums = zipWith (+) (although it's a little different, since it doesn't throw a pattern match exception, when the second list is short than the first)

Solution 3

The second problem is not a whitespace problem, you have to bracket the complex patterns a:as and b:bs so you'd write add res (a:as) (b:bs)

To put the point about whitespace in another way, the way it looks in the where clause is the way it would look at the top level. You would write:

addNums1 key num = add [] key num

add res (a:as) (b:bs)
  | as == [] = res
  | otherwise = add (res ++ [a+b]) as bs

So, adding indentation, you'd write

 addNums2 key num = add [] key num
   where 
   add res (a:as) (b:bs)
     | as == [] = res
     | otherwise = add (res ++ [a+b]) as bs

But we can't unindent your where clause so it would be on the left margin. (I modify it to something equivalent)

addNums key num = add [] key num
  where   
  add res a:as b:bs
| a == [] = res
| otherwise = add res:(a+b) as bs

since the guards are to the left of add; here they actually wind up on the left margin. I recommend lining up subordinate definitions with the governing where:

woof xs = foldr moo baaaah xs
  where
  moo :: Integer -> Integer -> Integer
  moo x 0 = 17
  moo x y = x * x + y * (y + x + 1)
  baaaah :: Integer
  baaaah = 3

-- *Main> woof [1,2]
-- 529

It's not as lovely as some things, but less error prone since it decreases the cognitive load of thinking more about indentation. (And Oleg does it!) It would immediately have averted this difficulty too. I think it isn't suitable everywhere, but this is more attractive and maybe makes indentation questions clearer:

 woof xs = foldr moo baaaah xs where
   moo :: Integer -> Integer -> Integer
   moo x 0 = 17
   moo x y = x * x + y * (y + x + 1)
   baaaah :: Integer
   baaaah = 3

Then we can see that the list of definitions in the where clause are like the list of definitions in a Haskell module, lined up with a 'left margin'.

Share:
19,782
user905686
Author by

user905686

Updated on June 04, 2022

Comments

  • user905686
    user905686 almost 2 years

    I wrote this code:

    addNums key num = add [] key num
        where add res a:as b:bs
            | a == [] = res
            | otherwise = add res:(a+b) as bs
    

    At line 3 the interpreter says:

    parse error (possibly incorrect indentation)

    I could not find something wrong, neither with the code nor with the indentation. I put four spaces for each tab.

    Annotation:

    Even this does not compile:

    addNums key num = add [] key num
        where add res a:as b:bs
                | a == [] = res
                | otherwise = add res:(a+b) as bs
    

    Line 2:

    Parse error in pattern: add

  • user905686
    user905686 over 12 years
    So the relative indentation has to rise every block? Then the smallest indentation ossible would be: 1,3,7,15,31,... Could you please reference to the section in the wiki where this is defined?
  • user905686
    user905686 over 12 years
    I meant to check if the whole list a:as is empty. Why the brackets?
  • hammar
    hammar over 12 years
    @user905686: I'm not sure where you're getting those numbers from. I've linked to the WikiBook page in my answer. It does a better job of explaining it than I can fit here.
  • John L
    John L over 12 years
    Using a difference list is yet efficient than repeated cons'ing and reversing, although both are much better than repeatedly appending to a list.
  • jwodder
    jwodder over 12 years
    @user905686 a:as can't be empty; if a:as is successfully matched, then there's at least one element in the list, and that's the element that's matched to a. To handle the second argument of add being empty, add another definition of the form add res [] (b:bs) = res.
  • C. A. McCann
    C. A. McCann over 12 years
    Another style that avoids ambiguity (and is the style I use) is to simply always have the first token of an indentation-sensitive block in-line with whatever precedes it, then use vertical alignment afterwards. So add res (a:as) (b:bs) | as == [] = res would be the first line. Of course, this also encourages concision and careful decomposition into smaller functions, in order to avoid slamming into the right margin at 40m/s...
  • applicative
    applicative over 12 years
    I don't do that, maybe I should -- but it does seem to have the clear merit for beginners who are lost in Haskell whitespace that it reduces anxiety about placing the first guard.
  • Daniel Wagner
    Daniel Wagner over 12 years
    @user905686 No, the relative indentation doesn't have to rise every block, only the absolute indentation. So the smallest possible indentation would be 1, 2, 3, 4, 5, ... . However, note that the absolute indentation of a where block depends on the first non-whitespace, non-comment character after the where keyword -- so in the final code snippet above, the add block is indented 4 spaces + five characters (for where) + 1 space = 10 spaces!
  • user905686
    user905686 over 12 years
    @Daniel Wagner now i see! Ty.