Monad tutorial

15,810 views
15,597 views

Published on

Published in: Technology
0 Comments
48 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
15,810
On SlideShare
0
From Embeds
0
Number of Embeds
1,619
Actions
Shares
0
Downloads
158
Comments
0
Likes
48
Embeds 0
No embeds

No notes for slide

Monad tutorial

  1. 1. 函数プログラミングの集い2011 チュートリゕル 「モナドについて」 株式会社 Preffered Infrastructure 田中 英行 tanaka.hideyuki@gmail.com
  2. 2. 自己紹介• 田中英行 (@tanakh, id:tanakh)• 株式会社 Preferred Infrastructure (PFI) 勤務 – 検索エンジンのゕルゴリズムとか作ってます• Haskell (2004~)• C++ (1998~)• BASIC (1992~)• プログラミングコンテスト愛好家 – ICPC, ICFPC, CodeJam, TopCoder, …
  3. 3. 本日の概要• モナドとは?• モナドの使い方 – モナドのセマンテゖクス – 典型的なモナドの例 – Haskellでのモナド• モナドの作り方 – モナドの゗ンスタンスに – モナド変換子
  4. 4. What is Monad?モナドとは?
  5. 5. モナドとは何か?• 非常に難しい質問です• 既に数多くの人がそれに答えようとして います – そして各々が一見全く違う主張をしている
  6. 6. 幾つかの例
  7. 7. 『モナドは象である』
  8. 8. 『モナドはメタフゔーではない』
  9. 9. 『プログラマブル・コンテナ』
  10. 10. 『コンベゕのゕナロジー』 from “All About Monads”
  11. 11. いろいろありますが…• 結局モナドとはなんなのか? モナドの力の秘密、 いつか解き明かしてみたいな…
  12. 12. モナドについての疑問• 疑問にもいろいろある – モナドとは何か? – 何の役に立つのか? – なぜモナドなのか? モナドがもてはやされるのか? • ゕローとモナド、どうして差がついた…• それぞれについて、私なりの見解
  13. 13. モナドとは何なのか?• モナドとはパラダ゗ムである !
  14. 14. 抽象的な話
  15. 15. パラダ゗ム?• プログラミングパラダ゗ム – 手続き型 – 関数型 – 論理型 – オブジェクト志向 – モナデゖック(?) • ここじゃない
  16. 16. モナドとは手続き型パラダ゗ムの 再定義である• プログラミングパラダ゗ム – 手続き型 • モナデゖック – 関数型 – 論理型 – オブジェクト志向
  17. 17. 意味的側面からの モナドのメタフゔー• モナドは『プログラマブルセミコロン』 である
  18. 18. Programmable Semicolon• Real World Haskell より
  19. 19. 手続き型言語と構造化定理• プログラムは、「順次・反復・分岐」の 基本的な構造の組み合わせによって記述 できる• これらはモナドへ直接的にマッピングで きる
  20. 20. それで、何が嬉しいの?• 分岐のセマンテゖクス書き換え• 反復のセマンテゖクス書き換え – そういうことができる言語は過去にはあった• 逐次のセマンテゖクス書き換え – かつて無いもの(…の様な気がします)!
  21. 21. 逐次のセマンテゖクス• およそほとんどの手続き型言語では、 セミコロンの意味は変えられない – 空気のような存在• セミコロンの意味を変えることの意義が 伝統的に見逃されて来たのではないか? int main() { main = foo(); bar(); foo >> bar }
  22. 22. 継続との関係• モナドは継続(continuation)の一般化とも考 えることができます• 継続=各セミコロンにおけるプログラム の状態• モナドはセミコロンを記述するわけなの で、その状態を取り出すことは簡単 – 実際に継続モナドというものがあります
  23. 23. セミコロンをいじることにより 可能になること• 普通のプログラムを非決定計算に変える• 普通のプログラムにエラーハンドリング を(プログラムを書き換えずに)追加する• 普通のプログラムに暗黙の状態を導入す る
  24. 24. コンテクスト• 具体的なモナドに対して、それが計算に 付加価値を与えます。それを(計算の) コンテクストと呼ぶことにします – つまり、モナドというのはコンテクスト付き の計算ということができる• 例えば… – monad:リストモナド → ctx:非決定性 – monad:Stateモナド → ctx:mutableな状態 – etc …
  25. 25. それぞれにそういうプログラムを書けばいいんじゃないんですか?• コンテクストごとに異なる記法• コンテクストごとに異なるプログラム• コンテクストごとに異なる語彙 ・・・ 抽象化の欠如
  26. 26. コンテクストの抽象化• 共通のゕルゴリズムの記述• 共通のコード片の抽象化 よりメタレベルの抽象化へ
  27. 27. 床下配線のゕナロジー• モナドによるセミコロンの抽象化は 床下配線と例えられることも – 見えないところを書き換える
  28. 28. 少し具体的な話
  29. 29. 例• N-ク゗ーン問題 – Int が与えられて解を返す – 解とはなんぞや? • 全解列挙 • どれか一つを見つける • 一番いい解を頼む – いろいろ考えうる
  30. 30. N-Queen問題• モナデゖックに書くと、これらを統一的 に扱える – 解の列挙のストラテジをモナドとして記述 – 問題を解くゕルゴリズムからの分離
  31. 31. 前半まとめ• モナドとは何なのか? – 計算コンテクストの抽象化である• なんでそれが嬉しいの? – 具体的なコンテクストに依存しないコードを 書ける – 抽象化したものを具体的なコードにできる• なぜモナドなの? – モナドは構造化定理に必要な要素を自然に記 述できて、なおかつ簡潔であるから
  32. 32. 三行で言うと• モナドは関数レベルで • メタプログラミング • するためのものです (´・_・`)えっ…?
  33. 33. How to use Monadsモナド入門・モナドの使い方
  34. 34. 実装レベルのお話
  35. 35. モナドとは• “ある特定の方法”で組み合わせることので きる計算のことをまとめて、 モナドと呼びます。
  36. 36. ちなみに• 組み合わせ可能な計算はモナドだけではあり ません – いろいろな抽象化におけるそれが存在• 例えば、 – 関数 (関数合成) – フゔンクタ (関手) – ゕプリカテゖブ・フゔンクタ – ゕロー – Iteratee – etc…
  37. 37. ひとまず置いておいて、Haskellでのモナドのお話
  38. 38. Haskellでのモナド• 次のような型クラスこれの゗ンスタンスが具体的なモナド=計算コンテクスト
  39. 39. モナドになっている標準データ型• 標準データ型の中にもモナドがある – リスト – Maybe – Either – IO
  40. 40. モナド則の必要性• モナド則は、モナドを安全に組み合わせ るのに必要 – これらの挙動が同じでなければ、組み合わせ 方によって意味が変わるということになる
  41. 41. Haskellのdo記法• Haskellではモナドを非常によく使うので、 専用の構文糖衣が用意されています
  42. 42. 高度なモナドの使い方
  43. 43. リストモナド• リストはモナドにできる• リストは非決定 計算のコンテクスト と捉えることが できる
  44. 44. Maybeモナド• Maybeもモナド• 失敗するかもしれない計算
  45. 45. IOモナド• 入出力を行う可能性のある計算• HaskellではIOモナドを介してしか入出力を 扱えない
  46. 46. IOモナドの功罪• モナドに関するよくある誤解 – モナドってpurely functional languageでIOする ためにあるんでしょ?• モナドはIOのためにあるのではありません• モナドはIOのためにあるのではありません – 大事なことなので
  47. 47. モナド則• すべてのモナドは次のモナド則を満たす ”べき”である – 満たす保証をするのはプログラマの責任 – あえて満たさなくても良い
  48. 48. モナド変換子(Monad Transformers)• モナドとモナドを組み合わせるもの – (cf. 計算と計算を組み合わせるものがモナド)
  49. 49. 動機• 複数の計算コンテクストを合成したい – 失敗するかもしれないIO計算 – エラーハンドリングできるパーザー – etc, …
  50. 50. MTL (Monad Transformer Library)• 標準のモナドラ゗ブラリ – Preludeのモナドを大幅強化• これらのものを含む – 幾つかの標準的なモナド – これらのモナドを合成するための モナド変換子(Monad Transformers)
  51. 51. MTLに含まれるモナド• Monad.Cont (継続)• Monad.Reader (ReadOnly状態)• Monad.Writer (ログ出力)• Monad.State (Mutable状態)• Monad.List (非決定計算)• Monad.Error (エラーハンドリング)• これに加え、それぞれのモナド変換子版
  52. 52. モナド変換子• 2つのモナドを合成するためのもの• 例えばStateモナドの場合: – StateT s m a • モナド変換子版Stateモナド • State s a と比べて、mというパラメータが追加 • mに合成したいモナドを代入 – StateT s IO a • IOモナドを内包したStateモナド • IOモナドの操作とStateモナドの操作が両方できる
  53. 53. 持ち上げ(lift)• StateT s IO の例 – StateT s IO の中でIOを行うには、持ち上げ(lift) を行う必要がある(型が合わないので)
  54. 54. モナドクラス• 例えばIOを行うだけの計算• これは、StateT s IO 以外のモナドでも使え て欲しい – ErrorT err IO – ReaderT s IO –…
  55. 55. MonadIOクラス• そのために、IOをliftできるクラス全体を抽象 化したMonadIOクラスを定義• 先のコードは次のような型に• StateT s IO などをMonadIOの゗ンスタンスに すれば使用可能に。
  56. 56. 一般の持ち上げ• モナド変換子に渡されるモナドはIOだけで はない – ネストする場合もある• 一般ケースのために、MonadTransという クラスが用意されている – 内側のモナド外側のモナドに持ち上げること ができる
  57. 57. 中盤まとめ• モナドとは >>= と return の2つの演算が定 義されたもの• 標準データ型の多くのものがモナドに なっている• mtlというモナド変換子ラ゗ブラリがある• モナド変換子を用いてモナドを組み合わ せる• モナド持ち上げで型の異なるモナドを張 り合わせる
  58. 58. Advanced Topics
  59. 59. monad-control (1)• liftの逆をするもの• 動機 – Haskellの例外ハンドリング機構はIOモナド ベース – 渡せるものがIO固定 • MonadIO に対しても例外ハンドルしたい
  60. 60. monad-control (2)• MonadIOに対して一般化• それを行えるようにするために、 MonadControlIOというクラスを用意
  61. 61. モナドいろいろ• 近年実に様々なラ゗ブラリがモナデゖッ クラ゗ブラリとして提供されるようにな りました• それらの一部を紹介していきたいと思い ます
  62. 62. MonadPar• 並列計算を記述するためのモナド – `par`, `seq` などをモナド化したもの
  63. 63. Parser• パーザいろいろ – Parsec, Attoparsec, trifecta
  64. 64. WebApp• WAI, Yesod, Snap, CGI, …
  65. 65. Interpreter• hint, BASIC, …
  66. 66. How to design your monadsモナドの作り方
  67. 67. モナドを設計するにあたって• 自分のラ゗ブラリが、モナドとして抽象 化できることに気づいたとします• しかし、モナドの作り方を間違うと、非 常に使い勝手の悪いものができてしまい ます – 使い勝手のよいモナドの実装には気をつける べきことが沢山あります• ここまで紹介したことはすべて理解して おくことが望ましいです
  68. 68. 1) 既存のモナドが利用できないか• 実際のところ、mtlに含まれるモナドで、 ほとんどのケースはカバーされます• 作りたい計算が、mtlにあるモナドの組み 合わせで実現できないかまず検討するべ きです
  69. 69. 2) モナド変換子版を用意する• いざモナドを作るとなったら、(原理的に) 可能なのであれば、モナド変換子版を必 ず用意しましょう – モナド変換子にはHogeTと、末尾に大文字Tを つけるのが慣習です• 非モナド変換子版は、モナド変換子版に Identityモナドを代入したものにします – 実装を重複させてはいけません
  70. 70. MonadIOクラスの゗ンスタンスにする• あなたのモナドをMonadIOの゗ンスタンス にしておくのはとても良いことです• あなたのモナドを利用するすべての場所 でIOを行うことができるようになります• MonadIOを用意しておくのはモナドによっ てIOを行うHaskellにとっては極めて重要な ことです
  71. 71. ※ IOモナドについて(1)• IOモナドは、Haskellのプログラムの中では外 すことのできないモナドです – unsafePerformIO などを除いて• その結果、IOを呼ぶコードはそれ自身がIOを 行わなくても、IOモナドにする必要がありま す• Haskellによくある批判として、まともなプロ グラムを書いているとほとんどすべての関数 の型がIOになる、というのがあります – IOモナドは感染するとか言われます
  72. 72. ※ IOモナドについて(2)• そこでMonadIOの出番です• IOが必要なコンテクストについてのみ、 MonadIOを要求させておけば良くなります• Pureなモナドに関しては、具体的な型が決 定するに従って、自動で持ち上げられる ことになります• つまり、PureなコードとIOのコードのオー バーロードが可能になるということです
  73. 73. 3) MonadControlIOの ゗ンスタンスにする• あなたのモナドが例外を正しく扱えるよ うにするために、MonadControlIOの゗ンス タンスにしましょう – これがないと bracket などが正しく後処理でき ません
  74. 74. 4) MonadTransの゗ンスタンスにする• あなたのモナド変換子が、他のモナドを 自動多段持ち上げ可能になるように(可能 であれば)必ず、MonadTransの゗ンスタン スにしましょう
  75. 75. 5) Functor, Applicative の゗ンスタンスにする• Applicativeスタ゗ルというものがあります – http://d.hatena.ne.jp/kazu-yamamoto/20101211/1292021817 – などを参照• あなたのモナドをFunctor, Applicativeの゗ ンスタンスにすると、使い勝手が大幅に 向上します• 必ずこれらの゗ンスタンスにしましょう – Monadの゗ンスタンスは必ずFunctor及び Applicativeの゗ンスタンスにできます
  76. 76. 6) 必要に応じて、その他• その他のモナドクラスの゗ンスタンスに します – エラーハンドリングを付けたいなら、 MonadError – 失敗に対する代替を与えたいときには、 Alternative
  77. 77. ※ Alternativeクラスについて• m1 <|> m2 なる演算子が定義されている• m1が失敗したとき、m2の結果• Alternativeの任意の゗ンスタンスに対して – many p – pを失敗するまで繰り返し – some p – pを失敗するまで1回以上繰り返し – optional p – p が失敗したらNothing成功したら Just aを返す – これらを定義することができる
  78. 78. GenericNewtypeDeriving• 自分のモナドをこれらすべての゗ンスタ ンスにするのは骨の折れる作業です• モナドがnewtypeの時、これをderiving で 済ませることができます – -XGenericNewtypeDeriving 言語拡張
  79. 79. 後半まとめ• モナドを作るにあたって – MTLのモナドの組み合わせで実現できないか 考える – いろいろなクラスの゗ンスタンスにしておく – モナド以外の有用なクラスが標準にあるので それの゗ンスタンスにもする

×