[2011-12-01 00:49:57]
(EmacsAdventCalendarにしようと思ってたけど納得いかなかったからやめたのは秘密)
OnLisp読んでてちょっとずつマクロがわかってきたのでEmacsLispを読む時の参考になればいいかなと.
Lispは記号が少なくて,リストの先頭は関数やからめっちゃ読みやすいんやけど,そうじゃないマクロとか,「,@」とか「,」,「`」「'」「#'」とかが入ってくると混乱します.
クォートで読み取りのモードが変わる
Lispの漫画(Casting SPELLs in lisp)読んでなるほどなーと思った考え方を紹介します.
まずLispのプログラムは全部リストで,Lispのコンパイラがそのリストを読み進める時はcode-modeとdata-modeの二つがあるんです.
Lispコンパイラは基本的にcode-modeで読み進めていくけど,'(quote)がついてる括弧の中はdata-modeに切り替えて読み進めるんです.この考え方個人的に驚いて感動しました.それだけです.
(setf *objects* '(whiskey bucket frog chain) )
この例だと,「(setf *objects*」と「)」の部分がcode-modeで,「'(whiskey bucket frog chain)」がdata-modeなんですね.
code-modeで読んでる時はそのリストの先頭を関数として,残りの要素を引数にして呼び出しますが,data-modeの時はデータなのでまるごと一つのオブジェクトとして扱うんです.
マクロで記号が増える
ところでクォートすると次の二つは同じです.
'(a b c) (list 'a 'b 'c)
なのでマクロ書いてて(list 'a b 'c)みたいに二つ目は評価するようにマクロを展開してほしいとなると困る訳です.
ここまでの話やとdata-mode(クォートの中)の中では関数もデータとして扱われちゃうから.
そこでバッククォートとコンマがでてきます.バッククォートだけやとクォートと同じです.
'(a b c) (list 'a 'b 'c) `(a b c) ;; 3つとも(a b c)
コンマつけると変わってきます.次の二つは同じです.
`(a ,b c) (list 'a b 'c)
bが評価されるんですね.実際にdefmacro読んでみるとします.(emacs lisp にも clojure の ->> が欲しいよね - 水底で思うことより)
(defmacro my:flip (f a b) `(,f ,b ,a))
これはfもaもbもコンマがついてるのでそれぞれ評価されるのでこうなりますね.
(my:flip f a b) ;=> (f b a) (my:flip concat "hoge" "fuga") ;=> "fugahoge"
,@
あともうひとつの記号は「,@」ですね.これは評価するときに括弧をとっちゃいます.いい例がなくて意味わからんけどこんな感じです.
(defmacro my:concat (a) `(concat ,@a)) (my:concat ("hoge" "fuga")) ;=> "hogefuga"
(my:concat ("hoge" "fuga"))が(concat "hoge" "fuga")に展開されるんですね.ここで@をつけてないと普通に置き換えるだけになっちゃうので(concat ("hoge" "fuga"))になっちゃいます.
なにを言いたかったのかわからなくなってきたのでこの辺でおわります.意味不明ですみません.
On Lisp --- マクロを読むとよくわかります.