2013/05/28

オブジェクト指向言語とHaskellの対応関係について

どうも,Haskellerかつ圏論愛好家の卵です.
すごいH本をひと通り読み終えて次はReal World Haskellを読み始めています.

Haskellは関数型言語ながらオブジェクト指向と共通するものを感じたので,その比較・対応関係をまとめました.

HaskellJava
クラス・メソッド定義データ型(ここではレコード)
data Human = Human{
  name::String,
  age::Int,
  sex::Sex
}

関数
sayHello :: Human->String
sayHello h = "my name is "++(name h)
クラス
class Human{
  string name;
  int age;
  Sex sex
  Human(nam,ag,se){
    name=nam;
    age=ag;
    sex=se
  }
  //メソッド
  sayHello(){
    return "my name is"+name;
  }
}
列挙型データ型
data Sex = Male | Female
列挙型
enum Sex { Male, Female }
インスタンス・メソッド呼び出しデータ
let uhyosan = Human{name="uhyo",age=18,sex=Male}

関数適用
sayHello uhyosan
インスタンス
Human uhyosan = new Human("uhyo",18, Male);

メソッド呼び出し
uhyosan.sayHello();
クラスの性質型クラス定義
class Runner a where
  run :: a->Int
  run' _ = 0 --既定の実装も書ける

型のインスタンス化
instance Runner Human where
  run _ = 1
インターフェイス定義
interface Runner{
  int run();
}

クラスの実装
class Human implements Runner{
  int run(){
    return 1;
  }
}
性質の継承型クラスの継承
class (Runner a, RoadRacer a, Swimmer a) => Triathlete a where
  triathlon :: a->Int
インターフェイスの継承
interface Triathlete extends Runner, RoadRacer, Swimmer{
  int triathlon(){
    return 2;
  }
}
抽象データ型抽象データ型
(LeafとNodeがモジュールの外から見えず,別の関数で生成する場合)
data Tree a=Leaf|Node a a
makeTree :: [a] -> Tree a
makeTree = ~

データ生成
let tree = makeTree [1,2,3]
ファクトリパターン
(コンストラクタが隠されファクトリが見える場合)
class Tree{
  private Tree(){}
  public static make(){
    return new Tree()
  }
}
インスタンス生成
Tree t = Tree.make();
(抽象クラス)(抽象データ型の"抽象"は,その型のデータを持てないという意味ではない)抽象クラス
abstract class Shape{
  abstract void draw();
}
(クラスの継承)(型間の継承はない)
(抽象クラスとそれを継承するクラスのようにも見える例)
data Shape = Circle Int Int Int | Rectangle Int Int Int Int
クラスの継承
class Circle extends Shape{
  void draw(){~};
}
class Circle extends Shape{
  void draw(){~};
}
多相データデータ型の引数
data MyList a = MyNil | Cons a (MyList a)

--MyList Human型 …Humanに固定
Cons uhyosan MyNil

--Num a=>MyList a型 …多相性を残している
Cons 1 (Cons 2 (Cons 3 MyNil))

--DoubleもIntもNumのインスタンスだが
--別のRunnerとは交換不可
Cons (1::Double) (Cons (2::Int) MyNil)

ジェネリクス
class MyList<T>{
  T data[10];
  void set(T t){
    data[0]=t;
  }
}

//Humanに固定
MyList<Human> ml = new MyList<Human>();
ml2.set(uhyosan);

//多相性を残している
MyList<Runner> ml2 = new MyList<Runner>();
ml2.set(uhyosan);

//別のRunnerと交換可能
class Robot implements Runner{int run(){return 100;}}
ml2.set(new Robot())
Haskellの型クラスは,オブジェクト指向言語でいう「既定の実装が書けるinterface」または「多重継承の出来るabstract class」と言えると思います.多くの単一継承の言語経験者にとっては「型クラスとはインターフェイスである」という表現がしっくり来るのではないでしょうか.