継承

Haskellでも多段の継承関係を持ったものを記述すること出来るよね…?
というか、なんというか、Preludeの数関係のクラスがそうなっている。
実装を持ったものの多重継承も出来るような気がする。

#include 
#include 

using namespace std;

class A{
public:
  virtual string foo()=0;
};

class B : public A{
public:
  virtual string bar(){
    return string("**")+foo()+"**";
  }
};

class C : public A{
public:
  virtual string baz()=0;
};

class D : public B,C{
public:
  virtual string hoge(){
    return bar()+","+baz();
  }
};

string itoa(int n){
  static char buf[12];
  sprintf(buf,"%d",n);
  return string(buf);
}

class Test : public D{
public:
  Test(int n){ this->n=n; }

  string foo(){
    return itoa(n);
  }
  string baz(){
    return itoa(itoa(n).length());
  }

private:
  int n;
};

int main(){
  Test t(777);D *d=&t;
  cout<hoge()<

なんとなく適当に書いてみたコード。
これが

class A a where
  foo :: a -> String

class (A a) => B a where
  bar :: a -> String
  bar = ("**"++) . (++"**") . foo

class (A a) => C a where
  baz :: a -> String

class (B a,C a) => D a where
  hoge :: a -> String
  hoge a = bar a ++ "," ++ baz a

data Test = Test Int

instance A Test where foo (Test n) = show n
instance B Test
instance C Test where baz (Test n) = show $ length $ show n
instance D Test

main = putStrLn $ hoge $ Test 777

こんな感じになったのだが、
一つ気になるのがinstanceのところだろうか。
継承しているすべてのクラスについてばらばらに
インスタンス化しないといけないのがやや煩雑。
ただし、C++版のほうでもおのおののメソッドを分かった上でないと
かけないので、このことが本質的な問題になることは無いのかもしれない。


で、このように書くのが継承関係を記述するスタンダードだと思うのだが、
WxHaskellではまた違った方法で記述されている。

Object
 |-Condition
 |-WxObject
    |-Clipbiard
    |-Closure
    |-Command
      ....
    |-GDIObject
       |-Bitmap
       |-Brush
       |-Font
       |-Palette
       |-Pen
       |-Region
    |-EvtHandler
       |-Window
          |-Control
          |-Dialog
            ...

WxHaskellのクラス階層(…クラスには成ってないけど)は
こんな感じのどこかで見たような階層構造になっているのだが、
これが、

type Object    a = Ptr a
type WxObject  a = Object    (CWxObject  a)
type GDIObject a = WxObject  (CGDIObject a)
type Bitmap    a = GDIObject (CBitmap    a)

例えばBitmapならこのように表現されている。
BitmapはGDIObjectであり、WxObjectでもあり、Objectでもあるということだ。
Bitmap a の型はぜんぶ展開すると

Bitmap a
=> GDIObject (CBitmap a)
=> WxObject  (CGDIObject (CBitmap a))
=> Object    (CWxObject (CGDIObjcet (CBitmap a)))
=> Ptr       (CWxObject (CGDIObjcet (CBitmap a)))

要するに上のtypeは、データ構造間に継承関係を定めている
ということになるのだろうか。
何か適当に書いてみた。

data CB c = CB String c
data CC c = CC Double c

instance Show (CB a) where show (CB s _) = "**"++s++"**"
instance Show (CC a) where show (CC d _) = show d

type A a = a
type B a = A (CB a)
type C a = A (CC a)

foo :: (Show a) => A a -> String
foo a = show a

createB :: String -> B ()
createB s = CB s ()
createC :: Double -> C ()
createC d = CC d ()

main = do
  putStrLn $ foo $ createB "hello"
  putStrLn $ foo $ createC 3.14159

むぐぐ、これまた何がしたいのかよく分からないことに。

A
 |-B
 |-C

BとCのオブジェクトはAを引数とする関数に渡すことが出来る。
が、しかし、結局そのようなことを可能にするために
classを経由することになってしまった。
なにか間違ったのだろうか。