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

Does a case expression in a let expression require braces and semicolons?

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

效果很好:

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

main = print b

让我们稍微复杂一点,让我们在混合物中添加 let

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

(注意,为简洁起见,从现在开始我将省略 nmmain 的定义;它们继续相同,我只是更改 b)

糟糕,这里有问题:

wtf.hs:5:5: error: parse error on input ‘(’
Failed, modules loaded: none.

我不知道,也许这是某种我没有理解的奇怪的缩进规则。好吧,让我们加上明确的括号:

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

还是不行?!

wtf.hs:6:7: error: parse error on input ‘->’
Failed, modules loaded: none.

我完全糊涂了。我不知道该怎么办。为什么这行不通??让我们在这里添加一个明确的分号,尽管这确实是一个盲目射击,尽管我不明白为什么这里需要它,因为毕竟,据我所知,一个换行符(出现在此处)应该使分号变得多余:

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

这终于奏效了!

...不知道,也许问题出在letcase在同一条线上。作为我自己研究这个的最后一次尝试,让我们试试这个:

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

然而,由于对我来说很神秘的原因,这将不起作用:

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

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

Haskell 哪个晦涩的解​​析规则我不明白?

From the Haskell 2010 Report:

Informally stated, the braces and semicolons are inserted as follows. The layout (or “off-side”) rule takes effect whenever the open brace is omitted after the keyword where, let, do, or of. When this happens, the indentation of the next lexeme (whether or not on a new line) is remembered and the omitted open brace is inserted (the whitespace preceding the lexeme may include comments). For each subsequent line, if it contains only whitespace or is indented more, then the previous item is continued (nothing is inserted); if it is indented the same amount, then a new item begins (a semicolon is inserted); and if it is indented less, then the layout list ends (a close brace is inserted)...

...Also, these rules permit:

f x = let a = 1; b = 2  
          g y = exp2  
       in exp1 

这个例子实际上展示了你应该如何处理 Haskell 中的缩进,基本上决定缩进程度的不是 关键字 ,而是它们后面的第一个标识符(或其他词位),所以在

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

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

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

本质上被解析为

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

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

你应该写

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

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

两者都将按照您的预期进行解析。