user=> (macroexpand '(when (pos? a) (println "positive") (/ b a)))
(if (pos? a) (do (println "positive") (/ b a)))
У Clojure есть программная система макросов, которая позволяется компилятору расширять пользовательский код. Макросы могут быть использованы для определения синтаксических конструкций, которые требовали бы примитивов или втроенной поддержки в других языках программирования. Многие ключевые конструкции в Clojure на самом деле являются не примитивами, а макросами.
user=> (macroexpand '(when (pos? a) (println "positive") (/ b a)))
(if (pos? a) (do (println "positive") (/ b a)))
Другие макросы переставляют формы в удобном порядке, например макрос ->
, который рекурсивно вставляет каждое выражение как первый аргумент следующего выражения.
user=> (-> {} (assoc :a 1) (assoc :b 2))
{:b 2, :a 1}
user=> (macroexpand '(-> {} (assoc :a 1) (assoc :b 2)))
(assoc (clojure.core/-> {} (assoc :a 1)) :b 2)
Для удобства внутри defmacro доступно две специальные переменные:
&form
- исходная исполняемая форма (в виде данных)
&env
- соответствие локальных привязок в точке вызова макроса. Это соответствие символов и объектов содержащее информацию компилятора о этой связи.
Все следующие макросы описаны на странице API. Многие уже были упомянуты на указанных страницах:
Макросы создания: defmacro definline macroexpand-1 macroexpand
Ветвление: and or when when-not when-let when-first if-not if-let cond condp
Циклы (см. также Последовательности): for doseq dotimes while
Работа с переменнымт (см. также Переменные и глобальное окружение): ns declare defn defmacro definline defmethod defmulti defn- defonce defstruct
Различные преобразования кода: .. doto ->
Динамические переменные (см. также Переменные и глобальное окружение): binding locking time with-in-str with-local-vars with-open with-out-str with-precision
Создание ленивых объектов (см. также Последовательности): lazy-cat lazy-cons delay
Макросы Взаимодействие с Java: .. amap areduce gen-class gen-interface proxy proxy-super memfn
Документирование кода: assert comment doc
Транзакции: dosync io!
Несколько специальных форм на самом деле реализованы как макросы, прежде всего подерживающие реструктуризирующее присваивание: fn let loop