Haskell その8
モナド乱読
亀のようなノロさでHaskellを学ぼうとしている。
けど、当然日記中で扱ったものだけに注目したわけでなく、わからないなりに拾い読みしてものは多々あるわけで…。
モナドに関しては、まず、ぼんやりとした輪郭をつかんでいきたい。
今日はその1。
とにかくモナドについての乱読の足跡。
『Wikipedia-モナド』
http://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%8A%E3%83%89
まずは辞書的な定義を見てみた。
プログラミング言語におけるモナドとは、(純粋)関数型言語において、参照透過性を保ちながら状態や副作用などを扱うための枠組みの1つ。数学の圏論におけるモナドに由来。
『Wikipedia-圏論』
http://ja.wikipedia.org/wiki/%E5%9C%8F%E8%AB%96
自分の数学知識は、大学の一般教養とマクロ経済学の授業くらいで終わってるので(しかもさっぱり忘れた)難しすぎ。
先走りするが、Haskellのモナドは計算を合成してより複雑な計算にする戦略、と言われる。
関連する数学的構造のさまざまな類(class)に共通する性質を見出そうとする試みであった
要するに、その戦略に、圏論の研究で見出された共通する性質を利用したと思えばいいのだろうか。
『情報処理学会 会誌「情報処理」Vol.47 No.3 Haskellプログラミング:自分自身を出力するプログラム 』
http://www.ipsj.or.jp/07editj/promenade/4703.pdf
圏論とHaskellのモナドがどう関係するのか詳しく記してある。
(Kleisliカテゴリ)を用いると、非決定的な計算や副作用を持つ計算、継続計算などさまざまな計算モデルが実現できることが知られている。
プログラミングでMonadを用いる際こうした数学的背景について知っておく必要はないが、(>>=)やreturnといった演算が異なるMonad間でオーバーロード可能で、Monadの合成をしてもプログラムの多くは書き換えなくてよいという性質はこうした背景によるものである.
多相性を利用して、様々な計算を合成する、と。
それにしても、ここに書いてること全部ちゃんと理解できたらいいのになぁ。
数式で埋め尽くされたページは、それはそれはカッコ良く見える。 (ヒント:もっとカッコ良くしたければ、ギリシャ文字を使うといい)。
『ハッカーと画家』より
って言うしw
でも人生は短い。必要なもんだけ取り込もう。
『モナドのすべて-モナドの物理的なアナロジー-』
http://www.sampou.org/haskell/a-a-monads/html/analogy.html
グッとくだけた見方で説明してくれている。
モナドは組み立てラインを構築するフレームワークのようなものだと。
しかも、箸でも飛行機でも作り出せる汎用性をもつと言う。
1.ベルトコンベヤとともに移動する作りかけの製品を載せるトレー
2.トレーに任意のオブジェクトを載せるローダ(loader)マシン
3.対象の載ったトレーをひとつとり、新しいオブジェクトの載った新しいトレーを作る合成(combiner)マシン。
これらの合成マシンは、実際に新しい オブジェクトを生成するワーカ(worker)マシンに取り付けられています。
直感的には継続計算の実現メカニズムの説明になってる気がする。
『やさしいHaskell入門-モナドについて-』
http://www.sampou.org/haskell/tutorial-j/monads.html
『モナドのすべて』
http://www.sampou.org/haskell/a-a-monads/html/index.html
そしてここへ戻ってくる。
あら。最初”どこがやさしいんだ?”と言ってたのが、
いろいろ寄り道してみると、結構やさしいことに気付く。
class Monad m where (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b return :: a -> m a fail :: String -> m a m >> k = m >>= \_ -> k fail s = error s
HaskellのMonadそのものはclassであり、いろんな総称関数の集まりとして定義される。
そうですな、"共通した性質"を表さなきゃならず、"箸でも飛行機でも作れ"なくちゃいかんのだ、と。
そんくらいのぼんやりした理解のまま、具象の理解へ進む。
やっと先日の宿題、Maybeモナド。
data Maybe a = Nothing | Just a instance Monad Maybe where return = Just fail = Nothing Nothing >>= f = Nothing (Just x) >>= f = f x
Maybeモナドの型は、きっちりと"data m a = .. "という形式を守っている。
「m a は型aの値を保持するコンテナ」という言葉が出てくるように、
多相性をもった入れ物、すなわちトレー。
計算と計算の間を流通するものを抽象化することで、いろんな計算が合成できる可能性が生まれる。
箸でも飛行機でも、トレーに置いた状態でないとベルトコンベアに乗せられない。
そこでトレーであるm aを作り出すのがreturn。
Maybeモナドは計算成功の連鎖を合成するためにJustを返す。
"failは付け足し"、と書いてあるが、計算失敗の連鎖まで合成するのはMaybeの本懐だ。
問題は(個人的に)、bindとも呼ばれる組み合わせ子関数 >>= 。
(>>=) :: m a -> (a -> m b) -> m b
- トレー&加工前製品 = m a
- トレーを外し、加工前製品を受けとり、トレー&加工後製品を返す = a -> m b
- トレー&加工後製品 = m b
とでも理解すればよい?
inc1 i = i + 1 inc2 i = Just (i+1) result a = Just ("Success")
こういうコードを書いてみる。
inc1はもちろん合成できず。
> elemIndex 1 [0..9] >>= inc1 ... Couldn't match `Maybe b' against `Int' Expected type: Int -> Maybe b Inferred type: Int -> Int
inc2、resultはくっつけることができる。
しかも、resultで中身は文字列になっても可。
> elemIndex 1 [0..9] >>= inc2 >>= result Just "Success"
あとはモナド則か。
でも、また今度にしよう。
『モナド則』
http://www.sampou.org/haskell/a-a-monads/html/laws.html