【问题标题】:Desugaring do-notation for Monads为 Monad 脱糖 do-notation
【发布时间】:2011-11-05 10:44:17
【问题描述】:

在学习 Haskell 时,我意识到 do 符号只是语法糖:

a = do x <- [3..4]
       [1..2]
       return (x, 42)

翻译成

a = [3..4] >>= (\x -> [1..2] >>= (\_ -> return (x, 42)))

我意识到我可能会使用 do-notation,但我想了解翻译中发生了什么。所以纯粹出于教学原因,ghc/ghci 有没有办法为我用 do-notation 编写的相当复杂的 monad 提供相应的绑定语句?

编辑。事实证明 #haskell 上的 lambdabot 可以做到这一点:

<Guest61347> @undo do x <- [3..4] ; [1..2] ; return (x, 42)
<lambdabot> [3 .. 4] >>= \ x -> [1 .. 2] >> return (x, 42)

这是Undo plugin的源代码。

【问题讨论】:

  • 其实m &gt;&gt;= (\_ -&gt; k)m &gt;&gt; k
  • Lambdabot 有一个“撤消”插件,可以脱糖标记
  • 我只是在学习,感觉这是真正理解特定实例细节的关键——它们都是用 >>= 的形式编写的

标签: haskell monads do-notation


【解决方案1】:

您可以要求 GHC 的 desugarer 的输出,但这也会对许多其他语法进行 desugar。

首先,我们会将您的代码放入模块Foo.hs

module Foo where

a = do x <- [3..4]
       [1..2]
       return (x, 42)

接下来,我们将要求 GHC 对其进行编译并在脱糖阶段后输出结果:

$ ghc -c Foo.hs -ddump-ds

输出可能看起来相当混乱,因为它是 Haskell 的变体,称为 Core,用作 GHC 的中间语言。但是,一旦习惯了它,阅读起来并不难。在其他一些定义的中间,我们找到了你的:

Foo.a :: [(GHC.Integer.Type.Integer, GHC.Integer.Type.Integer)]
LclIdX
[]
Foo.a =
  >>=_agg
    @ GHC.Integer.Type.Integer
    @ (GHC.Integer.Type.Integer, GHC.Integer.Type.Integer)
    (enumFromTo_ag7
       (GHC.Integer.smallInteger 3) (GHC.Integer.smallInteger 4))
    (\ (x_adf :: GHC.Integer.Type.Integer) ->
       >>_agn
         @ GHC.Integer.Type.Integer
         @ (GHC.Integer.Type.Integer, GHC.Integer.Type.Integer)
         (enumFromTo_ags
            (GHC.Integer.smallInteger 1) (GHC.Integer.smallInteger 2))
         (return_aki
            @ (GHC.Integer.Type.Integer, GHC.Integer.Type.Integer)
            (x_adf, GHC.Integer.smallInteger 42)))

Core 不是很漂亮,但在使用 GHC 时能够读取它非常有用,因为您可以在后期阶段读取转储,以了解 GHC 如何优化您的代码。

如果我们删除重命名器添加的_xyz 后缀,以及类型应用程序@ Xyz 和对GHC.Integer.smallInteger 的调用,并再次使运算符中缀,你会得到这样的结果:

Foo.a :: [(GHC.Integer.Type.Integer, GHC.Integer.Type.Integer)]
Foo.a = enumFromTo 3 4 >>= \x -> enumFromTo 1 2 >> return (x, 42)

【讨论】:

  • 这引出了一个问题……有什么东西可以自动删除 _xyz 后缀、键入应用程序、调用 GHC.Integer.smallInteger 并使运算符再次中缀?
  • @missingno:我不知道。但是,有一些库可用于在 Hackage 上与 Haskell 或 Core 一起使用,因此如果您非常想要将某些东西组合在一起应该不会太难。
  • 问题是,当您编写代码来执行此操作时,您不再需要它了。
  • @missingno 有一个标志来抑制足够的,ghc -ddump-ds -dsuppress-uniques Foo.hs 将从输出中删除它们。从 ghc-7.2 开始,还有一个 -ddump-to-file 标志,这将使 ghc 将输出转储到本例中的 Foo.dump-ds 中。如果您想要多个转储,例如,这将非常有用。 ghc -ddump-ds -ddump-simpl -ddump-to-file Foo 将产生 Foo.dump-ds 和 Foo.dump.simpl (顺便说一句,-ddump-simpl 还提供了一个去糖,如果你编译没有优化)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-14
  • 2017-11-15
  • 1970-01-01
  • 1970-01-01
  • 2021-12-27
  • 1970-01-01
相关资源
最近更新 更多