Сплайсинг-кавычка для не-литеральных последовательностей - PullRequest
2 голосов
/ 05 января 2011

Этот вопрос основан на ограничении этот ответ .

Если у меня есть макрос, который использует кавычки со сращиванием, как это:

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

Это будет работать только в том случае, если values является литеральной последовательностью или последовательной.

Если передается переменная, содержащая последовательность вроде:

(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 ]

2 голосов
/ 05 января 2011

Макросы получают свои аргументы без оценки, поэтому поведение, которое вы видите, соответствует назначению.

Макросы раскрываются во время компиляции, а не во время выполнения.Значения любых переменных, передаваемых в макрос, могут быть недоступны во время компиляции, поэтому грязные хаки, такие как использование eval, не будут работать в общем случае.Не создавайте макросы, которые требуют таких уловок.

1 голос
/ 05 января 2011

сращивание кавычек экономит много времени почти во всех случаях, кроме случаев, когда они не работают, тогда вам нужно делать вещи старомодным способом ...

(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)
...