blog
blog copied to clipboard
Topic Request: 誤解から学ぶモナド
私は「どのようにして私がモナドを誤解してきたか」という記事を執筆していたのですが、私自身がどんな誤解をしていたのかを既に記憶していないことに気が付いて執筆を諦めました。ここで行いたかった試みは、「モナドは箱・コンテナである」の節のように、不正確な理解について、どんなことを根拠としているのかと、どこが間違っているのかを、具体的に分析することです。
このような記事の場合は、複数人が自分の経験を持ち寄れば、有用な記事になるのではないかと思い付いたので、ここに投げておきます。
書きかけの内容
抽象的な概念を理解することは難しいです。そのため、イメージというものが頻繁に用いられます。イメージは、悪く言えば誤解ですが、しかし、それだけではありません。
イメージは、身近なものを使って抽象的なものを例えるものです。どうしても概念を理解できなくて学習が止まってしまうような時には、イメージが歩みを進める助けになります。しかし、イメージは本当の概念を表すものではありません。遠くまで進んだ時にイメージを捨てることが出来ないと、細部において本当の概念とイメージがずれていることに戸惑うことになったりします。さらに、イメージを使って理解したという霧が晴れるかのような体験を得たがために、イメージを頑固に信じ込んでしまうこともあり、そうなると、他の概念も、それを解釈する上手なイメージがないか探して、それを使って理解しようとするようになります。そして、イメージは難しい概念を身の回りの事柄で例えるものであるが故に、本来は繋ぎ合わせるべきではない概念を、概念 A は柱であると、概念 B は床であると、概念 C は屋根であると、イメージを通して無理に繋ぎ合わせることが可能になってしまい、歪な家を組み上げてしまうようになります(この歪な家というのもイメージですね)。こうなると、大量の不正確なイメージと、天才的なイメージを使って難しい概念を単純に解き明かしたという自負が重なって、誤解を解くことは困難になります。
イメージは、あくまでも学習を進めるために必要なだけであることを意識しながら、モナドを誤解で理解していきましょう。
## モナドは箱・コンテナである
Maybe モナドや Either モナドやリストモナドや Identity モナドなどを知った時に、こう思いませんでしたでしょうか? 私も同じことを考えました。
しかし、このイメージは Reader モナドや State モナドを知った時に崩れます。 Reader モナドは、関数であり、箱とは捉えられません。もしかしたら、関数もコンテナだと主張する人もいるかもしれませんし、そして、それは或る視点では正しいのですが、それでも State モナドは明らかにコンテナではありません。
## モナドは関数とコンテナである
## モナドは上から下へ実行される計算の列である
## モナドは上から下へ実行されるとは限らない計算である
## モナドは `class Applicative m => Monad m where { (>>=) :: m a -> (a -> m b) -> m b; }` である
大抵の Haskeller なら、これで充分でしょう。しかし、これに固執していると indexed monad などを受け入られなくなるかもしれません。
## モナドはモナドである
その通りです。そして、これはモナドについて全く知らない人でも言えることであり、これを唱えることでモナドを理解できていると思うのはやめた方がいいでしょう。
## モナドは私が理解しているモナドである
こういう確信を得た人もいるでしょう。しかし、大抵は、後になって、「私が知らないモナド」を知って驚くでしょう。
## まとめ
どんな人でも、ある程度は、物事に対してイメージを重ねています。大事なのは、自身の認識を超えていて、しかし確かであるような事実を知った時に、今までのイメージに囚われないで、柔軟な思考をすることが出来るかです。そういう月並みのことで、この記事を締めくくります。
参考資料
そもそも私はモナドを本当に理解しているのか謎ですが、
bind(>>=
)よりjoinを足すことだと考える方がモデル的にきれいだと分かってからFunctorとの関係などがすっと頭に入ってくる気がしました。
個人的な印象程度の話ですが,
- モナドは return / bind を持つ functor である
- モナドが与えられた時,それを元にある計算体系からそれを enrich した計算体系が自動的に考えられる (do expression)
という話と,
- List モナド / Maybe モナドは,そいつらをコンテナとして捉えた時に,コンテナ操作から return / bind / fmap を決められる
- Reader モナド / State モナドは,計算を enrich する transformer と捉えた時に,trans の仕方から return / bind / fmap を決められる
という話は別で,それを一緒に考えるから混乱するんじゃないかと思いますね
「モナド」を主語に持ってきてメタファーの話をするからメタファーの話が敬遠されるわけですが,list / maybe に限った話で言えばモナドの操作がコンテナの操作に対応するというのは間違っていないと思いますし,理解の助けにもなると思います.ただ,モナド自体が Haskell に導入されたのは「モナドが与えられた時,それを元にある計算体系からそれを enrich した計算体系が自動的に考えられる (do expression)」の方がモチベーションとなっていると思っていて,そっちの視点で見た時,モナド自体に意味があるのではなくそれを元に enrich した計算体系の方に意味があるので (コンテナ系は基本非決定的計算への拡張になりますね),「モナド」を主語に持ってくると話がずれるということだと思いますね (メインは「拡張された計算体系」であって,「モナド」ではない場合が多いということですね)
個人的な印象の話なので,実際に『モナド自体が Haskell に導入されたのは「モナドが与えられた時,それを元にある計算体系からそれを enrich した計算体系が自動的に考えられる (do expression)」の方がモチベーションとなっていると思っていて』とかはソースがあるわけではないですが
「モナドは上から下へ実行される計算の列である」については、「上下」をデータの依存関係と好意的に解釈すると反論が難しいですね。Control.Applicative.Backwardsと比較すると面白い解説ができるかもしれません