我正在学习Clojure宏,代码示例有时会包含构造'~symbol
或者~'symbol
。我知道(quote
和'
会阻止对表单进行求值,并且反引号还会添加名称空间限定,并且〜会导致对引用的表单进行求值。我的问题是:为什么停止然后开始评估是有用的?我还假设~'symbol
和'~symbol
不同,但是如何呢?
答案 0 :(得分: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
'~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
答案 1 :(得分:6)
~
是unquote
函数的读者宏。在引用列表中,它会导致符号被评估,而不是用作文字符号
user> (def unquoted 4)
user>`(this is an ~unquoted list)
(user/this user/is user/an 4 clojure.core/list)
user>
除了未加引号的符号之外的所有内容都被用作符号,其中未加引号被解析为其值4.这是最常用于编写宏。 repl还打印命名空间(用户)infront打印结果列表时的名称。
许多宏,基本上只是模板,旨在对一些无法在函数中完成的事情做一些微小的变化。在这个人为的例子中,模板宏通过产生对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>
在第二个例子中,我也没有使用自动gensyms功能,因为我没有使用语法引用