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