Макрос Clojure протокола сборки - PullRequest
1 голос
/ 20 июня 2011

Как продолжение моего предыдущего вопроса , я пытаюсь написать макрос, который создает defprotocol:

(build-protocol AProtocol
  [(a-method [this]) (b-method [this that])]
  (map (fn [name] `(~(symbol (str name "-method")) [~'this ~'that ~'the-other]))
    ["foo" "bar" "baz"])
  (map (fn [name] `(~(symbol (str name "-method")) [~'_]))
    ["hello" "goodbye"]))

должно расшириться до

(defprotocol AProtocol
  (a-method [this])
  (b-method [this that])
  (foo-method [this that the-other])
  (bar-method [this that the-other])
  (baz-method [this that the-other])
  (hello-fn [_])
  (goodbye-fn [_]))

Моя попытка:

(defmacro build-protocol [name simple & complex]
  `(defprotocol ~name ~@simple
     ~@(loop [complex complex ret []]
         (if (seq complex)
           (recur (rest complex) (into ret (eval (first complex))))
           ret))))

и расширение (macroexpand-1 '(...)):

(clojure.core/defprotocol AProtocol
  (a-method [this])
  (b-method [this that])
  (foo-method [this that the-other])
  (bar-method [this that the-other])
  (baz-method [this that the-other])
  (hello-method [_])
  (goodbye-method [_]))

Я не очень доволен eval. Кроме того, выражения map довольно уродливы. Есть ли способ лучше? Любые комментарии приветствуются.

Как только я получу эту работу, я собираюсь сделать аналогичный макрос для (build-reify ...). Я пишу довольно большое Swing-приложение, в котором есть несколько компонентов (JButton s, JCheckBox es и т. Д.), Которые имеют практически идентичные сигнатуры и действия методов.

1 Ответ

2 голосов
/ 20 июня 2011

Я думаю, вы делаете это с ног на голову.Сначала укажите материал "-method", завернутый в какой-то контейнер, чтобы build-protocol знал, что к чему, и позволил ему делать карту внутри макроса.например:

(build-protocol AProtocol
  {[this that whatever] [foo bar baz],
   [_] [hello goodbye]}
  ; a-method and b-method...
)
...