関数型プログラミングで使用されるモナドと矢印の概念については、広く知っています。また、同様の問題を解決するために使用できることも理解しています。
ただし、特定の状況で使用するものを選択する方法については、まだ少し混乱しています。
モナドはいつ使用する必要があり、矢印はいつ使用する必要がありますか?
Lindley、Wadler、Yallop による 2 つの優れた論文があります (ここで LTU で議論されています)。
理解すべき最も重要なことは、モナドよりもアローであるものが多いということです。逆に、モナドはアローより厳密に強力です (上記の 2 番目の論文で正確にその方法を指定しています)。
特に、モナドは type の適用関数を備えた矢印(a ~> b, a) ~> b
であり、(~>)
は与えられた矢印のコンストラクターです。リンドリー等。これは、矢印が用語とコマンド (または、必要に応じてオブジェクトと射) の間で維持する細心の注意を払った区別を破壊することを指摘してください。
アプリカティブ ファンクタには、特にストリームに対する操作として最もよく考えられるものに対して、さまざまなアプリケーションがあります。実際、アローは、ストリーム上のトランスフォーマーの概念を一般化することから生じると考えることができます (つまり、特定のアプリケーション ファンクターによって構築されるオブジェクトのモーフィズムに新しい言語を導入します)。
私の経験では、モナドはオブジェクトと射の区別をあいまいにするため (つまり、単語を正しく使用すると、閉デカルト圏が生じます)、モナド内の項は一般に、オブジェクト内の項よりも必然的に不透明になります。アローまたはアプリカティブ ファンクター (ただし、どちらもarr
およびpure
メソッドによってそれぞれ任意の関数を注入できることに注意してください)。
したがって、何かがモナドの特性を与えられていない場合(概念的にはモナドを形成していても)、より詳細な検査と最適化が可能になる可能性があります。また、シリアル化が容易になる可能性もあります。したがって、パーサーと回路モデリングでアプリケーションと矢印を使用します。
上記は、一般的かつ説明的なものにしようとしました。以下は、私の意見に基づく経験則の一部です。
状態のように見えるものをモデル化する必要がある場合は、モナドから始めます。グローバルな制御フロー (つまり、例外、継続) のようなものをモデル化する必要がある場合は、モナドから始めます。モナドのパワーと汎用性と矛盾する要件が発生した場合 (つまり、join(join :: m (m a) -> m a)
が強力すぎる場合)、使用しているもののパワーを削ぎ落とすことを検討してください。
ストリーム、ストリームの変換、特に特定の特性 (特に過去と未来の無制限のビュー) を不透明にする必要があるストリームをモデル化する必要がある場合は、アプリケーション ファンクターから始めます。ストリームの変換のプロパティについてより強力な推論が必要な場合は、矢印に手を伸ばすことを検討してください。
または、非常に大まかに言えば、アプリケーションは回路の動作用であり、矢印は回路の構造用であり、モナドは汎用目的の計算効果用です。
もちろん、この話にはまだまだ続きがあります。アプリケーションについては、特にFRP に関する Conal Elliott の研究を参照してください。矢印については、HXT XML パーサー ライブラリ、 Yampa FRP プロジェクト、Haskell on a Horse Web フレームワーク、Hudak と Liu の古典的な論文「Plugging a Space Leak with an Arrow」などを参照してください。モナドについては、どこでも参照してください。そしてもちろん、何かがモナドだからといって、Applicative Notation がより明確で表現力に欠けるという意味ではないことに注意してください。