Monads的Desugaring do-notation

Ste*_*ehl 24 monads haskell do-notation

当我正在学习Haskell时,我意识到do符号只是合成糖:

a = do x <- [3..4]
       [1..2]
       return (x, 42)
Run Code Online (Sandbox Code Playgroud)

翻译成

a = [3..4] >>= (\x -> [1..2] >>= (\_ -> return (x, 42)))
Run Code Online (Sandbox Code Playgroud)

我意识到我可能会使用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)
Run Code Online (Sandbox Code Playgroud)

这是Undo插件的源代码.

ham*_*mar 20

您可以询问GHC的desugarer的输出,但是这也会减少许多其他语法.

首先,我们将您的代码放在一个模块中Foo.hs:

module Foo where

a = do x <- [3..4]
       [1..2]
       return (x, 42)
Run Code Online (Sandbox Code Playgroud)

接下来,我们将要求GHC编译它并在desugaring阶段后输出结果:

$ ghc -c Foo.hs -ddump-ds
Run Code Online (Sandbox Code Playgroud)

输出可能看起来相当混乱,因为它是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)))
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

  • @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`也提供了一个desugaring). (8认同)
  • 只是为了好玩,[哈斯克尔98的快速而肮脏的记事本](https://gist.github.com/1341505). (5认同)
  • 这引出了一个问题......那里有什么东西可以自动删除_xyz后缀,输入应用程序,调用GHC.Integer.smallInteger并再次运算符中缀? (4认同)
  • 问题是,当你编写代码时,你不再需要它了. (4认同)