Этот ответ не столько о Clojure, сколько о Lisp и макросах в целом.
Помните:
APPLY позволяет вызывать функции со списками аргументов, которые создаются во время выполнения.
Существуют макросы для генерации нового исходного кода из некоторого исходного кода - и сгенерированный исходный код будет работать.
Сейчас:
Если вы разрешите применять для подачи другого исходного кода в макрос во время выполнения, необходимо иметь возможность генерировать код результата во время выполнения, а также выполнять сгенерированный код.
Таким образом, в скомпилированной системе Lisp каждый вызов APPLY с макросом потенциально создает новый код, который должен быть скомпилирован во время выполнения, чтобы иметь возможность его выполнить. Это также означает, что вы можете получить новые ошибки компилятора во время выполнения, когда ваш код выполняется, и у кода есть некоторые проблемы. Поэтому для ПРИМЕНЕНИЯ макросов во время выполнения вам необходим компилятор и вся необходимая информация (например, другие макросы), чтобы иметь возможность расширять и компилировать код.
Это также означает, что в общем случае вы не можете скомпилировать APPLY с макросом до времени выполнения, так как неизвестно, какие аргументы времени выполнения будут применены.
В Lisp на основе интерпретатора может быть больше информации, и макросы можно применять постоянно.
В раннем Лиспе были обычные функции и так называемые FEXPR. FEXPR позволяли гибко управлять вызовами и манипулировать кодом во время выполнения. Позже в истории Lisp они были заменены макросами, так как макросы обеспечивают эффективную компиляцию, а в системах на основе компилятора позволяют обрабатывать синтаксические ошибки перед выполнением.