对 Haskell 的布局工具如何处理此代码感到困惑

Posted

技术标签:

【中文标题】对 Haskell 的布局工具如何处理此代码感到困惑【英文标题】:Perplexed by how this code is processed by Haskell's Layout facility 【发布时间】:2015-04-04 01:16:08 【问题描述】:

在浏览https://wiki.haskell.org/IO_inside时,遇到如下注释和代码……

"此外,Haskell 布局规则允许我们使用以下布局:

main = do a <- readLn
          if (a>=0) then return ()
            else do
          print "a is negative"
          ...

这对于从冗长的 'do' 语句的中间转义可能很有用。”

下面,我将使用符号 C* 来引用上面的代码。

我推测 C* 的目的是读入一个数字,然后: (i) 如果它是非负数,什么也不做。 (ii) 如果它是负数,则显示输出说明它是负数。

我最初的反应是认为 C* 要么无法正确解析,要么无法按预期运行。

我认为 Layout 会在第二个 'do' 之后立即插入一组空的大括号和一个分号,因为词位 'print' 的缩进量不会超过由 'a' 中的 'a' 建立的当前布局上下文的缩进级别"a

也就是说,我对 Layout 生成的布局不敏感代码(以下简称 C')的预测是这样的:

main = do 
          a <- readLn;
          if (a>=0) then return ()
            else do ;
          print "a is negative"
          ...
          

我认为会是这种情况,是基于 Haskell 2010 语言报告 (https://www.haskell.org/onlinereport/haskell2010/haskellpa1.html) 第 1 部分第 2.7 节(“词汇结构”:“布局”)中包含的以下句子

"如果紧跟 where、let、do 或 of 的非大括号词位的缩进小于或等于当前缩进级别,则插入一个空列表“”而不是开始布局, 并针对当前级别进行布局处理(即插入分号或右大括号)。”

Haskell 2010 语言报告的第 1 部分(上面给出的 URL)第 10.3 节(“语法参考”:“布局”)给出了布局规则的更详细说明。

阅读这个更详细的说明后,我确信我对 Layout 生成的布局不敏感代码(即 C')的预测是正确的。

然而,令我惊讶的是,当我在 GHCi 中尝试上面规定的原始代码(即 C*)时,它可以正常工作(正确解析并按预期运行)。

问题...

    我上面引用的句子(来自第 2.7 节)是否准确?

    上面提到的布局规则的详细说明(来自第 10.3 节)是否准确?

    我用来预测由 Layout 为原始代码 C* 生成的布局不敏感代码(即 C')的推理中存在哪些缺陷?

    李>

    Layout为上面规定的原始代码(即C*)生成的布局不敏感代码是什么,解释它的规则/原则是什么?

    一般来说,有没有一种方法可以查看 Layout 生成的布局不敏感代码?如果是这样,它是什么(请在适合像我这样的 Haskell 新手的水平上详细说明/解释该技术)?

【问题讨论】:

我不确定我是否见过如此深入研究过的问题。赞一个。 【参考方案1】:

这是默认的 Haskell 标准或 Haskell 98 模式下的 GHC 的 known and documented deviation。

GHC 有一个名为NondecreasingIndentation 的语言扩展,可用于触发此行为。如果启用,do 关键字会引入一个新块,即使下一个标记以与周围块相同的缩进级别开始。

如果您不想这样,请说 -XNoNondecreasingIndentation-XHaskell2010(或相应地使用语言编译指示)。

您可以通过将 -ddump-parsed 标志传递给 GHC 来查看 GHC 解析的代码的打印版本。这只会部分删除布局(它对 do-blocks 这样做,但例如不用于 let),但仍可能提供线索。

【讨论】:

优秀的答案!谢谢!现在考虑了问题 1 到 4,但是如果有人可以回答,问题 5 仍然存在(诚然,问题 5 现在对我来说不再那么重要了,但如果有人有一个问题,我仍然会对它的答案感兴趣)。 关于使用 -ddump-parsed 标志的好建议......我一定会记住它!

以上是关于对 Haskell 的布局工具如何处理此代码感到困惑的主要内容,如果未能解决你的问题,请参考以下文章

我将如何处理此链接器错误?

如何处理此索引超出范围错误 (LINGO)

在 VC++ 中获取读取访问冲突异常如何处理此异常?

如何处理此错误:__init__() 有一个意外的关键字参数“book_category”

如何处理 Haskell 中的“可能 [值]”列表?

如何处理 IHostBuilder CreateHostBuilder 的异常