Haskellで(むりやり)やるオブジェクト指向

Haskellにもclassがあるのだから、C++とかで見るオブジェクト指向もできるでしょうということで、無理やりやってみました...笑って見過ごしてやってください。一応、クラスの継承関係もできるので、ここでは

Object -> Animal -> (Dog, Cat)

という構図になっています。Objectクラスではメンバー関数呼び出し演算子.>を定義して、Animalでは動物特有なメソッドを定義しています。

こうすることで、
d = Dog "Pochi"
d.>name ==> "Pochi"
d.>(soundN 3) ==> "BowowBowowBowow"
みたいなことができるようになります…

module Main where

class Object a where
	(.>) :: a -> (a -> b) -> b
	(.>) obj mthd = mthd obj

class (Object a) => Animal a where
	name :: a -> String
	sound :: a -> String
	soundN :: Int -> a -> String
	soundN i a = concat $ replicate i (a.>sound)
instance (Animal a) => Object a
	
newtype Dog = Dog String
instance Animal Dog where
	name (Dog nm) = nm
	sound _ = "Bowow"

newtype Cat = Cat String	
instance Animal Cat where
	name (Cat nm) = nm
	sound _ = "Meow"

d = Dog "Pochi"
c = Cat "Tama"

namesound :: (Animal a) => a -> (a -> String) -> String
namesound an sn = an.>name ++ " " ++ (an.>sn)

main = do
	print $ namesound d sound
	print $ namesound c (soundN 10)

強いて、学んだことを挙げるとすれば、どうやら、Haskellではクラスとタイプの宣言が別々で、データメンバーはタイプの中にしか表現できないので、メンバーの継承はできなさそげということです...
C++だったら:

class Animal
{
protected:
	String m_Name;
};

class Dog : public Animal {};

なんてやると、Dogにはm_nameメンバが勝手についてくるのですが、これはできないっぽい?

ではでは。