有谁可以解释为什么这是语法错误?
f =
f'
where f' = do
if True then
return ()
else
return ()
main = f
如果我对if
块进行更多缩进,那么它会以某种方式编译好。
f =
f'
where f' = do
if True then
return ()
else
return ()
main = f
或者我可以将我where
分开,我通常会这样做。
f =
f'
where
f' = do
if True then
return ()
else
return ()
main = f
我开始赏金以获得下面两个问题的好解释。 (是的,我读了Haskell报告。因为我不理解 10.3布局而感到羞耻)
答案 0 :(得分:6)
您违反的规则在Section 10.3下的注1中说明。我来引用一下:
注1。 嵌套上下文必须比封闭上下文( n> m )进一步缩进。如果没有, L 失败,编译器应指出布局错误。一个例子是: [例如,见下文] 这里,
p
的定义缩进小于封闭上下文的缩进,在本例中由h
的定义设置。
示例如下:
f x = let
h y = let
p z = z
in p
in h
在您的情况下,if
- 语句的上下文是f'
定义。 (正如在示例中,p
的定义的上下文是h
的定义。)由于if
- 语句是嵌套上下文,因此它需要缩进比封闭上下文(即if
需要比f'
缩进。这就是您在第一个代码段中出现错误的原因。
在您的第三个示例中,p
比f'
缩进,这符合规则。
修改强>
奇怪的是,你的第二个例子没有给出错误,因为p
没有比f'
进一步缩进,但是有相同的缩进,而且几乎看起来这不是故意的(即a BUG)。我做了一些研究,发现do
语句实际上有所不同。以下是错误:
f =
f'
where f' = -- no do
if True then
return ()
else
return ()
where
/ let
和do
之间的互动似乎会导致并发症。请查看以下示例:
1)编译没有问题:
f = let y = do
Just 1
in y
2)这会导致错误:
f = let y =
Just 1
in y
3)编译没有问题:
f = do
Just 1
4)这会导致错误:
f = do
Just 1
这里很奇怪的是(4)中的错误与(1)的成功解析不一致,并且(1)的成功解析似乎与前面所述的规则不一致(嵌套上下文需要进一步缩进)。
编辑2:
好吧,似乎我已经深究了它! (我继续提交了一份错误报告,但由于E.Z.Yang的解释,该报告被认为无效。)
这是交易:在某些情况下,使用do
- 符号时不需要不断增加缩进。因此,实现了语言扩展NondecreasingIndentation
,默认情况下处于启用状态。有关详细信息,请参阅here。
可以关闭此功能,以便在增加if-then-else
的缩进之前,不会编译以下版本的代码 - 部分:
{-# LANGUAGE NoNondecreasingIndentation #-}
f =
f'
where f' = do
if True then
return ()
else
return ()
NondecreasingIndentation
功能仅在已缩进的上下文中处于活动状态。这就是为什么我的上一个例子(4),即使启用了扩展,也不能编译。
<强> TL; DR 强>
golden rule of indentation通常有效,但有例外。缩进的do
- 块不需要进一步缩进而不是它们的封闭上下文。要阻止GHC以这种方式处理do
- 阻止,请启用语言扩展NoNondecreasingIndentation
。