Принудительное расширение выражения внутри макроса Clojure - PullRequest
2 голосов
/ 19 июня 2011

Я пытаюсь использовать макрос do-template Стюарта внутри defprotocol, и компилятор Clojure жалуется, что я переопределяю do-template - не то, что я намереваюсь:

(defprotocol AProtocol
  (a-method [_])
  (do-template [name]
    `(~(symbol (str name "-method")) [this that])
    foo
    bar
    baz))

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

(defprotocol AProtocol
  (a-method [_])
  (foo-method [this that])
  (bar-method [this that])
  (baz-method [this that]))

Проблема (я полагаю) состоит в том, что s-выражение do-template передается defprotocol без расширения.Есть ли способ заставить его оценить перед передачей?

Кстати, do-template должен фактически расшириться до

(do
  (foo-method [this that])
  (bar-method [this that])
  (baz-method [this that]))

, но я уже пробовал это (с версией, дополненной вручную)и defprotocol хорошо с вложенным do.

Как я могу увидеть фактическое расширение do-template?Я попробовал оба (macroexpand '(do-template ...)) и (macroexpand-1 '(do-template ...)) и получил:

(do (clojure.core / seq (clojure.core / concat (clojure.core / list (symbol (str foo) -метод)"))) (clojure.core / list (clojure.core / apply clojure.core / vector (clojure.core / seq (clojure.core / concat (clojure.core / list (цитирую пользователя / this))) (clojure.core/ list (указать пользователя / что)))))))) (clojure.core / seq (clojure.core / concat (clojure.core / list (symbol (str bar "-method"))) (clojure.core /list (clojure.core / apply clojure.core / vector (clojure.core / seq (clojure.core / concat (clojure.core / list (цитирую пользователя / это)) (clojure.core / list (цитирую пользователя / это)))))))) (clojure.core / seq (clojure.core / concat (clojure.core / list (symbol (str baz "-method")))) (clojure.core / list (clojure.core / применить clojure.core / vector (clojure.core / seq (clojure.core / concat (clojure.core / list (цитирует пользователя / это))) (clojure.core / list (цитирует пользователя / это)))))))))

Не совсем легко читать: -).

Кроме того, я, вероятно, хочу, чтобы this и that были анафорами и разверните к себе: ~'this.

1 Ответ

3 голосов
/ 19 июня 2011

(1) defprotocol не подходит для формы do. Это не вызывает ошибку, но это также не работает.

(2) Вы не можете делать то, что хотите, таким образом. defprotocol - это вызываемый макрос, поэтому он имеет абсолютные полномочия относительно того, как раскрываются подформы.

(3) Пункт (2) предлагает решение, фактически такое же, как и по крайней мере один из ваших недавних вопросов: определите новый макрос, скажем with-methods, который принимает список имен методов, за которыми следует любой другой аргументы defprotocol и расширяются до defprotocol с соответствующими заменами и уже выполненными соединениями, так что defprotocol может расширяться в спокойной обстановке без необходимости что-либо знать о вашей уловке do-template.

...