モナドをつくろう

5,054 views

Published on

函数プログラミングの集い 2012 in Tokyo 発表スライド
継続については『簡約!? λカ娘(算)』 http://www.paraiso-lang.org/ikmsm/books/c82.html の「オール・アバウト・ケイゾク・イン・スキーム」を読むといいんじゃなイカ?

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

No Downloads
Views
Total views
5,054
On SlideShare
0
From Embeds
0
Number of Embeds
1,425
Actions
Shares
0
Downloads
25
Comments
0
Likes
8
Embeds 0
No embeds

No notes for slide

モナドをつくろう

  1. 1. モナドをつくろう @dico_leque
  2. 2. 自己紹介Twitter: @dico_leque趣味 Schemerお仕事では F# とか OCaml とか Scala とかJava とか
  3. 3. しない話プログラムの中のモナドの見つけ方
  4. 4. しない話Haskell でのモナドの作り方(+ モナド則の証明)
  5. 5. する話継続(Continuation)を使ってモナドをつくる話型の話はしないので Scheme 時々 Haskell で説明します
  6. 6. モナド class Monad m where (>>=) :: m α → (α -> m β) → m β return :: α → m αただしreturn a >>= k ≡ k am >>= return ≡ mm >>= (x → k x >>= h) ≡ (m >>= k) >>= h α → m β なる計算をつなぐ便利な何か
  7. 7. 継続ある計算を実行したその後を表すもの
  8. 8. call/cccall-with-current-continuaitonある場所における現在の継続(currentcontinuation、残りの計算)全体を取り出す手続き
  9. 9. call/cc の例(display (string-append “hello, “ “world!”))(newline)(exit 0) (string-append “hello, “ “world!”) の継続 (残りの計算)を取り出す
  10. 10. call/cc の例 (display (call/cc (lambda (k) (string-append “hello, “ “world!”)))) (newline) (exit 0)(call/cc ...) 部分を穴にした手続きを引数 k に渡す
  11. 11. call/cc の例 k = (lambda (x) (display x) (newline) (exit 0))
  12. 12. call/cc の嫌な所常にプログラムの「残り*全体*」を取り出すプログラムの最後には (exit 0) 相当のものがあるので継続手続きは呼び出しても返らないcall/cc の継続は組み合わせられない
  13. 13. 限定継続プログラムの残りすべて(full continuation)ではなく、範囲を限定した継続(delimitedcontinuation)
  14. 14. shift / reset限定継続を扱うための演算子のひとつshift から reset までの継続を手続きとして取り出す他の継続演算子との比較や細かい部分は略
  15. 15. shift / reset の例(+ 2 (reset (* 2 3 (shift k (k (k 4))))))shift と reset の間の計算を k として取り出すこの例では k = (lambda (x) (* 2 3 x))戻り値は 146 = (+ 2 (* 2 3 (* 2 3 4)))限定継続は組み合わせられる
  16. 16. ここまでの話継続はプログラムの「残りの部分」を表すcall/cc, shift / reset を使うとプログラム中の「継続」を手続きとして取り出せる
  17. 17. ここからの話shift / reset を使うとモナドを表現することができる
  18. 18. 例: Maybe モナド(reify (let* ((a (reflect (find-opt (cut = <> 2) (1 0 3)))) (b (reflect (find-opt (cut = <> 3) (2 3 1))))) (list a b)));; find-opt : (α -> Bool) -> [α] -> Maybe α reify が Haskell の do に対応 monadic な値を使うところに reflect let* 等がそのまま使える
  19. 19. Maybe モナドの実装 (define-syntax reify (syntax-rules () ((_ expr) (reset (let ((v expr)) (some v))))))reset を使って、この内側は Maybe モナドの文脈であることを指定する
  20. 20. Maybe モナドの実装 (define (reflect m) (shift k (match m (($ Some x) (k x)) (($ None) m))))Some x だったら x の値で計算を続行し、None だったら残りの計算(継続)を捨てて全体を None にする
  21. 21. 継続から見た MaybeNone のときに捨てられる継続は、例外をthrow して catch されるまでの部分に相当する
  22. 22. その他のモナドList: 取り得る値(リストの要素)のぶんだけ継続を複製する(未来を複製する)State: 残りの計算(継続) α → β を状態を持ち回る計算 α → σ → (β, σ) に加工するAmb: 別の未来(継続)を保存しておいて、失敗したらそこから再開する(cf. SICP)……
  23. 23. その他のモナド(define-syntax reify (syntax-rules () ((_ expr) (reset (return expr)))))(define (reflect m) (shift k (>>= m k)))
  24. 24. 比較Haskell 等のモナドは CPS(ContinuationPassing Style = 継続渡し形式)shift / reset を使うと直接形式(DirectStyle)にそのままモナドを入れられる「プログラム全体を CPS で書くのはつらい→call/cc」 「プログラム全体を monadic styleで書くのはつらい→ shift / reset」
  25. 25. 比較純粋な計算のための let とモナド用の <-(let!)を分けなくてもよいmapM, foldM, ... も(副作用の順序が保証できるなら)別に用意しなくてもよい
  26. 26. 暗黒面継続は「副作用」なので評価順序重要 mapM はいらなくても map-in-order が欲 しくなる型付きの場合は型推論がないとかなりつらいcf. scala.util.continuations と OChaCaml
  27. 27. まとめshift / reset を使うとモナドを表現することができる(>>=) の右側は継続継続の側からモナドを見直してみると面白い
  28. 28. 参考文献Andrzej Filinski, “Representing Monads”,Proceedings of the Twenty-First Annual ACMSymposium on Principles of ProgrammingLanguages, 446—457, ACM Press, 1994浅井健一、『shift/reset プログラミング入門』、 http://pllab.is.ocha.ac.jp/~asai/cw2011tutorial/main-j.pdf

×