当我阅读Clojure的喜悦时,我遇到了一些代码。
(fn [~'key ~'r old# new#]
(println old# " -> " new#)
此声明〜'some-symbol 的确切行为是什么。
某些符号#和'~aother-symbol或gensym?
之间的区别Clojure的喜悦:(不明白)
你会在Clojure中看到模式〜'符号 用于有选择地捕获符号名称的宏 宏。这种尴尬[11]的原因是Clojure的 syntax-quote尝试解析当前上下文中的符号, 产生完全合格的符号。因此,〜'避免这种情况 通过不引用引用来解决问题。
答案 0 :(得分:5)
您可以在图尔佩图书馆中看到the Literate Threading Macro的示例。我们希望用户键入符号it
并让宏识别它。这是定义:
(defmacro it->
"A threading macro like as-> that always uses the symbol 'it'
as the placeholder for the next threaded value "
[expr & forms]
`(let [~'it ~expr
~@(interleave (repeat 'it) forms)
]
~'it))
这也被称为“照应”宏。然后用户创建如下代码:
(it-> 1
(inc it) ; thread-first or thread-last
(+ it 3) ; thread-first
(/ 10 it) ; thread-last
(str "We need to order " it " items." ) ; middle of 3 arguments
;=> "We need to order 2 items." )
用户在其代码中包含特殊符号it
,宏正在期待(在这种情况下是必需的)。
这是一个特例。在大多数情况下,无论用户选择什么符号,您都希望宏工作。这就是为什么大多数宏使用(gensym...)
或带有“#”后缀的阅读器版本,如下例所示:
(defmacro with-exception-default
"Evaluates body & returns its result. In the event of an exception, default-val is returned
instead of the exception."
[default-val & body]
`(try
~@body
(catch Exception e# ~default-val)))
这是“正常”情况,其中宏创建“局部变量”e#
,保证不与任何用户符号重叠。一个类似的示例显示spyx
宏创建一个名为spy-val#
的“局部变量”,以暂时保存评估表达式expr
的结果:
(defmacro spyx
"An expression (println ...) for use in threading forms (& elsewhere). Evaluates the supplied
expression, printing both the expression and its value to stdout, then returns the value."
[expr]
`(let [spy-val# ~expr]
(println (str (spy-indent-spaces) '~expr " => " (pr-str spy-val#)))
spy-val#))
请注意,对于(println...)
语句,我们会看到'~expr
的相反语法 - 但这是另一天的主题。