Расширение Clojure Macro - PullRequest
3 голосов
/ 13 мая 2011

Я работаю над макросом, я пытаюсь выяснить, как избежать раскрытия определенных форм, возьмите следующее и макрос, например,


(defmacro and
  ([] true)
  ([x] x)
  ([x & next]
   `(let [and# ~x]
      (if and# (and ~@next) and#))))

Когда развернуто,

(mexpand-all '(and 1 2 3))

становится,


(let* [and__973__auto__ 1]
      (if and__973__auto__
        (let* [and__973__auto__ 2]
              (if and__973__auto__ 3 and__973__auto__))
        and__973__auto__))

В этом случае мне нужно остановить прекращение расширения в let *.

Ответы [ 3 ]

5 голосов
/ 13 мая 2011

А? Непонятно, что вы подразумеваете под "стопом" let расширения. let - это макрос, определенный в clojure.core, о котором компилятор ничего не знает: он понимает только let*. Если ваш макрос расширился до let, который (каким-то образом) отказался расширяться дальше, он не сможет скомпилироваться.

Если вы хотите проверить только вывод вашего макроса изолированно, не беспокоясь о его рекурсивном расширении, вы должны использовать macroexpand или macroexpand-1 вместо этого mexpand-all. Я не знаю, откуда взялась mexpand-all, но когда мне нужно что-то подобное, я использую clojure.walk/macroexpand-all.

4 голосов
/ 13 мая 2011

Рекурсивное макро-расширение работает путем многократного расширения формы, пока нет макроса для расширения.Это означает, что если вы хотите рекурсивно развернуть макрос, но игнорировать определенные формы, вам придется либо написать свой собственный расширитель, либо найти чужой.

Вот краткий пример:

(defn my-expander [form]
    (cond (not (list? form)) (mexpand-1 form)
        (= (first form) 'let) form
           :else (map my-expander (mexpand-1 form))))

Пожалуйста, прости меня, если я допустил какие-либо ошибки.Я гораздо сильнее со Схемой и CL, чем с Clojure.

- Правка-- Обратите внимание, что вышеприведенная функция также не будет расширять подчиненные формы оператора let.

1 голос
/ 13 мая 2011

Используйте macroexpand-1 для выполнения одного уровня расширения макроса.

После загрузки макроса and это выражение:

user=> (macroexpand-1 '(and 1 2 3))

Выход:

(clojure.core/let [and__1__auto__ 1] (if and__1__auto__ (clojure.core/and 2 3) and__1__auto__))
...