Haskell解析错误缩进的错误

时间:2015-09-11 20:18:57

标签: haskell

有谁可以解释为什么这是语法错误?

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布局而感到羞耻)

  1. 为什么第一个例子是错误的?
  2. 为什么第二个例子不是错误?

1 个答案:

答案 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'缩进。这就是您在第一个代码段中出现错误的原因。

在您的第三个示例中,pf'缩进,这符合规则。

修改

奇怪的是,你的第二个例子没有给出错误,因为p没有比f'进一步缩进,但是有相同的缩进,而且几乎看起来这不是故意的(即a BUG)。我做了一些研究,发现do语句实际上有所不同。以下是错误:

f =
  f'
  where f' = -- no do
        if True then
          return ()
        else
          return ()

where / letdo之间的互动似乎会导致并发症。请查看以下示例:

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