# 041: tqd.hs で context reduction, Show [a] 問題 [↑up](bunny_notes) - issued: 2020-04-18 - 分類: A サンプルコードが fail - status: Closed (2020-05-03) ## 概要 Show クラスの扱いまわりをまともにしていく過程(参照:[017](bissue017))で、 sample116, 136 が動かなくなってしまった。instance (Show a) => Show [a] にきちんと対応できていないため。 そこで、sample116, 136 はともに testcases に格下げ、tqd.hs, tqd2.hs とした。 (両者の違いは、型シグネチャを明示しているか、していないか) 一方、tqd の show 以外の部分は動いているため、Show [a] に依存しないように 書きかえたものを test/sample/sample150 として追加した。 ## 調査ログ ### 2020-04-23 本件と 042 は同様の問題であるため、両方みながら対処することにしたい。 対処には、コンパイラの修正と lib/Prelude.hs への記述追加の両方が必要だが、 lib/Prelude.hs をいきなり変えると多くの test が fail するので、 そうせずに調査をすすめるためのサンプルケースを作成: - testcases/myshowlist.hs - testcases/myshowpair.hs - testcases/myshowtriple.hs Rename に trace を追加して確認したところ、instance メソッド定義に付加している 型シグネチャが不適切であることが原因と思われる。 myshowlist の場合: $$
{ TypeSigDecl [Name {origName = "Main.[]%I.myshow", namePos = (2,3), isConName = False}] (Nothing,FunTy (ListTy (Tyvar (Name {origName = "a", namePos = (10,32), isConName = False}))) (ListTy (Tycon (Name {origName = "Char", namePos = (2,19), isConName = True})))) $$} 本来、${Main.[]%I.myshow :: [Show a] :=> [a] -> [Char]} であるべきところ、 $ {[] :=> [a] -> [Char]} になっている。(Pred が空なのがおかしい) myshowpair, myshowtriple は Rename で未実装のパターンにあたってしまうので、 そこまでたどり着いていない。 インスタンスメソッドの型シグネチャを生成するときに、Pred を無条件で空にするのではなく、型に含まれる型変数が残った場合には、それに対応する Pred も残さなければならないようだ。 ### 2020-04-24 型シグネチャの生成。$ {renInstDecl (A.InstDecl ctx t ds)} の ctx をそのまま sigvar につけるように変更。 この部分は、ひとまずこれでいいはずなのだが、 myshowlist.hs はエラー。これは、Int, Char の instance 宣言において、 Int, Char が Main.Int, Main.Char と解釈されてしまったせい。 myshowlist2.hs のように修飾すると、別のエラーになった。 なので、instance (Show a) => Show [a] where ... の定義は直接 lib/Prelude.hs い追加して調査続行。こうなった: $$ { $ ./tcheck testcases/showils.hs # 1. test-compile source file: testcases/showils.hs dst dir: /showils doCompile ... done. implicitPrelude ... done. doCompile ... bunnyc: Error: dictionary not found: Prelude.print, (Tyvar "t0" Star,"Prelude.Show",TAp (TCon (Tycon "Prelude.[]" (Kfun Star Star))) (TVar (Tyvar "t7" Star)),[TVar (Tyvar "t6" Star),TVar (Tyvar "t4" Star),TVar (Tyvar "t2" Star)]) CallStack (from HasCallStack): error, called at src/DictPass.hs:232:43 in main:DictPass $$} $${ $ ./tcheck testcases/printstring.hs # 1. test-compile source file: testcases/printstring.hs dst dir: /printstring doCompile ... done. implicitPrelude ... done. doCompile ... bunnyc: Error: dictionary not found: Prelude.print, (Tyvar "t0" Star,"Prelude.Show",TAp (TCon (Tycon "Prelude.[]" (Kfun Star Star))) (TCon (Tycon "Prelude.Char" Star)),[]) CallStack (from HasCallStack): error, called at src/DictPass.hs:232:43 in main:DictPass $$} ここでは、[${Prelude.[] Prelude.Show}, ${Prelude.Int Prelude.Show}] の ように、辞書のリストを渡すのが正しいように思われる。 これを、((show ${Prelude.[] Prelude.Show}) ${Prelude.Int Prelude.Show}) のように処理すれば、期待されたような動作になるのではないか。 - Core の辞書型に、辞書のリストに対応するものを追加する - DictPass (findApplyDict) を、上述のような辞書のリストを渡すように改造する - Runtime で、辞書のリストは、複数回の辞書適用を実装するように改造する これでうまくいくかどうかは、リストだけでなく、tuple, triple のケースも考慮したほうがよさそう。辞書のリストのリストの方がいいのかもしれない。 たとえば、Main.(,)%I.show は辞書を2つ引数にとるので、show に渡すのは、 [[${Prelude.(,) Prelude.Show}], [${Prelude.Int Prelude.Show}, ${Prelude.Int Prelude.Show}]] のようにすべきなのではないか。 ### 2020-04-26 複合辞書は、[[Dictionary]] ではなく、第一要素は常に1つ、第二要素がリスト(第三以降はないはず)でいいと思われるため、${CompositDict Expr [Expr]} のような形にした。 必要と思われる修正は以下: 1. Core に CompositDict 定義を追加 2. PPCore を CompositDict に対応させる 3. DictPass で、[a] に出会ったときに CompositDict を生成するようにする 4. STG にも CompositDict を追加、trSTG をこれに対応させる 5. CodeGen の対応 4 項まで実施したところで、CodeGen 未対応による以下のエラーが出た: $$ { bunnyc: Non-exhaustive pattern in genAtomExpr: AtomExpr (VarAtom (CompositDict (AtomExpr (VarAtom (DictVar "Prelude.[]" "Prelude.Show"))) [AtomExpr (VarAtom (TermVar "Prelude.[]%I.show.DARG0"))])) $$} CodeGen にて、genAtomExpr は対処、最後は、OLshow にて CompositDict をハンドリングできるようにする。 現状の OLshow: $${ public static class OLshow implements LambdaForm { public int arity(){ return 1; } public Expr call(AtomExpr[] args){ Dict_36_Prelude_46_Show d = (Dict_36_Prelude_46_Show) RTLib.extrDict(args[0]); Expr t0 = d.mkshow(); return t0; } } $$} CodeGen を改造し、次のような OLshow を吐くようにした: $${ public static class OLshow implements LambdaForm { public int arity(){ return 1; } public Expr call(AtomExpr[] args){ Expr t0; if (args[0].a instanceof CompositDict){ Dict_36_Prelude_46_Show d = (Dict_36_Prelude_46_Show) RTLib.extrDict(((CompositDict) args[0].a).d); AtomExpr[] ds = ((CompositDict) args[0].a).ds; Expr t1 = d.mkshow(); t0 = RTLib.mkApp(t1, ds); } else { Dict_36_Prelude_46_Show d = (Dict_36_Prelude_46_Show) RTLib.extrDict(args[0]); t0 = d.mkshow(); } return t0; } } public static Expr mkshow(){ Expr t0 = RTLib.mkFun(new OLshow()); return t0; } $$} これで(いまのところ)期待どおりの動作をするようになった。 ただ、tqd.hs や printstring.hs では次のようなエラーがでる。こころあたりはあり。 $${ $ ./tcheck testcases/printstring.hs # 1. test-compile source file: testcases/printstring.hs dst dir: /printstring doCompile ... done. implicitPrelude ... done. doCompile ... bunnyc: src/DictPass.hs:(220,18)-(227,65): Non-exhaustive patterns in case $$} ⇒ かなりその場限りの書き方だが対処。printstring.hs、tqd.hs, tqd2.hs ともにエラーはしなくなった。 つぎに、lib/Prelude.hs における Show [a] の定義をまともにしよう。 ひとまず、[Char] 以外に対応、showils.hs は通した ⇒ sample163.hs shoswPrec や showList をもちいたトリックは、まだ理解できていないのと、 そのままやってみたらエラーしたので要継続。 ### 2020-05-03 [045](bissue045) の 2020-05-01 の対処、および、[052](bissue052) により、 Show [a] 定義を Haskell 2010 report 方式に書き直すことができるようになった。 まだ、いくらか問題を回避しつつだが、printstring.hs、tqd.hs, tqd2.hs が通るようになったので、本件はクローズとする。 保留、または、回避中の問題: - Show Char において、showLitChar などエスケープ未対応 ⇒ [053](bissue053) - showl "" など、String Literal パターンがエラーする ⇒ [054](bissue054) - Int, Integer ともに showList のデフォルト実装ではエラーするため、各々記述 ⇒ [055](bissue055)