Defaulting がひどいのを直した結果 showsPrec など実装できるかためしてみたところ、 型推論の問題は起こらなかった(これは期待した通り)が、ランタイムで以下のようなエラー:
javac -J-Duser.language=en -cp "../../brt/src$s$d" $target g2/Prelude.java:3536: error: cannot find symbol Expr t5 = Prelude.mk_91__93__37_I_46_showsPrec_46_DARG0(); ^ symbol: method mk_91__93__37_I_46_showsPrec_46_DARG0() location: class Prelude g2/Prelude.java:3659: error: cannot find symbol Expr t5 = Prelude.mk_40__44__41__37_I_46_showsPrec_46_DARG0(); ^ symbol: method mk_40__44__41__37_I_46_showsPrec_46_DARG0() location: class Prelude g2/Prelude.java:3661: error: cannot find symbol Expr t6 = Prelude.mk_40__44__41__37_I_46_showsPrec_46_DARG1(); ^ symbol: method mk_40__44__41__37_I_46_showsPrec_46_DARG1() location: class Prelude g2/Prelude.java:4093: error: cannot find symbol Expr t10 = Prelude.mk_91__93__37_I_46_showList_46_DARG0(); ^ symbol: method mk_91__93__37_I_46_showList_46_DARG0() location: class Prelude g2/Prelude.java:4106: error: cannot find symbol Expr t22 = Prelude.mk_91__93__37_I_46_showList_46_DARG0(); ^ symbol: method mk_91__93__37_I_46_showList_46_DARG0() location: class Prelude g2/Prelude.java:4283: error: cannot find symbol Expr t10 = Prelude.mk_40__44__41__37_I_46_showList_46_DARG0(); ^ symbol: method mk_40__44__41__37_I_46_showList_46_DARG0() location: class Prelude g2/Prelude.java:4285: error: cannot find symbol Expr t11 = Prelude.mk_40__44__41__37_I_46_showList_46_DARG1(); ^ symbol: method mk_40__44__41__37_I_46_showList_46_DARG1() location: class Prelude g2/Prelude.java:4298: error: cannot find symbol Expr t23 = Prelude.mk_40__44__41__37_I_46_showList_46_DARG0(); ^ symbol: method mk_40__44__41__37_I_46_showList_46_DARG0() location: class Prelude g2/Prelude.java:4300: error: cannot find symbol Expr t24 = Prelude.mk_40__44__41__37_I_46_showList_46_DARG1(); ^ symbol: method mk_40__44__41__37_I_46_showList_46_DARG1() location: class Prelude 9 errors
例えば Prelude.[]%I.showsPrec は、自分が受け取った辞書を CompositDict にして Prelude.show に渡す。該当部の Core は以下のようになっている:
(Prelude.[]%I.showsPrec :: ([Prelude.Show t267] :=> (Prelude.Int -> ([t267] -> ([Prelude.Char] -> [Prelude.Char]))))) = \(Prelude.[]%I.showsPrec.DARG0 :: Ä) -> \(_Prelude.[]%I.showsPrec.U1 :: ([Prelude.Show t264] :=> Prelude.Int)) (_Prelude.[]%I.showsPrec.U2 :: ([Prelude.Show t264] :=> [t264])) (_Prelude.[]%I.showsPrec.U3 :: ([Prelude.Show t264] :=> [Prelude.Char])) -> (((Prelude.++ :: ([t265] -> ([t265] -> [t265]))) (((Prelude.show :: ([Prelude.Show t266] :=> (t266 -> [Prelude.Char]))) (CompositDict ${Prelude.[] Prelude.Show} [(Prelude.[]%I.showsPrec.DARG0 :: Å)])) (_Prelude.[]%I.showsPrec.U2 :: ([Prelude.Show t264] :=> [t264])))) (_Prelude.[]%I.showsPrec.U3 :: ([Prelude.Show t264] :=> [Prelude.Char])))
この辞書から変数として渡された辞書を取り出すところがまずい:
public static class LAM310 implements LambdaForm { public int arity(){ return 3; } public Expr call(AtomExpr[] args){ Expr t0 = Prelude.mk_43__43_(); Expr t1 = Prelude.mkshow(); Expr t2 = (Expr) new AtomExpr(new Dict(new Dict_36_Prelude_46__91__93__64_Prelude_46_Show())); AtomExpr t3 = (AtomExpr) t2; AtomExpr[] t4 = new AtomExpr[1]; Expr t5 = Prelude.mk_91__93__37_I_46_showsPrec_46_DARG0(); t4[0] = (AtomExpr) t5; Expr t6 = (Expr) new AtomExpr(new CompositDict(t3, t4)); Expr t7 = RTLib.mkApp(t1, t6); Expr t8 = args[1]; Expr t9 = RTLib.mkApp(t7, t8); Expr t10 = RTLib.mkApp(t0, t9); Expr t11 = args[2]; Expr t12 = RTLib.mkApp(t10, t11); return t12; } } public static class LAM309 implements LambdaForm { public int arity(){ return 1; } public Expr call(AtomExpr[] args){ Expr t0 = RTLib.mkFun(new LAM310()); return t0; } } public static Expr mk_91__93__37_I_46_showsPrec(){ Expr t0 = RTLib.mkFun(new LAM309()); return t0; }
Prelude.mk_91__93__37_I_46_showsPrec_46_DARG0() のようにスタティックな辞書生成関数(そんなものは存在しない)を呼び出すのでなく、 args を参照するようなコードを出力すべき。
おそらく、CompositDict に引数がわたされるようなケースはダメなので、 それを再現する小さなテストケースをつくって調査したい。(lib/Prelude でやるのはしんどい)
CodeGen で、変数参照に対応するコードを出力している部分に trace を 仕込んで、なぜ args[0] へ変換されていないのか調べてみた。
genAtomExpr :: Expr -> GEN Int genAtomExpr (AtomExpr (VarAtom (TermVar n))) | n == "Prim.:" = emit "RTLib.cons" | n == "Prim.[]" = emit "RTLib.nil" | otherwise = do st <- get let h = env st v = fromMaybe (refTopLevel n) (Map.lookup n h) trace (show (n, h)) $ return () emit v where emit s = do i <- nexti appendCode $ "Expr t" ++ show i ++ " = " ++ s ++ ";" return i
その該当部分が以下:
("Prelude.[]%I.showsPrec.DARG0",fromList [("_Prelude.[]%I.showsPrec.U1","args[0]"),("_Prelude.[]%I.showsPrec.U2","args[1]"),("_Prelude.[]%I.showsPrec.U3","args[2]")])
うーん。\${darg0 u1 u2 u3 -> body} という4引数の1つの lambda ではなく、\${darg0 u1 u2 u3 -> (\u1' u2' u3' -> body) u1 u2 u3} みたいな変換になってんのかな。
STG.fv が、CompositDict 中の変数をとらえていないのが問題のようにも思える。
⇒ STG.fv を以下のように修正:
-fv (AtomExpr (VarAtom (CompositDict _ _))) = [] +fv (AtomExpr (VarAtom (CompositDict e es))) = nub (fv e ++ concatMap fv es)
これで、治った。