Передача карты функций в макрос - PullRequest
6 голосов
/ 28 апреля 2011

У меня есть макрос, который будет реализовывать интерфейс Java, который является слушателем. Я определил макрос, чтобы взять карту, содержащую функции, которые я хочу разложить, и использовать для каждого из методов интерфейса. Это макрос: -

(defmacro with-cache-listener-m [component event body]
   (let [{:keys [f-insert f-update]} body]
     `(. ~component addMapListener
     (proxy [AbstractMapListener] []
       (entryInserted [~event] ~f-insert ~event)
       (entryUpdated [~event] ~f-update ~event)))))

Карта тела выглядит так: -

(def m-callbacks {:f-insert callback-insert :f-update callback-update})

Но когда я звоню (macroexpand '(with-cache-listener-m test-cache e m-callbacks)), оно расширяется до (. test-cache user/addMapListener (clojure.core/proxy [com.tangosol.util.AbstractMapListener] [] (user/entryInserted [e] nil e) (user/entryUpdated [e] nil e)))

Функции обратного вызова - ноль. Нужно ли мне определять их по-другому или я поступаю неправильно?

Ответы [ 2 ]

4 голосов
/ 28 апреля 2011

Когда вы вызываете макрос with-cache-listener-m, аргумент body ограничивается символом 'm-callbacks, поэтому при попытке деструктурировать этот локальный var он не будет работать, потому что это не карта.Вы можете позволить полученной форме выполнять работу следующим образом:

(defmacro with-cache-listener-m [component event body]
  `(let [{:keys [f-insert# f-update#]} ~body]
     (. ~component addMapListener
        (proxy [AbstractMapListener] []
          (entryInserted [~event] f-insert# ~event)
          (entryUpdated [~event] f-update# ~event)))))

Но в конце я не уверен, что вашему коду нужен макрос, вы пытались написать его как функцию:

(defn add-map-listener [component insert-fn update-fn]
  (.addMapListener component
    (proxy [AbstractMapListener] []
      (entryInserted [e] (insert-fn e))
      (entryUpdated [e] (update-fn e)))))

Как вы видели, я изменил пару вещей:

  • Сделав имя функции более понятным, ваш макрос не был действительно похож на другие макросы с - *, которые обычно оценивают некоторый код (body) в каком-то особом контексте.
  • Удалил аргумент события, так как казалось, что он не имеет никакого смысла.
  • Сделал аргументы insert-fn и update-fn явными дляупростить пример.
  • Использовал новый метод, вызывающий синтаксис.
  • Исправлены методы прокси для фактического использования данных функций.

Если вы хотите сделать функцииполностью необязательный и дает возможность быть заданным в любом порядке, вы всегда можете сделать это:

(defn add-map-listener [component & functions]
  (let [{:keys [insert-fn update-fn]} (into {} functions)]
    (when-not (empty? functions)
      (.addMapListener component 
        (proxy [AbstractMapListener] []
          (entryInserted [e] (insert-fn e))
          (entryUpdated [e] (update-fn e)))))))

Обратите внимание, что я добавил код, чтобы не вызывать addMapListener, когда функции не заданы.

1 голос
/ 28 апреля 2011

Макросы не являются функциями: они знают только о буквальных формах, переданных им во время компиляции.Если вы присвоите значение, скажем, 10, переменной x, а затем передадите макросу x, он увидит не 10, а x.Ваш макрос, вероятно, будет работать нормально, если вместо def ing m-callbacks и затем передать этот символ, вы просто передадите карту непосредственно как литерал.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...