Macros in Clojure      @athos0220
Agenda• Lispマクロ入門• Clojureのマクロとその周辺• Clojureマクロの応用例
 Lispマクロ入門
マクロとは                when                                       if      =        print    print          =                ...
マクロの定義• シンボルやリストで展開形のコードを 作ってやる  (when ⃝⃝   (if ⃝⃝    △△         (do △△    ✕✕)             ✕✕)               nil)
マクロの定義    • シンボルやリストで展開形のコードを       作ってやる           (when ⃝⃝            (if ⃝⃝             △△                  (do △△     ...
マクロの定義    • シンボルやリストで展開形のコードを       作ってやる           (when ⃝⃝              (if ⃝⃝             △△                    (do △△ ...
名前衝突の問題
名前衝突の問題束縛変数の衝突   自由変数の衝突
名前衝突の問題束縛変数の衝突                  自由変数の衝突     (defmacro or [expr1 expr2]       `(let [val ~expr1]          (if val          ...
名前衝突の問題束縛変数の衝突                           自由変数の衝突              (defmacro or [expr1 expr2]                `(let [val ~expr1]...
名前衝突の問題束縛変数の衝突                           自由変数の衝突              (defmacro or [expr1 expr2]                `(let [val ~expr1]...
名前衝突の問題束縛変数の衝突                           自由変数の衝突              (defmacro or [expr1 expr2]                `(let [val ~expr1]...
名前衝突の問題束縛変数の衝突                           自由変数の衝突              (defmacro or [expr1 expr2]                `(let [val ~expr1]...
名前衝突の問題束縛変数の衝突                           自由変数の衝突              (defmacro or [expr1 expr2]                `(let [val ~expr1]...
名前衝突の問題束縛変数の衝突                           自由変数の衝突              (defmacro or [expr1 expr2]                `(let [val ~expr1]...
名前衝突の問題束縛変数の衝突                           自由変数の衝突              (defmacro or [expr1 expr2]                `(let [val ~expr1]...
名前衝突の問題束縛変数の衝突                           自由変数の衝突              (defmacro or [expr1 expr2]                `(let [val ~expr1]...
健全なマクロ (Hygienic macros)• 名前の衝突を自動的に回避してくれる  ハイパーなマクロ
健全なマクロ (Hygienic macros)   • 名前の衝突を自動的に回避してくれる     ハイパーなマクロ(define-syntax or  (syntax-rules ()   ((or expr1 expr2)    (let...
健全なマクロ (Hygienic macros)   • 名前の衝突を自動的に回避してくれる     ハイパーなマクロ(define-syntax or        (let ([val true])  (syntax-rules ()   ...
健全なマクロ (Hygienic macros)   • 名前の衝突を自動的に回避してくれる     ハイパーなマクロ(define-syntax or        (let ([val true])  (syntax-rules ()   ...
マクロの分類• 高レベル:専用のパターン言語をもつ• 低レベル:Lispの関数でコードを操作する          低レベル                 高レベル不健 • 伝統的なマクロ全健 • syntactic closures  • ...
マクロの分類• 高レベル:専用のパターン言語をもつ• 低レベル:Lispの関数でコードを操作する          低レベル                 高レベル不健 • 伝統的なマクロ全                     >健 • ...
マクロの分類• 高レベル:専用のパターン言語をもつ• 低レベル:Lispの関数でコードを操作する          低レベル                 高レベル不健 • 伝統的なマクロ全            >             ...
 Clojureのマクロシステムとその周辺
Clojureのマクロシステム• 伝統的なマクロがベース                              低レベル                   高レベル                     不               ...
syntax-quote
syntax-quote束縛変数の衝突    自由変数の衝突
syntax-quote束縛変数の衝突                  自由変数の衝突     (defmacro or [expr1 expr2]       `(let [val# ~expr1]          (if val#   ...
syntax-quote束縛変数の衝突                         自由変数の衝突            (defmacro or [expr1 expr2]              `(let [val# ~expr1]...
syntax-quote束縛変数の衝突                           自由変数の衝突              (defmacro or [expr1 expr2]                `(let [val# ~...
syntax-quote        束縛変数の衝突                                自由変数の衝突                        (defmacro or [expr1 expr2]      ...
syntax-quote        束縛変数の衝突                                自由変数の衝突                        (defmacro or [expr1 expr2]      ...
syntax-quote        束縛変数の衝突                                         自由変数の衝突                        (defmacro or [expr1 exp...
メタデータ    •   ほとんどすべてのオブジェクトにメタデータを付加できる    •   Clojureではコードもデータ        →コードのほとんどあらゆる部分にメタデータをアノテー         ションとして付加できる     ...
Java Interop• ClojureからJavaのクラスにアクセスできる• Clojureは大部分がJavaで書かれている• Javaで書かれているClojureのコンパイラ自 体や内部で使われる構文木にも触れる
暗黙の引数 &formと&env• マクロ呼出しのフォームを囲むコンテ キストに関する情報が渡ってくる -   &form:マクロ呼出しのフォーム全体 -   &env:マクロ呼出しの時点で見えて     いるローカル環境
 Clojureマクロの応用例
the オペレータ   http://d.hatena.ne.jp/athos/20120129/THE_operator_in_clojure   •   「型を1つ引数にとり現在のスコープに唯一存       在するその型のオブジェクトを返...
inline assembler マクロ                         http://www.slideshare.net/sohta/shibuyalisp-tt7         • Clojureコンパイラが使うバイトコ...
syntactic-closure                        http://d.hatena.ne.jp/athos/20120506/syntactic_closure_in_clojure•   syntactic cl...
 まとめ• Clojureのマクロ周りには遊べるおも ちゃがたくさん• アイデア次第で貢献できる可能性?• nagoya-lispに参加しましょう
おわり
Upcoming SlideShare
Loading in...5
×

Macros in Clojure

2,227

Published on

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

No Downloads
Views
Total Views
2,227
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
16
Comments
0
Likes
13
Embeds 0
No embeds

No notes for slide

Macros in Clojure

  1. 1.  Macros in Clojure @athos0220
  2. 2. Agenda• Lispマクロ入門• Clojureのマクロとその周辺• Clojureマクロの応用例
  3. 3.  Lispマクロ入門
  4. 4. マクロとは when if = print print = do nilmod 0 "Fizz" "Buzz" mod 0 print print x 15 x 15 "Fizz" "Buzz" (if (= (mod x 15) 0)(when (= (mod x 15) 0) (do (print “Fizz”) (print “Fizz”) (print “Buzz”)) (print “Buzz”)) nil) 構文木を組み替えるための仕組み →自由に構文を作ることができる仕組み
  5. 5. マクロの定義• シンボルやリストで展開形のコードを 作ってやる (when ⃝⃝ (if ⃝⃝ △△ (do △△ ✕✕) ✕✕) nil)
  6. 6. マクロの定義 • シンボルやリストで展開形のコードを 作ってやる (when ⃝⃝ (if ⃝⃝ △△ (do △△ ✕✕) ✕✕) nil)(defmacro when [test & body] (list ’if test (cons ’do body) nil))
  7. 7. マクロの定義 • シンボルやリストで展開形のコードを 作ってやる (when ⃝⃝ (if ⃝⃝ △△ (do △△ ✕✕) ✕✕) nil)(defmacro when [test & body] (defmacro when [test & body] (list ’if `(if ~test test (do ~@body) (cons ’do body) nil) nil))
  8. 8. 名前衝突の問題
  9. 9. 名前衝突の問題束縛変数の衝突 自由変数の衝突
  10. 10. 名前衝突の問題束縛変数の衝突 自由変数の衝突 (defmacro or [expr1 expr2] `(let [val ~expr1] (if val val ~expr2)))
  11. 11. 名前衝突の問題束縛変数の衝突 自由変数の衝突 (defmacro or [expr1 expr2] `(let [val ~expr1] (if val val ~expr2)))(let [val true] (or false val))
  12. 12. 名前衝突の問題束縛変数の衝突 自由変数の衝突 (defmacro or [expr1 expr2] `(let [val ~expr1] (if val val ~expr2)))(let [val true] (or false val))(let [val true] (let [val false] (if val val val))
  13. 13. 名前衝突の問題束縛変数の衝突 自由変数の衝突 (defmacro or [expr1 expr2] `(let [val ~expr1] (if val val ~expr2)))(let [val true] (or false val))(let [val true] (let [val false] (if val val val))
  14. 14. 名前衝突の問題束縛変数の衝突 自由変数の衝突 (defmacro or [expr1 expr2] `(let [val ~expr1] (if val val ~expr2)))(let [val true] (or false val))(let [val true] (let [val false] (if val val val))
  15. 15. 名前衝突の問題束縛変数の衝突 自由変数の衝突 (defmacro or [expr1 expr2] `(let [val ~expr1] (if val val ~expr2)))(let [val true] (let [let nil] (or false val)) (or false true))(let [val true] (let [val false] (if val val val))
  16. 16. 名前衝突の問題束縛変数の衝突 自由変数の衝突 (defmacro or [expr1 expr2] `(let [val ~expr1] (if val val ~expr2)))(let [val true] (let [let nil] (or false val)) (or false true))(let [val true] (let [let nil] (let [val false] (let [val false] (if val (if val val val val)) true))
  17. 17. 名前衝突の問題束縛変数の衝突 自由変数の衝突 (defmacro or [expr1 expr2] `(let [val ~expr1] (if val val ~expr2)))(let [val true] (let [let nil] (or false val)) (or false true))(let [val true] (let [let nil] (let [val false] (let [val false] (if val (if val val val val)) true))
  18. 18. 名前衝突の問題束縛変数の衝突 自由変数の衝突 (defmacro or [expr1 expr2] `(let [val ~expr1] (if val val ~expr2)))(let [val true] (let [let nil] (or false val)) (or false true))(let [val true] (let [let nil] (let [val false] (let [val false] (if val (if val val val val)) true))
  19. 19. 健全なマクロ (Hygienic macros)• 名前の衝突を自動的に回避してくれる ハイパーなマクロ
  20. 20. 健全なマクロ (Hygienic macros) • 名前の衝突を自動的に回避してくれる ハイパーなマクロ(define-syntax or (syntax-rules () ((or expr1 expr2) (let ([val expr1]) (if val val expr2)))))
  21. 21. 健全なマクロ (Hygienic macros) • 名前の衝突を自動的に回避してくれる ハイパーなマクロ(define-syntax or (let ([val true]) (syntax-rules () (or false val)) ((or expr1 expr2) (let ([val expr1]) (if val val expr2)))))
  22. 22. 健全なマクロ (Hygienic macros) • 名前の衝突を自動的に回避してくれる ハイパーなマクロ(define-syntax or (let ([val true]) (syntax-rules () (or false val)) ((or expr1 expr2) (let ([val expr1]) (if val (let ([val true]) val (let ([val_0 false]) expr2))))) (if val_0 val_0 val)))
  23. 23. マクロの分類• 高レベル:専用のパターン言語をもつ• 低レベル:Lispの関数でコードを操作する 低レベル 高レベル不健 • 伝統的なマクロ全健 • syntactic closures • explicit renaming • syntax-rules全 • syntax-case
  24. 24. マクロの分類• 高レベル:専用のパターン言語をもつ• 低レベル:Lispの関数でコードを操作する 低レベル 高レベル不健 • 伝統的なマクロ全 >健 • syntactic closures • explicit renaming • syntax-rules全 • syntax-case
  25. 25. マクロの分類• 高レベル:専用のパターン言語をもつ• 低レベル:Lispの関数でコードを操作する 低レベル 高レベル不健 • 伝統的なマクロ全 > >健 • syntactic closures • explicit renaming • syntax-rules全 • syntax-case
  26. 26.  Clojureのマクロシステムとその周辺
  27. 27. Clojureのマクロシステム• 伝統的なマクロがベース 低レベル 高レベル 不 健 • 伝統的なマクロ 全 >• syntax-quote が特徴 > 健 • syntactic closures • explicit renaming • syntax-rules 全 • syntax-case
  28. 28. syntax-quote
  29. 29. syntax-quote束縛変数の衝突 自由変数の衝突
  30. 30. syntax-quote束縛変数の衝突 自由変数の衝突 (defmacro or [expr1 expr2] `(let [val# ~expr1] (if val# val# ~expr2)))
  31. 31. syntax-quote束縛変数の衝突 自由変数の衝突 (defmacro or [expr1 expr2] `(let [val# ~expr1] (if val# syntax-quote val# ~expr2)))
  32. 32. syntax-quote束縛変数の衝突 自由変数の衝突 (defmacro or [expr1 expr2] `(let [val# ~expr1] (if val# syntax-quote val# ~expr2)))(let [val true] (or false val))
  33. 33. syntax-quote 束縛変数の衝突 自由変数の衝突 (defmacro or [expr1 expr2] `(let [val# ~expr1] (if val# syntax-quote val# ~expr2))) (let [val true] (or false val))(let [val true] (clojure.core/let [val__419__auto__ false] (if val__419__auto__ val__419__auto__ val))#をつけた名前を自動でリネーム (auto-gensym)
  34. 34. syntax-quote 束縛変数の衝突 自由変数の衝突 (defmacro or [expr1 expr2] `(let [val# ~expr1] (if val# syntax-quote val# ~expr2))) (let [val true] (let [let nil] (or false val)) (or false true))(let [val true] (clojure.core/let [val__419__auto__ false] (if val__419__auto__ val__419__auto__ val))#をつけた名前を自動でリネーム (auto-gensym)
  35. 35. syntax-quote 束縛変数の衝突 自由変数の衝突 (defmacro or [expr1 expr2] `(let [val# ~expr1] (if val# syntax-quote val# ~expr2))) (let [val true] (let [let nil] (or false val)) (or false true))(let [val true] (let [let nil] (clojure.core/let [val__419__auto__ false] (clojure.core/let [val__419__auto__ false] (if val__419__auto__ (if val__419__auto__ val__419__auto__ val__419__auto__ val)) true))#をつけた名前を自動でリネーム (auto-gensym) その他の名前にはnamespace名をqualifyする
  36. 36. メタデータ • ほとんどすべてのオブジェクトにメタデータを付加できる • Clojureではコードもデータ →コードのほとんどあらゆる部分にメタデータをアノテー ションとして付加できる 名前をnamespaceにプライベートにする (defn ^:private f [x] x) (def ^:dynamic x nil)動的スコープの変数にする 戻り値と引数の型ヒント (defn fact ^long [^long x] (if (= x 0) 1 (* x (fact (- x 1)))))
  37. 37. Java Interop• ClojureからJavaのクラスにアクセスできる• Clojureは大部分がJavaで書かれている• Javaで書かれているClojureのコンパイラ自 体や内部で使われる構文木にも触れる
  38. 38. 暗黙の引数 &formと&env• マクロ呼出しのフォームを囲むコンテ キストに関する情報が渡ってくる - &form:マクロ呼出しのフォーム全体 - &env:マクロ呼出しの時点で見えて いるローカル環境
  39. 39.  Clojureマクロの応用例
  40. 40. the オペレータ http://d.hatena.ne.jp/athos/20120129/THE_operator_in_clojure • 「型を1つ引数にとり現在のスコープに唯一存 在するその型のオブジェクトを返す演算子」 by @kinaba • &envを使って、そのスコープで見えている変 数のうち、指定した型がメタデータに付いて いるものを拾ってくる(let [^File _ (File. "foo.txt") ^FileReader __ (FileReader. (the File)) ^BufferedReader ___ (BufferedReader (the FileReader))] (.readLine (the BufferedReader)))
  41. 41. inline assembler マクロ http://www.slideshare.net/sohta/shibuyalisp-tt7 • Clojureコンパイラが使うバイトコード 生成ライブラリをマクロ展開時に使う(def fact public final java.lang.Object invoke(java.lang. (fn-iasm [n] Code: (aload_1) Stack=2, Locals=6, Args_size=2 (checkcast Integer) 0: aload_1 (invokevirtual ^int Integer/intValue []) 1: checkcast #25; //class java/lang/I (istore_2) 4: invokevirtual #29; //Method java/lang/ (iconst_1) 7: istore_2 (istore_3) 8: iconst_1 :loop 9: istore_3 (iload_2) 10: iload_2 (ifeq :end) 11: ifeq 24 (ilaod_2) 14: iload_2 (iload_3) 15: iload_3 (imul) 16: imul (istore_3) 17: istore_3 (iinc 2 -1) 18: iinc 2, -1 (goto :loop) 21: goto 10 :end 24: iload_3 (iload_3) 25: invokestatic #33; //Method java/lang/ (invokestatic ^Integer Integer/valueOf [int]) 28: areturn (areturn)))
  42. 42. syntactic-closure http://d.hatena.ne.jp/athos/20120506/syntactic_closure_in_clojure• syntactic closuresによる健全なマクロを定義で きるようにするライブラリ 低レベル 高レベル• syntax-quoteで定義できない 不 健 全 • 伝統的なマクロ ある種のマクロが定義可能に • syntactic closures(define-syntax or [expr1 expr2] 健 • explicit renaming • syntax-rules 全 • syntax-case (sc-macro-transformer (fn [env] (quasiquote (let [val ~(make-syntactic-closure env nil expr1)] (if val val ~(make-syntactic-closure env nil expr2)))))))(let [val true] (let [val true] (or false val)) (let [val396 false] (if val396 val396 val))
  43. 43.  まとめ• Clojureのマクロ周りには遊べるおも ちゃがたくさん• アイデア次第で貢献できる可能性?• nagoya-lispに参加しましょう
  44. 44. おわり
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×