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
- 翻訳させていただいた回答をした方のプロフィール
- その他の回答をした方のプロフィール