haskell - Why do we need monads? - Stack Overflow
の回答がわかりやすかったため翻訳させていただきました。
STEP 1
私たちは関数のみを使ってプログラミングしたい。(つまるところ「関数型プログラミング(FP)」)
STEP 2
その時、私たちは最初の大きな問題にぶつかる。
f(x) = 2 * x
g(x, y) = x / y
何が最初に実行されるべきだろうか?
どのように関数以外のものを使わずに、関数の羅列(プログラム)を作れるだろうか?
解決法
関数の合成。もしgを最初にして、次をfにしたいなら、f(g(x, y))と書く。この方法では、「プログラム」は次のような関数だ:
main = f(g(x, y))
良い感じだが…
STEP 3
次の問題: いくつかの関数は失敗する可能性を持っている(例えば、g(2, 0)は0除算となる)。
関数型プログラミングでは「例外」を持ってはいない(例外は関数ではない)。これをどのように扱うか?
解決法
関数に二種類のものを返すことができるようにする。
g : Real,Real -> Real(二つの実数から一つの実数への関数)の代わりに、g : Real,Real -> Real | Nothing(二つの実数から一つの実数またはNothingへの関数)とする。
良さそうだ、しかし…
STEP 4
しかし、関数は一つの値のみ返すべきだ(シンプルにするため)。
解決法
戻り値のための新しい型を作ろう。
新しい型は、実数かNothingを閉じ込む「Box化型」だ。
そのため、g : Real,Real -> Maybe Realとなる。だがしかし…
STEP 5
現状、f(g(x, y))はどうなってしまうか?
fはMaybe Realを引数として受け取る準備はできていない。
そして、Maybe Realを引数として受け取るために、gに接続(connect)する全ての関数を変更したくない。
解決法
関数を「connect」「compose」「link」するための、特別な関数を作ろう。
この方法は、舞台裏で、ある関数の出力(戻り値)を次の関数に渡すために合わせることができる。
私たちの場合は、g >>= f (gをfへconnect/compose)となる。
私たちは>>=にgの出力を拾い上げさせ、調査させ、Nothingの場合はfを呼び出すことなくNothingを返し、それ以外の場合はBox化された実数を取り出しfに与える。
(このアルゴリズムはMaybe型のための>>=の実装にすぎない)。
>>=は「Box化型」ごとに一度だけ書かれなければならないことに注意してほしい(Boxが異なれば、適用アルゴリズムは異なる)。
STEP 6
同じパターンを使って解決できるたくさんの問題がある。
- 「Box」を異なる意味/値を体系化/保存するために使う。そして、
gのような「Box化された値」を返す関数を作る。 - composer/linkerである
g >>= fを、gの出力をfの入力に接続するために作る。このため、fを変える必要は全くない。
STEP 7
このテクニックで解決できる目立つ例として:
例1
関数の羅列(プログラム)内の全ての関数が共有することができる、グローバルな状態を持つ
解決法
StateMonad
例2
純粋でない関数が嫌いだ: 同じ入力に対して異なる出力を生成する関数。
解決法
これらの関数にマークをつけておいて、これらの関数にタグ付け/Box化された値を返させる。
IO Monad
幸せ!
ライセンス
StackOverflowのコンテンツはcc-by-saのライセンスの下でシェアすることができます。
以下に、翻訳元の情報を記します。
翻訳元のURL: https://stackoverflow.com/questions/28139259/why-do-we-need-monads
- 質問をした方のプロフィール cibercitizen1
- 翻訳させていただいた回答をした方のプロフィール
- その他の回答をした方のプロフィール