lib/Prelude.hs の Ord クラス定義を完成させる。
現状では、以下のように一部をコメントアウトしないとエラーする。 (以下、min の型宣言を忘れているような…)
class (Eq a) => Ord a where (<) :: a -> a -> Bool (<=) :: a -> a -> Bool (>=) :: a -> a -> Bool (>) :: a -> a -> Bool {- compare :: a -> a -> Ordering max :: a -> a -> a -- Minimal complete definition: -- (<=) or compare compare x y | x == y = EQ | x <= y = LT | otherwise = GT x <= y = compare x y /= GT x < y = compare x y == LT x >= y = compare x y /= LT x > y = compare x y == GT max x y | x <= y = y | otherwise = x mix x y | x <= y = x | otherwise = y -}
そこで、未実装機能だけを確認する mycompare.hs をつくって、 まずは、そちらで調査を継続する。
mycompare.hs では、以下の GuardedRhs をリネームする部分が未実装なのでコケてる:
GuardedRhs [([ExpStmt (InfixExp (VarExp (Name {origName = "x", namePos = (1,17), isConName = False})) (Name {origName = "==", namePos = (1,19), isConName = False}) (VarExp (Name {origName = "y", namePos = (1,22), isConName = False})))],VarExp (Name {origName = "EQ", namePos = (1,29), isConName = True})),([ExpStmt (InfixExp (VarExp (Name {origName = "x", namePos = (2,17), isConName = False})) (Name {origName = "<=", namePos = (2,19), isConName = False}) (VarExp (Name {origName = "y", namePos = (2,22), isConName = False})))],VarExp (Name {origName = "LT", namePos = (2,29), isConName = True})),([ExpStmt (VarExp (Name {origName = "otherwise", namePos = (3,17), isConName = False}))],VarExp (Name {origName = "GT", namePos = (3,29), isConName = True}))] [])
mycompare.hs シリーズのうち、まず、mycompare4.hs を 009 で扱うことにする。
⇒ 009 の対処で nodup0.hs は通るようになったのだけど、mycompare4.hs はランタイムにて abend! するようになってしまったので、このテストケースはこちらに戻します。
jout/mycompare4 を jout/mycompare4e にコピーし、まずは、手で書き直して実験してみる。 Eq, Ord, Num などは interface にし、各辞書の実態は、たとえば Int の Ord 辞書は、Eq と Ord の2つのインターフェイスを implement する。
一部の書き換えを以下に例示する。
Dict_36_Prelude_46_Eq.java:
import jp.ne.sakura.uhideyuki.brt.brtsyn.*; import jp.ne.sakura.uhideyuki.brt.runtime.*; interface Dict_36_Prelude_46_Eq { abstract public Expr mk_61__61_(); abstract public Expr mk_47__61_(); }
Dict_36_Prelude_46_Ord.java:
import jp.ne.sakura.uhideyuki.brt.brtsyn.*; import jp.ne.sakura.uhideyuki.brt.runtime.*; interface Dict_36_Prelude_46_Ord { abstract public Expr mk_60_(); abstract public Expr mk_60__61_(); abstract public Expr mk_62__61_(); abstract public Expr mk_62_(); }
Dict_36_Prelude_46_Integer_64_Prelude_46_Eq.java:
import jp.ne.sakura.uhideyuki.brt.brtsyn.*; import jp.ne.sakura.uhideyuki.brt.runtime.*; public class Dict_36_Prelude_46_Integer_64_Prelude_46_Eq extends Dictionary implements Dict_36_Prelude_46_Eq { public Expr mk_61__61_(){ return Prelude.mkI_37_Integer_46__61__61_(); } public Expr mk_47__61_(){ return Prelude.mkI_37_Integer_46__47__61_(); } }
Dict_36_Prelude_46_Integer_64_Prelude_46_Ord.java:
import jp.ne.sakura.uhideyuki.brt.brtsyn.*; import jp.ne.sakura.uhideyuki.brt.runtime.*; public class Dict_36_Prelude_46_Integer_64_Prelude_46_Ord extends Dictionary implements Dict_36_Prelude_46_Eq, Dict_36_Prelude_46_Ord { private Dict_36_Prelude_46_Integer_64_Prelude_46_Eq dictEq; public Dict_36_Prelude_46_Integer_64_Prelude_46_Ord(){ this.dictEq = new Dict_36_Prelude_46_Integer_64_Prelude_46_Eq(); } /* methods of Eq */ public Expr mk_61__61_(){ return this.dictEq.mk_61__61_(); } public Expr mk_47__61_(){ return this.dictEq.mk_61__61_(); } /* methods of Ord */ public Expr mk_60_(){ return Prelude.mkI_37_Integer_46__60_(); } public Expr mk_60__61_(){ return Prelude.mkI_37_Integer_46__60__61_(); } public Expr mk_62__61_(){ return Prelude.mkI_37_Integer_46__62__61_(); } public Expr mk_62_(){ return Prelude.mkI_37_Integer_46__62_(); } }
このようにしておけば、あらゆる辞書は Dictionary 型変数に格納することができ、 たとえば、Integer Ord 辞書は、Dict_36_Prelude_46_Ord にも Dict_36_Prelude_46_Eq にもキャストできる。
…が、このようにしても、また、別のランタイムエラーが生じてしまった。 今度は、Eq 辞書の実態を Ord にキャストしようとして abend しており、これは、確かに変。
--ddump-core で確認してみると、mycompare の型は [Prelude.Eq t15,Prelude.Ord t15] :=> (t15 -> (t15 -> Prelude.Ordering))) となっていて、辞書は Eq, Ord の順でわたされることを期待しているのに、 呼び出し側で逆順にわたしてしまっている。
…が、そもそも、mycompre の型は Eq a, Ord a => a -> a -> Ordering ではなく、Ord a => a -> a -> Ordering ではないのか。
というわけで、問題は3つあることになる。
述語リストが単純になっていなかったのは、simplify が呼ばれてないとかではなく、 ClassEnv に親子関係が正しく登録されていなかったため。 Rename.renClassDecls を修正して、Class 定義から super class 情報を読み取って、 ClassEnv に追加するようにした。
ただし、現状の実装はかなり特殊なので、要改善(026)。
これにて、mycompare の型はただしく Forall [Star] ([Prelude.Ord a] :=> (a -> (a -> Prelude.Ordering))) となった。
次に、DictPass における lookupDictArgs をこれに対応。 そのため、Sement から ClassEnv 情報を DictPass まで引き回して利用。 ClassEnv には defaults も含まれるため、DictPass で defaulting しなければいけなくなった場合に使えそう。
これは、すでに手で書いてためしていたような出力になるよう、CodeGen を書き換えて完了。
mycompare4.hs は通ったので sample143 とした。
これを試すために、↓のような関数を用いればいいかなと思ったのですが、
Prelude> let f x y a b = (x + y) == (a * b) Prelude> :t f f :: (Eq a, Num a) => a -> a -> a -> a -> Bool
Haskell 2010 では、Eq が Num のスーパークラスなので (参考)、 述語はひとつに単純化されてしまう。
そこで、Num と Monad が述語に現れるようなプログラムを用意した(028)。
008が解決したので、mycompare*.hs 系も通るようになった。通ったものは test/sample 入り。
mycompare2.hs は Prim.() の扱いに難があってエラー、 これを回避した mycompare2x.hs は通った。
これをうけて、lib/Prelude.hs を修正、Ord クラスの定義を完全にした。 そのテストのためにつくった ordtest.hs では単項マイナスの未実装が露見。 単項マイナスをつかわない ordtest2.hs は通った (sample148)。
mycompare2.hs, ordtest.hs の件はそれぞれ独立のイシューをたてる。
本件は、これでクローズする。