在Clojure中〜或'〜的目的是什么?

时间:2012-08-14 19:07:35

标签: clojure macros

我正在学习Clojure宏,代码示例有时会包含构造'~symbol或者~'symbol。我知道(quote'会阻止对表单进行求值,并且反引号还会添加名称空间限定,并且〜会导致对引用的表单进行求值。我的问题是:为什么停止然后开始评估是有用的?我还假设~'symbol'~symbol不同,但是如何呢?

2 个答案:

答案 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功能,因为我没有使用语法引用