在Clojure宏中引用基于〜和〜@的选择

时间:2014-12-19 03:31:53

标签: macros clojure

我有两个不同的Clojure宏,但基于操作(〜@和〜),我需要引用输入或不引用。

(defmacro make2 [t]
  `(list 1 ~@t)) 

(defmacro make3 [t]
  `(list 1 ~t))

(make2 (1 2 3)) -> (1 1 2 3)

(make3 '(1 2 3)) -> (1 (1 2 3))

这是为什么?我可以猜测,使用宏,不会评估参数(这就是为什么make2不会导致错误)。但是在获得参数之后,我不确定处理它们的逻辑。

1 个答案:

答案 0 :(得分:2)

(macroexpand-1 '(make2 (1 2 3)))
;; ==> (clojure.core/list 1 1 2 3)

(macroexpand-1 '(make3 (1 2 3)))
;;==> (clojure.core/list 1 (1 2 3))

~@将列表(1 2 3)拼接到表达式(list 1 ...)中,然后计算结果表达式,即使用参数list计算函数1 1 2 3。 Clojure会评估每个参数,但当然,数字会自行评估。

~只需将参数(1 2 3)插入(list 1 ...)作为其第二个参数,然后评估整个表达式,同时评估每个参数list。当它发生时,Clojure看到第二个参数中有一对未加引号的括号,并假设左括号后面的第一个表达式是一个函数(或宏)。也就是说,Clojure假设1的内部实例是一个函数,它不是。这就是你得到例外的原因

ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn ...

表示长整数不能转换为函数。