「Haskellでの合成可能なオブジェクトの構成とその応用」評

Haskellでの合成可能なオブジェクトの構成とその応用では、オブジェクトをメッセージをアクションに写すものとして捉え、構成している。この構成方法では、アクションを対象、オブジェクトを射とする*1圏ができ、継承やメソッド・オーバーライドといった操作を、射の合成として表すことができる。

論文では、「操作の拡張性」「データの拡張性」「振る舞いの動的性」の3点について、クラスベースOOP・代数データ型・型クラスを用いた場合と提案手法とで比較を行っている。論文での考察結果をまとめた表を次に引用する。

操作の拡張性 データの拡張性 振舞いの動的性
クラスベースOOP
代数データ型
型クラス
提案手法

型クラスで「振舞いの動的性」を実現する

しかし、型クラスでも「振舞いの動的性」は実現できるのではないだろうか。Haskellでは存在量化を使ってElfとOrcをひとつの型にまとめられるのだから、SpellがEntityを返すように定義すればいいはずだ。

Rustでも、トレイト・オブジェクトを使うことで同様のことができる。

表現問題の観点から言えば、新しいインターフェースを追加しようとすると、Entityを変更しなくてはいけないという問題は残っていると思うのだが、振舞いの動的性の問題は解決出来ている。

提案手法における「操作の拡張性」の問題点

一方で、提案手法の実装には問題がある。論文では、メッセージの和に対して次のような実装が行われていた。

instance (Elf s, Elf t) => Elf (Sum s t) where
    elf = elf @||@ elf

演算子@||@を使っているので、これは和の左右メッセージをそれぞれ左右のオブジェクトに振り分けるということだ。左右のオブジェクトは状態を共有せず、独立して動作することになるはずで、これだとSpellで左のelfがorcに変わったとしても、右のelfはそのままということになってしまう。このような挙動は目的に沿っていないはずだ。

*1:オブジェクトは対象でなく射だ。日本語だとなんてことないが、英語にするとややこしい