【问题标题】:Parse error in list monad's `do` notation列表 monad 的“do”表示法中的解析错误
【发布时间】:2017-07-08 08:30:17
【问题描述】:

好的,所以这是一个奇怪的。

这很好用:

test = do
  x <- [1..5]
  y <- [1..5]
  [x+y, x-y]

但是这个:

test = do
  x <- [1..5]
  y <- [1..5]
  [
    x+y,
    x-y
  ]

惨败。 GHC 完全拒绝解析这个。无论我如何坐立不安,我似乎都无法说服 GHC 允许我将列表分布在多行中。这是个问题,因为如果你用真正的 big 表达式替换 x+y 和 x-y,它很快就会变得难以阅读......

有人知道为什么这不起作用,我该如何强制它起作用? (或者至少做一些看起来清晰的事情?)

【问题讨论】:

  • 总是使用显式大括号和分号的另一个例子(尤其是在教材中)。
  • 如果您的表达式非常大,请使用let 表达式为其定义临时名称。

标签: list haskell syntax monads do-notation


【解决方案1】:

在do 之后,与do 之后的第一个单词在同一列开始的每一行都开始一个新条目。使用显式大括号,您的代码相当于

test = do
  { x <- [1..5]
  ; y <- [1..5]
  ; [
      x+y,
      x-y
  ; ]
  }

这是由于indentation rules。正如我们所见,最后一个分号不应该在那里——为了避免它,我们应该将最后一行缩进更多。

【讨论】:

    【解决方案2】:

    如果我解析这个,我会得到以下错误:

    File.hs:10:3: error:
        parse error (possibly incorrect indentation or mismatched brackets)
    

    我认为解析器只是将右方括号] 视为一个新语句。它抱怨前一个语句没有右括号(而新的语句是没有左括号的右括号)。如果你将它推到右边一列,它会正确解析(至少在 GHC-8.0.2 中)

    test = do
      x <- [1..5]
      y <- [1..5]
      [
        x+y,
        x-y
       ] -- one space to the right
    

    只要你不回到之前的缩进级别(这里是左边一个空格),应该没问题。因为编译器会将其视为一个do-statement。

    【讨论】:

    • 嗯。为了修复缩进规则你必须缩进不正确真的很奇怪......我还发现你可以使用多余的let块来摆脱这个.不过还是很烦人。
    • @MathematicalOrchid 好吧,取决于你所说的“正确”。左括号和右括号应该缩进到同一级别的规则不是标准的,IMO也没有多大意义。我发现更烦人的是,在这种情况下,您也不能将 commata 缩进到与前面括号相同的级别。 — 请注意,在do 块的情况下,该问题比let 更容易规避——写&gt; id [ x+y \n &gt;   , x-y ] 就足够了。 (但可能会更令人困惑,所以我真的不推荐这个。)
    【解决方案3】:

    这里有几种合法的写法:

    test = do
      [x,y] <- replicateM 2 [1..5]
      [
        x+y
       ,x-y
       ]
    
    test = do
      [x,y] <- replicateM 2 [1..5]
      [ x+y
       ,x-y ]
    
    test = do
      [x,y] <- replicateM 2 [1..5]
      [ x+y ,
        x-y ]
    
    test = do
      [x,y] <- replicateM 2 [1..5]
      id [ x+y
         , x-y ]
    
    test = do
      [x,y] <- replicateM 2 [1..5]
      id [
           x+y,
           x-y
         ]
    
    test = do
      [x,y] <- replicateM 2 [1..5]
      ([
         x+y,
         x-y
       ])
    

    【讨论】:

    • 我个人最喜欢使用id。
    • @MathematicalOrchid id 看起来像个黑客。 “原生”解决方案是一个额外的尾随 return,例如 do { ... ; r &lt;- [x+y, x-y] ; return r}。
    • @WillNess 我想说这更像是一种黑客行为。唯一真正明智的做法是使缩进符合 Haskell 标准。
    • @leftaround 关于意见问题,然后。为了清楚起见,我希望尾矿返回始终在那里。 (嗯,几乎总是)。
    猜你喜欢
    • 1970-01-01
    • 2017-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多