私の謙虚な意見では、有名な質問に対する答えは「モナドとは何か?」特に最も投票数の多いものは、モナドがなぜ本当に必要なのかを明確に説明せずに、モナドとは何かを説明しようとしています。モナドは問題の解決策として説明できるのでしょうか?
ベストアンサー1
なぜモナドが必要なのでしょうか?
- 関数のみを使用してプログラミングしたいのです。(結局は「関数型プログラミング(FP)」です)。
さて、最初の大きな問題があります。これはプログラムです:
f(x) = 2 * x
g(x,y) = x / y
最初に何を実行するかをどのように指定すればよいでしょうか?関数のみを使用して、順序付けられた関数のシーケンス (つまりプログラム)をどのように形成できるでしょうか?
解決法:関数を作成します
g
。最初に、次に としたい場合はf
、 と記述しますf(g(x,y))
。この方法では、「プログラム」も関数になります。OKmain = f(g(x,y))
ですが...さらに問題があります。一部の関数は失敗する可能性があります(つまり
g(2,0)
、0 で割る)。FPには「例外」はありません(例外は関数ではありません)。どうすれば解決できるでしょうか?解決策:関数が 2 種類のものを返すようにします。つまり、(2 つの実数から 1 つの実数への関数) ではなく、 (2 つの実数から (実数または何もない) への関数)
g : Real,Real -> Real
を許可します。g : Real,Real -> Real | Nothing
しかし、関数は(より単純にするために)1 つのものだけを返す必要があります。
解決策: 返される新しいタイプのデータ、つまり、実数または単に何も囲まない「ボクシング タイプ
g : Real,Real -> Maybe Real
」を作成しましょう。したがって、次のようになります。OK ですが...では
f(g(x,y))
、f
は を使用する準備ができていません。また、を使用するためMaybe Real
に、接続できるすべての関数を変更する必要はありません。g
Maybe Real
解決策:関数を「接続」/「作成」/「リンク」するための特別な関数を用意しましょう。こうすることで、舞台裏で、1 つの関数の出力を次の関数に供給するように調整できます。
この場合は、 (に
g >>= f
接続/構成) です。の出力を取得して検査し、 の場合は を呼び出さずにを返すか、逆に、ボックス化された を抽出してそれをフィードします。(このアルゴリズムは、 型に対するの実装にすぎません)。また、 は「ボクシング タイプ」ごとに1 回だけ記述する必要があることに注意してください(異なるボックス、異なる適応アルゴリズム)。g
f
>>=
g
Nothing
f
Nothing
Real
f
>>=
Maybe
>>=
この同じパターンを使用して解決できる他の多くの問題が発生します。1. 「ボックス」を使用してさまざまな意味/値をコード化/保存し、そのような関数にそれらの「ボックス化された値」を返すようにします。2.の出力を の入力に接続するための
g
コンポーザー/リンカーを用意します。これにより、何も変更する必要がなくなります。g >>= f
g
f
f
この技術を使用して解決できる注目すべき問題は次のとおりです。
関数のシーケンス(「プログラム」)内のすべての関数が共有できるグローバル状態を持つ:ソリューション
StateMonad
。私たちは「不純な関数」、つまり同じ入力に対して異なる出力を生成する関数を好みません。したがって、これらの関数をマークして、タグ付き/ボックス化された値 (モナド) を返すようにします。
IO
完全に幸せです!