新年なので monad を勉強してみた

(この記事は2006/01/03に書かれたものです)

新年とはあまり関係ないのですが、まとまった時間が取れたので前から気になっていた monad を勉強してみました。

monad と聞いて知っていたのは、まず、純粋関数型プログラミング言語である Haskell で、副作用が発生する入出力を処理するための理論的な枠組み、ということ。そして、数学の圏論(Category Theory) というものをベースとしたものであること。くらいのものでした。

本当に純粋な関数型言語では、評価値のキャッシュや評価の並列化など、計算の効率を上げるさまざまな工夫が可能になります。しかし、入出力や破壊的代入など副作用を伴う操作が混ざってしまうとそういった工夫ができません。ただ、入出力のないプログラムは非常に限られますし、また書きやすさや効率の観点から破壊的代入を許す関数型言語のほうが(僕の知る限りでは)一般的です。

Haskell はそこらへんの妥協をほとんどしていないのに実用性を確保している言語らしいということで気になっていました。monad はその肝となる概念ということで、この機にお勉強です。

なお、monad の原論文は Eugenio Moggi. Computational lambda-calculus and monads. LICS 1989 とのこと。

圏論って……

上記のページによると: 対象 X, Y に対して定義される射の集合を Hom(X, Y) と書く。そのとき、以下を満たす概念を圏 (Category) と呼ぶそうです。

 (Cat 1) 射の合成は結合法則 h(gf) = (hg)f をみたす.
 (Cat 2) 任意の対象 X に対して
   ∃ε∈Hom(X, X) ∀f∈Hom(X, Y)∀g∈ Hom(Z, X), fε=f, εg=g
 (Cat 3) 対象のペア (X, Y), (X', Y') が異なる
               ⇒ Hom(X, Y) ∩ Hom(X', Y') = φ

(Cat 1) と (Cat 2) は結合則と単位元ということで理解は容易なのですが、(Cat 3) の理解が難しいです。射 f ∈ Hom(X, Y) は X と Y に属しており、異なる対象間の射とオーバーラップしていない、というようなイメージなのでしょうか。うーむ。

そして、covariant functor と contravariant functor と Nat(F, G) の四角い可換図式が出てくるに至って、ようやく大学院時代に授業を受けていたことを思い出しました……。今から思い直すと貴重な講義ばかりだったわけですが、あのころのノートは今いずこ……。

追記: Wikipedia での説明 には (Cat 3) 相当の説明は見当たりませんね。

そして

ぱらぱら調べているうちに、monad が圏論をベースにしているというと難しく聞こえますが、基本的には monoid くらいの枠組みで考えている、というだけなんじゃないかという疑惑がむくむくと。monoid は結合律を満たし単位元が存在している演算がある群、というだけですので、functor とかあそこらへんのやたら高階なフレームワークを勉強しなおす必要はない気がしてきました。

ちなみに

Haskell で使われている monad という範囲では、型にタグをつけるためのフレームワークということで僕の中では理解が進んでおります。作り方によってはそのタグをはがせないように出来るので、たとえば IO によって評価値に影響を受けるものをしっかりタグで区別できる、という理解です。monad 自体はいろいろな使い方ができるのに、変に Haskell で IO で使用している、という文言が一人歩きしてしまって、理解を難しくしてしまっている気がしますが……。

あと、アスペクト思考的に操作を weave するためにも使われているんでしょうか。途中で Error が発生したらもう処理しないとか。型にあとから属性を付加するという点では同じなんですが。

その後

その後、細切れの時間しか取れていないため、バックグラウンドへの理解は遅々として進みません。monad で囲う、という操作が理論的に functor と関係してくるのかも……。