【问题标题】:Why parse error? Indentation?为什么要解析错误?缩进?
【发布时间】:2011-11-02 22:33:43
【问题描述】:

我写了这段代码:

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

模式中的解析错误:添加

【问题讨论】:

  • 第二个问题不是空格问题,您必须将复杂模式a:asb:bs 括起来,这样您就可以写add res (a:as) (b:bs)

标签: haskell pattern-matching indentation parse-error


【解决方案1】:

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]

您还将 element alist [] 进行比较。这可能不是您的意思,如果列表为空,则模式 (a:as) 将不匹配。最简单的解决方案是添加另一个模式而不是你的守卫。

把所有这些放在一起,这段代码应该能达到你的预期:

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

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


参考资料:

【讨论】:

  • 所以相对缩进必须每块都增加?那么最小的缩进可能是:1,3,7,15,31,... 您能否参考 wiki 中定义它的部分?
  • @user905686:我不确定你从哪里得到这些数字。我已在我的回答中链接到 WikiBook 页面。它在解释它方面做得比我在这里更合适。
  • 使用差异列表仍然比重复cons'ing和reversing有效,尽管两者都比重复附加到列表要好得多。
  • @user905686 不,相对缩进不必每块都上升,只有绝对缩进。所以最小可能的缩进是 1, 2, 3, 4, 5, ... 。但是,请注意where 块的绝对缩进取决于where 关键字之后的第一个非空白、非注释字符——所以在上面的最终代码sn-p 中,add 块是缩进的4 个空格 + 5 个字符(where)+ 1 个空格 = 10 个空格!
  • @Daniel Wagner 现在我明白了!泰。
【解决方案2】:

出现缩进错误,因为您需要将 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 (+)(虽然有点不同,因为当第二个列表比第一个短时它不会引发模式匹配异常)

【讨论】:

  • 我的意思是检查整个列表 a:as 是否为空。为什么是括号?
  • @user905686 a:as 不能为空;如果a:as 匹配成功,则列表中至少有一个元素,即与a 匹配的元素。要处理add 的第二个参数为空,请添加add res [] (b:bs) = res 形式的另一个定义。
【解决方案3】:

第二个问题不是空格问题,您必须将复杂模式 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 模块中的定义列表一样,用“左边距”排列。

【讨论】:

  • 另一种避免歧义的样式(也是我使用的样式)是简单地将缩进敏感块的第一个标记始终与它之前的任何内容对齐,然后使用垂直对齐。所以add res (a:as) (b:bs) | as == [] = res 将是第一行。当然,这也鼓励简洁仔细地分解成更小的函数,以免以 40m/s 的速度撞到右边距……
  • 我不这样做,也许我应该这样做 - 但对于迷失在 Haskell 空白中的初学者来说,它似乎确实有明显的优点,它可以减少对放置第一后卫的焦虑。
猜你喜欢
  • 1970-01-01
  • 2018-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-25
  • 2015-10-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多