我对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
(注意,为简洁起见,我从现在开始省略n
,m
和main
的定义;它们继续相同,我只改变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
这终于有效了!
...不知道,也许问题在于let
和case
在同一条线上。作为我自己研究的最后一次尝试,让我们试试这个:
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哪个模糊的解析规则我没有到这里?
非正式地说,括号和分号插入如下。只要在关键字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
这两个都将按照您的预期进行解析。