我正在学习 Clojure 宏,代码示例有时会有结构'~symbol
或交替~'symbol
。我知道(quote
并'
防止对表单进行评估,并且反引号还添加了命名空间限定,并且 ~ 导致对带引号的表单进行评估。我的问题是:为什么停止然后开始评估有用?我也假设~'symbol
和'~symbol
是不同的,但怎么会呢?
问问题
3600 次
2 回答
33
~'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
'~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
于 2012-08-14T19:53:32.577 回答
6
~
是unquote
函数的读取器宏。在带引号的列表中,它会导致评估符号而不是用作文字符号
user> (def unquoted 4)
user>`(this is an ~unquoted list)
(user/this user/is user/an 4 clojure.core/list)
user>
除了 unquoted 符号之外的所有东西都被用作 unquoted 被解析为其值 4 的符号。这最常用于编写宏。repl 在打印结果列表时还会打印名称前面的名称空间(用户)。
许多宏基本上只是模板,旨在对函数中无法完成的事情进行一些细微的变化。在这个人为的例子中,模板宏通过调用 def 来定义一个函数。带取消引用的语法引用使这更容易阅读:
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
相比:
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>
在第二个示例中,我也没有使用 auto-gensyms 功能,因为我不在语法引用中
于 2012-08-14T19:12:07.240 回答