拼接非文字序列的非引号

时间:2011-01-05 17:33:16

标签: macros clojure

此问题基于this answer的限制。

如果我有一个使用拼接unquote的宏,请执行以下操作:

(defmacro instantiate [klass values] 
        `(new ~klass ~@values))

仅当values是文字序列或seq-able时才会起作用。

如果传递了一个包含如下序列的var:

(def v [1 2 3]) 
(macroexpand '(instantiate Person v))

然后输出将是一个错误,表明v不是序列。

即使函数调用也会被解释为列表:

(defn vf [] [1 2 3])
(macroexpand '(instantiate Person (vf)))
user=>(new Person vf)

我的问题是:在那两个要拼接的序列不是文字的情况下,有没有办法在Clojure宏中使用拼接取消引用?

2 个答案:

答案 0 :(得分:2)

宏接收的参数未经评估,因此您看到的行为符合预期。

宏在编译时扩展,而不是在运行时扩展。传递给宏的任何变量的值可能在编译时不可用,因此使用eval之类的脏操作在一般情况下将不起作用。不要创建需要这些技巧的宏。

答案 1 :(得分:1)

拼接引号在几乎所有情况下都节省了很多时间,除非它们不工作,那么你需要用老式的方式做事......

(defmacro instantiate [klass values] 
    `(new ~klass ~@values))

可能会成为

(defmacro instantiate [klass values] 
    (concat (list 'new klass) (if (seq? values) 
                                  values 
                                  (list values))))

user=> (macroexpand '(instantiate asdf (1 2 3)))
(new asdf 1 2 3)

user=>  (macroexpand '(instantiate asdf 1))
(new asdf 1)