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

时间:2019-03-21 10:28:46

标签: haskell switch-statement let

我对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的定义;它们的含义相同,我只更改{{1} })

糟糕,这里有问题:

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

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

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 let在同一行上。作为我自己研究的最后尝试,让我们尝试一下:

case

但是由于我不知道的原因,这将无法工作:

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

严重的是,我在这里感到困惑。为什么在这里需要使用括号和分号? (是吗?可以将代码格式化为不需要的格式吗?)

Haskell的哪个解析规则晦涩难懂?

1 个答案:

答案 0 :(得分:11)

From the Haskell 2010 Report

  

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

     

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

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

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

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

这很好,因为第二行和第三行比第一行的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

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