このようなモナドの言語に依存しない説明を使用します。最初にモノイドを説明します。
モノイドは(おおよそ)のパラメータとして、いくつかの種類を取り、同じ型を返す関数のセットです。
モナドを取る関数の(おおよそ)が設定されているラッパーパラメータとしてタイプと同じラッパー・タイプを返します。
これらは説明であり、定義ではないことに注意してください。その説明を気軽に攻撃してください!
したがって、OO言語では、モナドは次のような操作構成を許可します。
Flier<Duck> m = new Flier<Duck>(duck).takeOff().flyAround().land()
モナドは、含まれるクラスではなく、これらの操作のセマンティクスを定義および制御することに注意してください。
従来、OO言語では、クラス階層と継承を使用してこれらのセマンティクスを提供していました。したがってBird
、メソッドtakeOff()
、flyAround()
およびを持つクラスがありland()
、Duckはそれらを継承します。
しかし、その後、penguin.takeOff()
失敗するため、飛べない鳥とのトラブルに巻き込まれます。例外のスローと処理に頼らなければなりません。
また、ペンギンがであると言うとBird
、たとえばの階層もある場合、多重継承の問題に遭遇しますSwimmer
。
基本的に、私たちはクラスをカテゴリーに分類し(カテゴリー理論に謝罪して)、個々のクラスではなくカテゴリーごとにセマンティクスを定義しようとしています。しかし、モナドは階層よりもそれを行うためのはるかに明確なメカニズムのようです。
したがって、この場合、Flier<T>
上記の例のようなモナドができます。
Flier<Duck> m = new Flier<Duck>(duck).takeOff().flyAround().land()
...そして、インスタンス化することはありませんFlier<Penguin>
。おそらくマーカーインターフェイスを使用して、静的な型付けを使用してそれを防ぐこともできます。または、実行時の機能チェックで解決します。しかし、実際には、プログラマーはゼロで割るべきではないという意味で、ペンギンをフライヤーに入れてはいけません。
また、より一般的に適用できます。チラシは鳥である必要はありません。たとえばFlier<Pterodactyl>
、またはFlier<Squirrel>
、これらの個々のタイプのセマンティクスを変更せずに。
型階層ではなく、コンテナ上の構成可能な関数によってセマンティクスを分類すると、特定の階層に適合する「やる、しない」クラスの古い問題を解決します。また、簡単&はっきりと同じように、クラスの複数の意味を可能にするFlier<Duck>
だけでなく、Swimmer<Duck>
。動作をクラス階層で分類することにより、インピーダンスの不一致に苦労しているようです。モナドはそれをエレガントに処理します。
私の質問は、継承よりも合成を優先するようになったのと同じように、継承よりもモナドを優先することも理にかなっていますか?
(ところで、これがComp Sciにあるのか、それともComp Sciにあるのかはわかりませんでしたが、これは実際的なモデリングの問題のように見えます。