当我正在学习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。
答案 0 :(得分:18)
你可以要求GHC的desugarer的输出,但是这也会减少很多其他的语法。
首先,我们将您的代码放在模块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)