GHC に -ddump-simpl オプションを渡すと、Core 形式(中間表現の関数型言語)を出力するというので、Performance/Accumulating parameterのコードに対して Core を出力しみた。
len
末尾再帰でない len のコードはこう。
len :: [a] -> Int len [] = 0 len (x:xs) = len xs + 1
これに対して、Core を出力させるとこう。明らかに末尾再帰には直されてない。
len_rfB = \ (@ a_afQ) (ds_dyA :: [a_afQ]) -> case ds_dyA of wild_B1 { [] -> GHC.Types.I# 0; : x_afH xs_afJ -> GHC.Num.+ @ GHC.Types.Int GHC.Num.$f6 (len_rfB @ a_afQ xs_afJ) (GHC.Types.I# 1) }
GHC に -O2 を渡して、Core を出力させるとこう。末尾再帰に直っているような気がする。
Main.$wlen = \ (@ a_afu) (w_sIa :: [a_afu]) -> case w_sIa of wild_B1 { [] -> 0; : x_afw xs_afy -> case Main.$wlen @ a_afu xs_afy of ww_sId { __DEFAULT -> GHC.Prim.+# ww_sId 1 } }
追記:case of の部分で $wlen を先に呼び、後で + しているので、末尾再帰にはなってないそうです。(shelarcy さんより)
len'
ついでに末尾再帰の len' に対してもやってみる。
len' :: [a] -> Int -> Int len' [] acc = acc len' (x:xs) acc = len' xs (1 + acc)
GHC に -O2 を渡さないとこうなる。
len'_rfF = \ (@ a_afY) (ds_dyR :: [a_afY]) (acc_afL :: GHC.Types.Int) -> case ds_dyR of wild_B1 { [] -> acc_afL; : x_afN xs_afP -> len'_rfF @ a_afY xs_afP (GHC.Num.+ @ GHC.Types.Int GHC.Num.$f6 (GHC.Types.I# 1) acc_afL)
GHC に -O2 を渡すとこうなる。
Main.$wlen' = \ (@ a_afH) (w_sIw :: [a_afH]) (ww_sIz :: GHC.Prim.Int#) -> case w_sIw of wild_B1 { [] -> ww_sIz; : x_afN xs_afP -> Main.$wlen' @ a_afH xs_afP (GHC.Prim.+# 1 ww_sIz) }
コメント&議論を求む!