5

我写了这段代码:

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

模式中的解析错误:添加

4

3 回答 3

10

Haskell 的主要缩进规则是,如果你想在另一行继续定义,它必须比你定义的内容进一步缩进。add在这种情况下,您的函数的守卫缩进较少,这就是编译器所抱怨的。

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

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

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

您的代码的另一个语法问题是您似乎误解了 Haskell 的优先规则。在 Haskell 中,函数 application比任何 operator 绑定得更紧密,因此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 中没有将单个元素附加到列表末尾的运算符,因此您必须改用列表连接运算符(++) :: [a] -> [a] -> [a]res ++ [a+b].

您还将元素 与警卫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

PS 重复追加到列表的末尾不是很有效。事实上,它是 O(n 2 )。您可能希望添加到前面,并在完成后反转列表。这是 O(n)。


参考:

于 2011-08-24T15:38:43.713 回答
4

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

除此之外,由于类型错误,代码仍然无法编译。即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 (+)虽然它有点不同,因为它不会引发模式匹配异常,当第二个列表比第一个短时)

于 2011-08-24T15:48:59.783 回答
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 模块中的定义列表一样,用“左边距”排列。

于 2011-08-24T16:04:51.997 回答