# 023: lib/Prelude.hs の Ord クラス定義を完成させる [↑up](bunny_notes) - issued: 2020-04-13 - 分類: B 機能追加 - status: Closed (2020-04-15) ## 概要 lib/Prelude.hs の Ord クラス定義を完成させる。 ## 調査結果 ### 2020-04-13 現状では、以下のように一部をコメントアウトしないとエラーする。 (以下、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 

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](bissue009) で扱うことにする。

⇒ 009 の対処で nodup0.hs は通るようになったのだけど、mycompare4.hs はランタイムにて abend! するようになってしまったので、このテストケースはこちらに戻します。

### 2020-04-14
### 辞書の多重継承化

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つあることになる。

- Runtime における辞書の実装を変える(interface による多重継承)
- 推論された、各項の型における述語リストを最も単純な形にする (simplify が使えそう)
- 定義側と呼び出し側で辞書渡しの順序がくいちがっていた

### 推論された、各項の型における述語リストを最も単純な形にする (simplify が使えそう)

述語リストが単純になっていなかったのは、simplify が呼ばれてないとかではなく、
ClassEnv に親子関係が正しく登録されていなかったため。
Rename.renClassDecls を修正して、Class 定義から super class 情報を読み取って、
ClassEnv に追加するようにした。

ただし、現状の実装はかなり特殊なので、要改善([026](bissue026))。

これにて、mycompare の型はただしく
${Forall [Star] ([Prelude.Ord a] :=> (a -> (a -> Prelude.Ordering)))} となった。

次に、DictPass における lookupDictArgs をこれに対応。
そのため、Sement から ClassEnv 情報を DictPass まで引き回して利用。
ClassEnv には defaults も含まれるため、DictPass で defaulting しなければいけなくなった場合に使えそう。

###  Runtime における辞書の実装を変える(interface による多重継承)

これは、すでに手で書いてためしていたような出力になるよう、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 のスーパークラスなので ([参考](https://blog.miz-ar.info/2016/06/haskell-num-class/#Eq_Show))、
述語はひとつに単純化されてしまう。

そこで、Num と Monad が述語に現れるようなプログラムを用意した([028](bissue028))。

### 2020-04-15 

008が解決したので、mycompare*.hs 系も通るようになった。通ったものは test/sample 入り。

mycompare2.hs は Prim.() の扱いに難があってエラー、
これを回避した mycompare2x.hs は通った。

- mycompare.hs ok -> sample145
- mycompare2.hs NG 
- mycompare2x.hs ok -> sample146
- mycompre3.hs ok -> sample147

これをうけて、lib/Prelude.hs を修正、Ord クラスの定義を完全にした。
そのテストのためにつくった ordtest.hs では単項マイナスの未実装が露見。
単項マイナスをつかわない ordtest2.hs は通った (sample148)。

mycompare2.hs, ordtest.hs の件はそれぞれ独立のイシューをたてる。

本件は、これでクローズする。