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)
これで、治った。