「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:オブジェクトは対象でなく射だ。日本語だとなんてことないが、英語にするとややこしい