Макросы возвращают список, который затем оценивается в пространстве имен, из которого он вызывается, а не в пространстве имен, в котором он определен. Это отличается от функций, которые оценивают в пространстве имен, в котором они были определены.Это , потому что макросы возвращают код для запуска, а не просто запускают его.
, если я иду в другое пространство имен, например hello.core
, и расширяю вызов до следующей даты.get:
hello.core> (macroexpand-1 '(next-date weeks 2))
(weeks 2)
затем после расширения недели разрешаются из hello.core, в котором он, конечно, не определен.чтобы исправить это, нам нужен возвращаемый символ для переноса информации о пространстве имен.
к счастью, вы можете явно разрешить символ в пространстве имен с помощью ns-resolve
. . Требуется пространство имен исимвол и пытается найти его в пространстве имен, возвращая ноль, если он не найден
(ns-resolve 'clj-time.core (symbol "weeks"))
#'clj-time.core/weeks
следующий ваш макрос будет принимать символ и число, чтобы мы могли обойтись без явного вызова symbol
(ns-resolve 'clj-time.core 'weeks)
#'clj-time.core/weeks
, так что теперь вам просто нужна функция, которая разрешает функцию, а затем создает список разрешенных функций с последующим номером,
(defmacro next-date [interval freq]
(list (ns-resolve 'clj-time.core interval) freq))
В приведенном выше макросе все, что он делает, это делаетвызов функции, который вызывается немедленно, поэтому вам даже не нужен макрос для этого:
(defn next-date [interval freq]
((ns-resolve 'clj-time.core interval) freq))
(next-date 'weeks 2)
#<Weeks P2W>
не-макро версия требует, чтобы вы указали интервал, потому что он не должен оцениваться перед вами.могу посмотреть.То, что макрос действительно покупает здесь, не включает в себя кавычку, а требует от всех вызывающих абонентов требовать clj-time
. Конечно, вы также можете просто требовать clj-time везде, но это не совсем так.точка.