Проблема в том, что a
это просто символ во время компиляции. Поэтому у макроса во время компиляции нет возможности увидеть, что он содержит, и выполнить необходимое расширение. В результате вам нужно развернуть макрос во время выполнения, используя eval .
Один из способов сделать это - просто обернуть макрос в функцию, которая вызывает eval, что можно сделать с помощью этого удобного макроса «functionize»:
(defmacro functionize [macro]
`(fn [& args#] (eval (cons '~macro args#))))
(let [a [true]] (apply (functionize and) a))
=> true
Если хотите, вы также можете определить apply-macro в терминах functionize:
(defmacro apply-macro [macro args]
`(apply (functionize ~macro) ~args))
(let [a [true false]] (apply-macro and a))
=> false
Сказав все это, я все же думаю, что лучше всего избегать макросов полностью, когда они на самом деле не нужны: они добавляют дополнительную сложность и лучше всего зарезервированы для случаев, когда вам действительно нужна генерация кода времени компиляции. В этом случае вы не: Ответ Алекса Таггарта дает хороший пример того, как достичь аналогичной цели без каких-либо макросов, что, вероятно, более подходит в большинстве ситуаций.