Clojureでマクロ を学習中
- 作者: Bruce A. Tate,まつもとゆきひろ,田和勝
- 出版社/メーカー: オーム社
- 発売日: 2011/07/23
- メディア: 単行本(ソフトカバー)
- 購入: 9人 クリック: 230回
- この商品を含むブログ (65件) を見る
- 作者: Stuart Halloway,川合史朗
- 出版社/メーカー: オーム社
- 発売日: 2010/01/26
- メディア: 単行本(ソフトカバー)
- 購入: 10人 クリック: 338回
- この商品を含むブログ (72件) を見る
マクロを勉強中。 unlessをマクロで定義する簡単な例。その後、テンプレートエンジンを使うような感じで、プログラムを書くプログラムの例が進み、マクロの分類の話が出てきた。分類の話は、On Lispをちょっと思い出し、軽く7章に目を通した。
unlessについて。関数にできなくて、マクロに出来ることの1つとしては、引数の評価を遅らせられるか否かがある。unlessはその例になっている。
testを評価してfalseのときのみ、bodyが評価されるのが、unlessの期待する振る舞いとなる。
(defmacro unless [test body] (list 'if test nil body)) (unless false (println "print")) ; #=> "print" (unless true (println "not print")) ; # =>
下2行の実行結果になるのは、マクロ定義のところで、unlessのリストを、 if のリストに展開し直すようになっているため。
Ruby目線でマクロをいろいろ考えたが、マクロしか出来ないことあるんだなと、再認識。
Rubyのブロックも評価を遅らせられる点では似ている。が、マクロと違って、いろいろ制約(ブロック要素は1つ)があるので、my_unlessの構文をつくることはできないはず。(my_unlessをメソッド定義するには、testとbodyの2つブロック要素を渡し、testを評価して falseのときのみ、 bodyを評価したいが、渡せるブロックは1つ)。
ERBの様なテンプレートを使って生成したコードを eval すれば、似たことが出来るんじゃねと思ったが、それでは、呼び出し側の引数 testと body を文字列で渡すことになるのでいまいち。
無名の関数オブジェクトを test, bodyとして、引数に渡す時点では評価せず。。。、と考えたが、これも呼び出し側が,少々不格好になる。
関数やメソッドでは、この新しい構文をうまく、つくれない。ふむふむ。
def my_unless(test, body) if test.call() else body.call() end end my_unless ->{ false }, -> do puts "print HOGE" end unless false puts "hogehoge" end
ちなみに、Rubyの場合は既に unless、Clojureには、when-notの構文があらかじめ用意されている。
「unless」の構文で マクロのことを悩む必要はない。