継承
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を経由することになってしまった。
なにか間違ったのだろうか。