Clojure оценка макросов - PullRequest
7 голосов
/ 26 марта 2011

У меня проблема с созданием DSL в Clojure. Это конкретная проблема, которую я изолировал от всего остального.

Допустим, у нас есть простой макрос:

user> (defmacro m1 [x] `'~x)
#'user/m1 

он просто возвращает предоставленный литерал пользователь> (m1 toUpperCase) toUpperCase

если мы вызываем Java-метод для объекта, все работает как положено

user> (. "a" toUpperCase)
"A"

но если подставить имя метода для вызова макроса, который возвращает имя метода

user> (. "a" (m1 toUpperCase))

; Evaluation aborted.
Unable to resolve symbol: toUpperCase in this context

Я хочу использовать некоторую библиотеку Java, которая имеет свободный интерфейс, такой как a (). B (). C (). Это сопоставляется с Clojure как:

(.. obj method1 method2 method3....etc)

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

(.. obj method1 macro1)

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

(.. obj method1 method2 method3)

определение также не помогает. Я попробовал это также

1 Ответ

6 голосов
/ 27 марта 2011

Причина, по которой вы столкнулись с этой проблемой, заключается в том, что. специальная форма не оценивает свой второй аргумент (символ, определяющий метод или поле) так, как вы ожидаете: она видит его как вызов МЕТОДА m1 с аргументом ARGUMENT toUppercase Из-за этого вы не можете генерировать символ для метода динамически, просто как аргумент. (точка) - даже если вы используете макрос для указания этого аргумента.

Способ обойти это - включить. в вашем макросе:

 (defmacro m1 [x y] `(. ~x (~y)))
 (m1 "a" toUppercase)
 user> "A"

Обратите внимание, что вам нужно заключить в скобки ~ y, чтобы указать, что вы хотите вызвать метод вместо чтения поля.

...