问题
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
回答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:
- Indentation
- Pattern matching
回答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)
回答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'.
来源:https://stackoverflow.com/questions/7178199/why-parse-error-indentation