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

问题描述 投票:6回答:1

我对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.

我完全糊涂了。我不知道该怎么办。为什么这不起作用?让我们在这里添加一个明确的分号,即使这显然是一个盲目的镜头,即使我不明白为什么会在这里需要它,因为毕竟AFAIK,一个换行符(这里存在)应该使分号多余:

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哪个模糊的解析规则我没有到这里?

haskell switch-statement let
1个回答
11
投票

From the Haskell 2010 Report

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

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

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缩进,所以它不是它的定义的一部分。 这就是为什么编译器抱怨解析错误(它期望=之后的一个lexeme但什么都没有,它也不期望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

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

© www.soinside.com 2019 - 2024. All rights reserved.