Successfully reported this slideshow.

More Related Content

Related Books

Free with a 14 day trial from Scribd

See all

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のモナドの組み合わせで実現できないか 考える – いろいろなクラスの゗ンスタンスにしておく – モナド以外の有用なクラスが標準にあるので それの゗ンスタンスにもする

×