我正在学习Clojure宏,代码示例有时会有构造'~symbol
或交替~'symbol
.我知道这一点,(quote
并'
阻止对表单进行评估,并且反引号还添加了名称空间限定,并且〜导致引用的表单被评估.我的问题是:为什么停止然后开始评估是有用的?我也认为~'symbol
并且'~symbol
不同,但是如何呢?
Bey*_*mor 31
~'symbol
用于产生不合格的符号.默认情况下,Clojure的宏捕获命名空间,因此宏中的符号通常会被解析为(your-namespace/symbol)
.unquote-quote成语直接导致简单的,不合格的符号名称(symbol)
- 通过评估引用的符号.来自Clojure的喜悦:
(defmacro awhen [expr & body]
`(let [~'it ~expr] ; refer to the expression as "it" inside the body
(when ~'it
(do ~@body))))
(awhen [:a :b :c] (second it)) ; :b
Run Code Online (Sandbox Code Playgroud)
'~symbol
很可能用于在宏或类似的东西中插入名称.在这里,symbol
将绑定一个值 - let [symbol 'my-symbol]
.然后通过评估将该值插入宏生成的代码中symbol
.
(defmacro def-symbol-print [sym]
`(defn ~(symbol (str "print-" sym)) []
(println '~sym))) ; print the symbol name passed to the macro
(def-symbol-print foo)
(print-foo) ; foo
Run Code Online (Sandbox Code Playgroud)
~
是该unquote
函数的读者宏.在引用列表中,它会导致符号被评估,而不是用作文字符号
user> (def unquoted 4)
user>`(this is an ~unquoted list)
(user/this user/is user/an 4 clojure.core/list)
user>
Run Code Online (Sandbox Code Playgroud)
除了未加引号的符号之外的所有内容都被用作符号,其中未引用的符号被解析为其值4.这通常用于编写宏.repl还会在打印结果列表时打印名称前面的名称空间(用户).
许多宏,基本上只是模板设计用于对函数中无法完成的一些细微变化.在这个人为的例子中,模板宏通过产生对def的调用来定义函数.使用unquoting的语法引用使这更容易阅读:
user> (defmacro def-map-reducer [name mapper reducer]
`(defn ~name [& args#]
(reduce ~reducer (map ~mapper args#))))
#'user/def-map-reducer
user> (def-map-reducer add-incs inc +)
#'user/add-incs
user> (add-incs 1 2 3 4 5)
20
Run Code Online (Sandbox Code Playgroud)
相比:
user> (defmacro def-map-reducer [name mapper reducer]
(let [args-name (gensym)]
(list `defn name [`& args-name]
(list `reduce reducer (list `map mapper args-name)))))
#'user/def-map-reducer
user> (def-map-reducer add-decs dec +)
#'user/add-decs
user> (add-decs 1 2 3 4 5)
10
user>
Run Code Online (Sandbox Code Playgroud)
在第二个例子中,我也不使用auto-gensyms功能,因为我没有使用语法引用