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

Ale*_*lex 24 macros clojure

我正在学习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)


Art*_*ldt 6

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