Clojure

Макросы

У Clojure есть программная система макросов, которая позволяется компилятору расширять пользовательский код. Макросы могут быть использованы для определения синтаксических конструкций, которые требовали бы примитивов или втроенной поддержки в других языках программирования. Многие ключевые конструкции в Clojure на самом деле являются не примитивами, а макросами.

Некоторые макросы производят простые комбинации форм-примитивов. Например, when соединяет if и do:

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