我对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
的定义;它们的含义相同,我只更改{{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的哪个解析规则晦涩难懂?
答案 0 :(得分:11)
非正式地,括号和分号的插入如下。只要在关键字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
两者都将按您期望的方式进行解析。