GHCの生成するコードを理解しようという話
と、見せかけて、ただ単にこれを読んだ小学生の感想文なので、元の論文が読める人には必要無い
GHCは中では "元 -> Core言語 -> Stg言語 -> なんか -> なんか " という構造になっていることは、どっかで読んだことあるかと思う
Core言語、STG言語は、それぞれ、言語になってて、Haskell言語はそれに変換されたあと、最適化されたりして、Cコードになる。
簡単に説明しておくと、Core言語が、型クラスとか、ややこしいCase式とかを取り除いたもの。STG言語が…(ただいま調査中あとで書く)
Core言語というのは、Haskell言語からややこしいSyntax Sugarを取り除いたものだと考えればよいと思う。GHCの中では、"Haskell言語 → Core言語" の変換の名前が"Desugar"になってるとか。(compiler/deSugar/Desugar.lhs:deSugarExpr)。ちなみに、HsExprがHaskellの式で、LHsExprが場所付き式。 CoreExprがCore言語の式(という解釈であってるはず)
例えば、↓こんなコードがあったとしたら、
c:: Eq a=> [a]->a->Int c x k = case x of [] -> 3 (xs:_) | k == xs -> 4 | otherwise -> 9
Core言語には、Boolによる条件判断、if式というのが存在していないので、ガードの部分は表現できない。 こういうのは全部、Case式に変換される
-ddump-simplオプション付きでコンパイルすると、途中のCore言語が見れるので、それで上のがどう変換されたか確認すると、
[GlobalId] [Arity 3 NoCafRefs] Nanika.c = \ (@ a_ajB) ($dEq_ajH :: {GHC.Base.Eq a_ajB}) (x_aj8 :: [a_ajB]) (k_aj9 :: a_ajB) -> case x_aj8 of wild_B1 { [] -> GHC.Base.I# 3; : xs_ajc ds_dpC -> case $dEq_ajH of tpl_Xh { GHC.Base.:DEq tpl1_B2 tpl2_B3 -> case tpl1_B2 k_aj9 xs_ajc of wild1_Xs { -- ここらへん -- GHC.Base.False -> GHC.Base.I# 9; GHC.Base.True -> GHC.Base.I# 4 } } }
こんな感じ。ガードがcase式になっとる。
…と、思ったけど、それ以前にCore言語が読めないと思った。
まず、最初の GlobalId…ちょっとわからん。
Arity…引数の数? NoCafRefs 外の変数を参照してるかどうか?
んで、次。@で始まってるのが、多相型の。んで、引数が並んで "->"で関数。
まあそういうのはいいか。とにかく、Core言語というのは、ほんと原始的な関数言語という理解でよいと思う。(compiler/coreSyn/CoreSyn.lhsらへん参考)
↓こういうのを-ddump-simplしてみると良いと思う
d::Int->Int->Int d 3 _ = 4 d _ _ = 9
ちなみに、GHCの中間表現を見るときは、数字リテラルに気を付けたほうがいい。 数字リえテラルは Num の値になって、なんか Int とは違う動きになるので、Intを明示するようにしましょう。
add x = 3+ x addI x = (3::Int)+ (x::Int)
Nanika.add = \ (@ t_apf) ($dNum_apk :: {GHC.Num.Num t_apf}) -> let { lit_apg :: t_apf [] lit_apg = case $dNum_apk of tpl_Xp { GHC.Num.:DNum tpl1_B2 tpl2_B3 tpl3_B4 tpl4_B5 tpl5_B6 tpl6_B7 tpl7_B8 tpl8_B9 tpl9_Ba -> tpl9_Ba (GHC.Num.S# 3) } } in \ (x_ajz :: t_apf) -> case $dNum_apk of tpl_Xn { GHC.Num.:DNum tpl1_B2 tpl2_B3 tpl3_B4 tpl4_B5 tpl5_B6 tpl6_B7 tpl7_B8 tpl8_B9 tpl9_Ba -> tpl3_B4 lit_apg x_ajz } Nanika.addI = \ (x_ajB :: GHC.Base.Int) -> case GHC.Num.$f6 of tpl_XC { GHC.Num.:DNum tpl1_B2 tpl2_B3 tpl3_B4 tpl4_B5 tpl5_B6 tpl6_B7 tpl7_B8 tpl8_B9 tpl9_Ba -> tpl3_B4 (GHC.Base.I# 3) x_ajB }
こんなに違う!