在Clojure宏中,如何强制自动名称相同?
我正在编写一些Clojure宏,我想在enlive html宏之上使用它们。现在,我需要编写一个宏,在这样使用时:在Clojure宏中,如何强制自动名称相同?,clojure,Clojure,我正在编写一些Clojure宏,我想在enlive html宏之上使用它们。现在,我需要编写一个宏,在这样使用时: (macroexpand-1 '(def-app [ [:page/not-found [{path :path}] [:path] (content path)] [:page/other-page [{x :x}] [:x] (content x)]])) …将扩展到: (def app ^:dynamic {}) (def-page
(macroexpand-1 '(def-app
[ [:page/not-found [{path :path}]
[:path] (content path)]
[:page/other-page [{x :x}]
[:x] (content x)]]))
…将扩展到:
(def app ^:dynamic {})
(def-page app
[:page/not-found [{path :path}]
[:path] (content path)])
(def-page app
[:page/other-page [{x :x}]
[:x] (content x)])
我的尝试是:
(defmacro def-app [pages]
`(do
(def app# ^:dynamic {})
~@(for [page# pages]
`(def-page app# ~page#))))
…其扩展到:
(do (def app__3251__auto__ {})
(user/def-page app__3250__auto__ [:page/not-found [{path :path}] [:path] (content path)])
(user/def-page app__3250__auto__ [:page/other-page [{x :x}] [:x] (content x)]))
…除了两件事外,这几乎没什么问题:
谢谢
gensym
s使用#
创建,仅在创建它们的语法引号中可重用。要重用生成的符号,可以使用显式调用,如下所示:
(defmacro def-app [pages]
(let [app (gensym "app")]
`(do
(def ~app ^:dynamic {})
~@(for [page# pages]
`(def-page ~app ~page#)))))
这也扩大了:
(do (def app22770 {})
(user/def-page app22770 [:page/not-found [{path :path}] [:path] (content path)])
(user/def-page app22770 [:page/other-page [{x :x}] [:x] (content x)]))
接下来,^:dynamic
丢失,因为读取器宏^:
是在宏扩展编译器阶段之前读取的。将函数或与meta一起使用
生成动态var:
(defmacro def-app [pages]
(let [app (gensym "app")]
`(do
(def ~(vary-meta app merge {:dynamic true}) {})
~@(for [page# pages]
`(def-page ~app ~page#)))))
;; => user/app23239
我们可以看到,生成的var是动态的:
(meta (var app23239))
;; => {:dynamic true (...) }