IK.AM

@making's tech note


Clojureのdefmacroで強制的にシンボル捕捉させる

🗃 {Programming/Lisp/Clojure}
🗓 Updated at 2010-02-25T18:22:45Z  🗓 Created at 2010-02-25T18:22:45Z   🌎 English Page

Clojureはマクロ定義内のシンボルを名前空間で修飾する。シンボル束縛を回避するためであり、バグを防いでくれるが、次のような書き方をしたいときはNG。

(defmacro foo [x]
  `(defn ~x [x]
     x))
user> (macroexpand-1 '(foo aaa))
(clojure.core/defn aaa [user/x] user/x)                                                                                              
user> (foo aaa)

Can't use qualified name as parameter: user/x [Thrown class java.lang.Exception]

シンボル束縛を強制的に行うためには~'をつける。

(defmacro foo [x]
  `(defn ~x [~'x]
     ~'x))
user> (macroexpand-1 '(foo aaa))
(clojure.core/defn aaa [x] x)                                                                                                        
user> (foo aaa)
#'user/aaa                                                                                                                           
user> (aaa 100)
100

使うときは要注意。
尤も、このケースでは(gensym)を使うべきなのだが。。。

→ (追記:2010/03/03)Clojureはマクロ内で使うシンボルの末尾に「#」をつければ勝手にgensymしてくれます。

user> (defmacro foo [x] `(defn ~x [x#] x#))
#'user/foo
user> (macroexpand-1 '(foo aaa))
(clojure.core/defn aaa [x__4956__auto__] x__4956__auto__)

✒️️ Edit  ⏰ History  🗑 Delete