let表达式中的case表达式是否需要大括号和分号?

gaa*_*kam 6 haskell let switch-statement

我对Haskell的解析规则感到困惑。

这很漂亮:

n = 5
m = 6
b = case (n, m) of
  (5, 6) -> True
  _ -> False

main = print b
Run Code Online (Sandbox Code Playgroud)

让我们把它复杂化得很小,让我们let在混合物中添加一个:

b =
  let res = case (n, m) of
    (5, 6) -> True
    _ -> False
  in not res
Run Code Online (Sandbox Code Playgroud)

(注意,为了简便起见,我省略的定义nmmain从现在开始,他们进行相同的,我只是改变b

糟糕,这里的问题:

wtf.hs:5:5: error: parse error on input ‘(’
Failed, modules loaded: none.
Run Code Online (Sandbox Code Playgroud)

我不知道,也许那是我没有得到的某种奇怪的缩进规则。好的,让我们用括号括起来:

b =
  let res = case (n, m) of {
    (5, 6) -> True
    _ -> False }
  in not res
Run Code Online (Sandbox Code Playgroud)

还没有?!

wtf.hs:6:7: error: parse error on input ‘->’
Failed, modules loaded: none.
Run Code Online (Sandbox Code Playgroud)

我很困惑。我不知道该怎么办。为什么不行呢?让我们在这里添加一个明确的分号,即使这确实是一个盲目的镜头,即使我不明白为什么在这里需要它,因为毕竟AFAIK,换行符(在此存在)应该使分号变得多余:

b =
  let res = case (n, m) of {
    (5, 6) -> True;
    _ -> False }
  in not res
Run Code Online (Sandbox Code Playgroud)

终于可以了!

...不知道,也许问题就出在letcase是在同一行。作为我自己研究的最后尝试,让我们尝试一下:

b =
  let res =
    case (n, m) of
      (5, 6) -> True
      _ -> False
  in not res
Run Code Online (Sandbox Code Playgroud)

但是,由于我不知道的原因,这是行不通的:

wtf.hs:5:5: error:
    parse error (possibly incorrect indentation or mismatched brackets)
Failed, modules loaded: none.
Run Code Online (Sandbox Code Playgroud)

说真的,我在这里很困惑。为什么在这里需要使用括号和分号?(是吗?可以将代码格式化为不需要它们的方式吗?)

我没有到达Haskell的哪个晦涩的解​​析规则?

M. *_*osi 11

从Haskell 2010报告中

非正式地说,括号和分号的插入方式如下。只要在where,let,do或of关键字后省略左括号,布局(或“越位”)规则即会生效。发生这种情况时,将记住下一个词素的缩进(无论是否在新行上),并插入省略的大括号(词素前面的空白可能包含注释)。对于每个后续行,如果它仅包含空格或缩进更多,则前一项继续(不插入任何内容);如果缩进量相同,则开始新的项目(插入分号);如果缩进较少,则布局列表结束(插入了大括号)...

...此外,这些规则还允许:

f x = let a = 1; b = 2  
          g y = exp2  
       in exp1 
Run Code Online (Sandbox Code Playgroud)

该示例实际上显示了如何在Haskell中处理缩进,基本上,不是由关键字来确定事物的缩进程度,而是它之后的第一个标识符(或其他词素),因此对于

b = case (n, m) of
  (5, 6) -> True
  _ -> False
Run Code Online (Sandbox Code Playgroud)

这很好,因为第二行和第三行的缩进比b第一行的缩进更多,另一方面,

b =
  let res =
    case (n, m) of
      (5, 6) -> True
      _ -> False
  in not res
Run Code Online (Sandbox Code Playgroud)

本质上被解析为

b =
  let { res =
    } case (n, m) of
     { (5, 6) -> True
     ; _ -> False
  } in not res  
Run Code Online (Sandbox Code Playgroud)

这是因为case缩进不超过res,所以它不是其定义的一部分。
这就是为什么编译器抱怨解析错误(它期望之后有一个词素,=但什么也没得到case,因为它不符合let ... in ...语法,所以它也没有期望那里)。

相反,你应该写

b =
  let res =
        case (n, m) of
          (5, 6) -> True
          _ -> False
  in not res
Run Code Online (Sandbox Code Playgroud)

要么

b =
  let res = case (n, m) of
        (5, 6) -> True
        _ -> False
  in not res
Run Code Online (Sandbox Code Playgroud)

两者都将按您期望的方式进行解析。