C++
Haskell
オブジェクト指向
Rust
関数型言語

C++ と Haskell と Rustの似てるとこ、違うとこ

関数型言語とオブジェクト指向が相反するものではないことを
感じ始めました。

C++ と Haskell と Rust で似てるところを挙げて
どこが異なっているかを示します。

間違っていたらご指摘お願いします。

列挙型

C++ Haskell Rust
enum data enum

C++ は値と結び付くけど Haskell, Rustは型と結びつく

Rust では Derive を使い規定した振る舞いを付加できる。
振る舞いはトレイトで規定される。

Haskell では Deriving を使い規定した振る舞いを付加できる。
振る舞いは型クラスで規定される。

構造体

C++ Haskell Rust
struct data struct

Rust では Derive を使い規定した振る舞いを付加できる。
振る舞いはトレイトで規定される。

Haskell では Deriving を使い規定した振る舞いを付加できる。
振る舞いは型クラスで規定される。

クラス

C++ Haskell Rust
classes

Rust, Haskellではモジュールによりメソッドをモジュール化し、再利用することが可能です。
Rustではenum、構造体によりデータを、implによりメソッドを梱包します。

どちらもカプセル化 (情報隠蔽)が可能です。

継承については以下に詳しく記します。

継承

Rust, Haskellにおいて継承はC++通常のオブジェクト指向言語とは
異なるアプローチをします。

Haskell では型クラスを使い型の振る舞いに制約をかけますが、

data Eq a => Ord a where -- こんな感じに

Rust もこの考え方に基づき、トレイト境界を使い型の振る舞いに制約をかけます。

pub struct Eq<T: Ord> {

}

impl<T> Eq<T>
  where T: Ord {

}

// こんな感じに

しかしこのままでは部分片付けを実現することができないので、トレイトオブジェクトを
継承先で宣言します。
パラメータ境界多相性と呼びます。

継承においてRust が従来のオブジェクト指向と異なるアプローチをとったのは
あなたも感じての通りオブジェクト指向の継承は必要以上にクラスを共有してしまい、クラスの
柔軟性をそぐ危険性を孕んでいるなどの理由から現在オブジェクト指向においてあまり
重要視されていないためです。

Haskellにおいては部分型付け実現のためにExistentialQuantification 拡張が必要1
と述べましたがこれによりRustは部分型付けの機能を実現します。

この時コンパイラはダイナミックディスパッチにより単相化を行うため
このコードにおいてインライン化が行えなくなり、最適化ができなくなる
部分が生じます。

また
スーパートレイトを使用してトレイト内で、他のトレイトのメソッドを使用することができます。

また
Haskell では newtype, Rust ではニュータイプパターンを用いることにより、
外部の型クラスに他の外部の型クラスの振る舞いを付加した新しい型をつくること
ができます。ニュータイプもカプセル化を実現できます。

インターフェース

メソッドに対するデフォルト実装を提供

Haskell, Rust においては
型の振る舞いを規定する
型クラス、トレイト境界と呼ばれる。それらは型に制約をかける。

C++ Haskell Rust
純粋仮想関数 classとinstance traitとimpl

おまけ

オブジェクト指向が
カプセル化 ポリモーフィズム ダイナミックバインディング インヘリタンス
であるというなら
 Haskell, Rustには
全部あります1

だから

関数型プログラミングはオブジェクト指向と相反するものではないのでしょうか、

余談

デザインパターン: 再利用可能なオブジェクト指向ソフトウェアの要素にはオブジェクト指向は

オブジェクト指向プログラムは、オブジェクトで構成される。オブジェクトは、データとその データを処理するプロシージャを梱包している。このプロシージャは、典型的にメソッドまた はオペレーションと呼ばれる。

と定義されるようです(読んでいない)。オブジェクト指向といっても色々な定義があるようです。

感想

関数型言語を学び初めてまだ日が浅くenumをどういう時に使うかいまいちわからないので(具体的な例で言えば自動微分とかパーサくらいしか知らない。でもすごく感動した。)

気合いでなんとかしたいです。

参考


  1. [コメントより追記] Haskellにおいては部分型付け実現のためにExistentialQuantification 拡張が必要2 

  2. 山本和彦 あどけない話 Haskell vs OOP