为什么解析错误?缩进?
我写了这段代码:
addNums key num = add [] key num
where add res a:as b:bs
| a == [] = res
| otherwise = add res:(a+b) as bs
在第 3 行,解释器说:
解析错误(可能是缩进不正确)
我找不到任何错误,无论是代码还是缩进。我为每个选项卡放置了四个空格。
注释:
即使这样也不能编译:
addNums key num = add [] key num
where add res a:as b:bs
| a == [] = res
| otherwise = add res:(a+b) as bs
第 2 行:
模式解析错误:添加
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Haskell 中的主要缩进规则是,如果你想在另一行继续定义,它必须比你定义的内容进一步缩进。在这种情况下,您的
add
函数的缩进较少,因此这就是编译器所抱怨的。忽略代码中的其他错误,缩进应该是这样的:
另请注意,缩进的确切数量并不重要,重要的是连续行相对于所定义内容的缩进。
你的代码的另一个语法问题是你似乎误解了 Haskell 的优先规则。在 Haskell 中,函数应用程序的绑定比任何运算符都更紧密,因此
add res a:as b:bs
被解析为(add res a):(as b) :bs
,而您的意思是添加 res (a:as) (b:bs)
。最后的问题是类型错误。
(:)
运算符的类型为a ->; [一]-> [a]
,这意味着它需要一个元素和一个列表,并生成一个列表。在您的代码res:(a+b)
中,您似乎将其颠倒过来,因为res
是一个列表,而a+b
是元素。由于 Haskell 中没有运算符可以将单个元素附加到列表的 end 上,因此您必须使用列表串联运算符(++) :: [a] -> ; [一]-> [a]
改为:res ++ [a+b]
。您还将元素
a
与守卫中的列表[]
进行比较。这可能不是您的意思,如果列表为空,模式(a:as)
将不匹配。最简单的解决方案是添加另一个模式而不是你的守卫。将所有这些放在一起,此代码有望实现您的预期:
PS 重复追加到列表末尾并不是很有效。事实上,它是 O(n2)。您可能想添加到前面,并在完成后反转列表。这是 O(n)。
参考文献:
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:
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 meantadd res (a:as) (b:bs)
.The final problems are type errors. The
(:)
operator has the typea -> [a] -> [a]
, which means that it takes an element and a list, and produces a list. In your coderes:(a+b)
, you appear to have this reversed, asres
is a list anda+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:
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:
出现缩进错误是因为您需要将 where 子句中的模式保护至少缩进到第一个定义(在您的情况下为
add
)。除此之外,由于类型错误,代码仍然无法编译。即
a
不是列表,因此a == []
不会进行类型检查。此外,您需要更多括号(用于模式匹配列表和要添加的参数)。您的意思可能是这样的:
编辑:
顺便说一句,我猜你真的想做以下事情:
如果是这样的话,你甚至可以写:
addNums = zipWith (+)
(虽然有点不同,因为它不会抛出当第二个列表比第一个列表短时,模式匹配异常)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, soa == []
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:
Edit:
By the way, I guess you really want to do the following:
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)第二个问题不是空格问题,您必须将复杂的模式
a:as
和b:bs
括起来,这样您就可以编写add res (a: as) (b:bs)
用另一种方式表达有关空白的观点,它在
where
子句中的外观就是它在顶层的外观。你会写:所以,添加缩进,你会写
但是我们不能取消你的 where 子句的缩进,所以它会在左边距。 (我将其修改为等效的内容)
因为守卫位于
add
的左侧;在这里,它们实际上位于左边距。我建议将从属定义与控制where
对齐:它不像某些东西那么可爱,但不太容易出错,因为它减少了更多地思考缩进的认知负担。 (奥列格做到了!)它也会立即避免这个困难。我认为它并不适合任何地方,但这更有吸引力,也许可以使缩进问题更清晰:
然后我们可以看到 where 子句中的定义列表就像 Haskell 模块中的定义列表一样,用 ' 排列左边距”。
The second problem is not a whitespace problem, you have to bracket the complex patterns
a:as
andb:bs
so you'd writeadd 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:So, adding indentation, you'd write
But we can't unindent your where clause so it would be on the left margin. (I modify it to something equivalent)
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 governingwhere
: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:
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'.