# 079: Prelude にて、Show より前に Num のクラス宣言を書けるようにする [↑up](bunny_notes) - issued: 2020-05-17 - 分類: B 機能追加 - status: Closed (2021-01-28) ## 概要 現状では、Show クラスの宣言より前に Num の宣言を書くとエラーしてしまう。 コンパイラがトポロジカルソートすべきと思われる。 ## 調査ログ ## 2021-01-28 ### 念のため、トポロジカルソートで強連結成分(循環)が生じないかチェック もしかしたら、クラス定義についても循環をゆるす(関数は循環参照、相互再帰可能) んだったらどうしようと心配になって、しらべてみた: $$
{ class (B a) => A a where methodA :: a -> String methodY :: a -> String class (A a) => B a where methodB :: a -> Int methodX :: a -> Int instance A Int where methodA x = show x methodY x = show (methodX x) instance B Int where methodB x = length (methodA x) methodX x = x^2 main = print $ methodB (8::Int) $$} これは、GHC でもエラーになる: $${ $ runhaskell mutual_recursion.hs mutual_recursion.hs:1:1: error: • Superclass cycle for ‘A’ one of whose superclasses is ‘B’ one of whose superclasses is ‘A’ Use UndecidableSuperClasses to accept this • In the class declaration for ‘A’ | 1 | class (B a) => A a where | ^^^^^^^^^^^^^^^^^^^^^^^^... mutual_recursion.hs:5:1: error: • Superclass cycle for ‘B’ one of whose superclasses is ‘A’ one of whose superclasses is ‘B’ Use UndecidableSuperClasses to accept this • In the class declaration for ‘B’ | 5 | class (A a) => B a where | ^^^^^^^^^^^^^^^^^^^^^^^^... $$} ### lib/Prelude.hs 変更 では、トポロジカルソートを実装するまえに、テストを Red にしておく。 lib/Prelude.hs の Show を unzip 定義の後ろにもっていく。期待通りエラーする: $${ $ bin/bunny tcompile --xno-implicit-prelude lib/Prelude.hs /home/unno/prj/bunny/compiler/bin/bunnyc -d ./jout/Prelude --xno-implicit-prelude /home/unno/prj/bunny/compiler/bin/../lib/Prelude.hs bunnyc: addClass failed: ("Prelude.Num",ClassEnv {ceMap = fromList [("Prelude.Bounded",([],[])),("Prelude.Enum",([],[])),("Prelude.Eq",([],[])),("Prelude.Ord",(["Prelude.Eq"],[]))], defaults = [TCon (Tycon "Prelude.Integer" Star)]}) CallStack (from HasCallStack): error, called at src/Rename.hs:379:28 in main:Rename CallStack (from -prof): Rename.renClassDecls.clsadd.ce' (src/Rename.hs:(379,11)-(380,39)) Rename.renClassDecls.clsadd (src/Rename.hs:(374,5)-(384,53)) Rename.renClassDecls.\ (src/Rename.hs:(362,37)-(364,53)) Rename.renClassDecls (src/Rename.hs:(360,1)-(403,31)) Semant.renProg (src/Semant.hs:(21,1)-(52,11)) Main.doCompile.(...) (app/Main.hs:83:7-70) Main.doCompile (app/Main.hs:(77,1)-(114,33)) Main.main (app/Main.hs:(117,1)-(132,42)) tcompile: failed to compile lib/Prelide.hs $$} ### 対処 Rename モジュールの scanDecl で class 宣言をトポロジカルソートするようにした。 解決。