在Clojure宏中取消引用列表
我尝试定义一个宏以从特殊形式的文本中提取信息, [0 => "0n"]
,实际上它是Clojure中的一个列表。
现在让我们说我只是想用宏get-input
来获得它的first
部分。
(println (get-input [0 => "0n"])) ; i.e. 0
下面的一个工作得很好。
; this works
(defmacro get-input
[expr]
(let [input (first expr)]
input))
但是当我使用Syntax-Quote ,即反引用时 ,事情变得混乱。 只要用~
表示expr
引导我这样做。 实际上,我从来没有使用过expr
的second
部分,即=>
,但似乎仍然在后面进行评估。
CompilerException java.lang.RuntimeException:在此上下文中无法解析符号:=>
; this sucks
(defmacro get-input
[expr]
`(let [input# (first ~expr)]
input#))
我想知道第一个解决方案和第二个解决方案之间有什么区别。
宏在编译时被扩展,宏的主体被评估。 如果它是语法引用的,则只计算未加引号的表达式,但如果没有引号(如在第一个宏定义中那样),则在编译时计算正文。
如果用第一个定义(无引号)展开(get-input [0 => "0n"])
),您将拥有
> (macroexpand '(get-input [0 => "0n"]))
0
0
是宏扩展的结果,意味着所有对(get-input [0 => "0n"])
调用在编译时将被替换为0
。
随着第二个定义的扩展将是类似的(生成的符号将不同)
> (macroexpand '(get-input [0 => "0n"]))
(let* [input__11966__auto__ (first [0 => "0n"])]
input__11966__auto__)
扩展之后,Clojure编译器将评估向量[0 => "0n"]
,正如clojure文档所述:
向量,集合和映射产生向量和(散列)集合和映射,其内容是它们包含的对象的估计值。
向量的每个元素都按顺序评估,对于0
(评估为0),但不适用于=>
,这不是已知的符号。
可能你正在寻找的是扩展表达式(在你的情况下是矢量),而不对其内容进行评估。 为此,您需要quote
~
的结果,例如
(defmacro get-input-as-str
[expr]
`(let [a# (quote ~expr)]
(map str a#)))
它们扩展到 - 注意'[...]
:
> (macroexpand '(get-input-as-str [0 => "0n"]))
(let* [a__12040__auto__ '[0 => "0n"]] (map str a__12040__auto__))
并给予
> (get-input-as-str [0 => "0n"])
("0" "=>" "0n")
你会得到这个异常,因为你试图取消[0 => "0n"]
表单,这不是一个有效的Clojure代码。 您可以通过更改first
和非引用操作的顺序来修复它:
(defmacro get-input
[expr]
`(let [input# ~(first expr)]
input#))
链接地址: http://www.djcxy.com/p/65767.html