为什么解析错误?缩进?

时间:2011-08-24 15:34:47

标签: haskell pattern-matching indentation parse-error

我写了这段代码:

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行:

  

模式中的解析错误:添加

3 个答案:

答案 0 :(得分:9)

Haskell中的主要压缩规则是,如果要在另一条线上继续定义,则必须进一步缩进而不是您定义的内容。在这种情况下,add函数的守卫 less 缩进,这就是编译器抱怨的内容。

忽略代码中的其他错误,缩进应该是这样的:

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

另请注意,缩进的确切数量无关紧要,只是相对于正在定义的事物的连续行的缩进。

您的代码的另一个语法问题是您似乎误解了Haskell的优先规则。在Haskell中,函数应用程序绑定比任何运算符更紧密,因此add res a:as b:bs被解析为(add res a):(as b):bs,而您的意思是add res (a:as) (b:bs)

最后的问题是类型错误。 (:)运算符的类型为a -> [a] -> [a],这意味着它需要元素列表,并生成列表。在您的代码res:(a+b)中,您似乎反过来了,因为res是一个列表,a+b是元素。由于Haskell中没有运算符将单个元素附加到列表的 end ,因此您必须使用列表并置运算符(++) :: [a] -> [a] -> [a]代替:res ++ [a+b]。< / p>

您还要将元素 a与警卫中的列表 []进行比较。这可能不是您的意思,如果列表为空,则模式(a:as)将不匹配。对此最简单的解决方案是添加另一种模式而不是保护。

将所有这些放在一起,这段代码应该按照你的意图行事:

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

P.S。反复附加到列表的末尾并不是非常有效。事实上,它是O(n 2 )。您可能希望添加到前面,并在完成后反转列表。这是O(n)。


参考文献:

答案 1 :(得分:4)

出现缩进错误,因为您需要至少在第一个定义(在您的情况下为add)中缩进where子句中的模式保护。

除此之外,由于类型错误,代码仍然无法编译。 I.e a不是列表,因此a == []没有进行类型检查。此外,您需要更多括号(用于匹配列表的模式和要添加的参数)。

你有没有这样的意思:

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

修改 顺便说一句,我想你真的想做以下事情:

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

如果是这种情况,你甚至可以写:addNums = zipWith (+)(虽然它有点不同,因为当第二个列表比第一个列表短时,它不会抛出模式匹配异常)

答案 2 :(得分:2)

第二个问题不是空白问题,你必须将复杂模式a:asb:bs括起来,以便你写add res (a:as) (b:bs)

以另一种方式提出关于空白的观点,它在where子句中的样子是它在顶层看的方式。你会写:

addNums1 key num = add [] key num

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

所以,添加缩进,你会写

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

但我们不能取消你的where子句,因此它会在左边缘。 (我将其修改为等效的东西)

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

因为守卫在add的左边;他们实际上在左边缘结束了。我建议使用管辖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

它不像某些东西那么可爱,但不容易出错,因为它减少了更多关于缩进思维的认知负担。 (奥列格做到了!)它也会立即避免这种困难。我认为它并不适用于所有地方,但这更具吸引力,也许使缩进问题更清晰:

 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

然后我们可以看到where子句中的定义列表与Haskell模块中的定义列表类似,排列为“左边距”。