对 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 的布局工具如何处理此代码感到困惑的主要内容,如果未能解决你的问题,请参考以下文章