27

doHaskellを学んでいると、表記法は単なる糖衣構文であることに気づきます。

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

に翻訳

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

おそらくdo表記を使用することは理解していますが、翻訳で何が起こっているのかを理解したいと思います。純粋に教育的な理由で、ghc / ghciがdo表記で書かれたかなり複雑なモナドに対応するバインドステートメントを提供する方法はありますか?

編集。#haskellのlambdabotがこれを実行できることがわかりました:

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

Undoプラグインのソースコードは次のとおりです。

4

1 に答える 1

22

GHCの脱糖剤の出力を要求できますが、これにより他の多くの構文も脱糖されます。

まず、コードをモジュールに入れますFoo.hs

module Foo where

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

次に、GHCにコンパイルして、脱糖段階の後に結果を出力するように依頼します。

$ ghc -c Foo.hs -ddump-ds

GHCの中間言語として使用されるCoreと呼ばれるHaskellのバリアントであるため、出力はかなり乱雑に見える場合があります。ただし、慣れれば読むのはそれほど難しくありません。他のいくつかの定義の真ん中に、私たちはあなたのものを見つけます:

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)
于 2011-11-05T11:25:44.453 に答える