2016-03-12 2 views
1

Я использую CIDER, если это имеет значение.Macroexpanded form оценивает, но исключает исключение формы исключений

(defmacro trace [prompt x] 
    (let [p (subs prompt 4) 
     expanded (macroexpand x)] 
    (cond (seq? expanded) `(do (println ~p '~x "...") 
           (let [result ~(map #(if (or (not (symbol? %)) (function? %)) 
                (list 'trace (join [prompt prompt]) %) 
                %) expanded)] 
           (println ~p result "->" ~expanded)) 
           ~expanded) 
      :else expanded))) 

Это макрос, над которым я работаю, но это не должно иметь значения (хотя, вероятно, это так).

Это конкретный фрагмент кода, который вызывает проблему

(trace " " (if true 6 4)) 

Оценки этого прямыми броски исключение:

Can't let qualified name: clj-match.trace/result 

Я macroexpanded формы для отладки, и я получил это:

(do 
    (println "" '(if true 6 4) "...") 
    (let* [result (if true 6 4)] (println "" result "->" (if true 6 4))) 
    (if true 6 4)) 

Это не выглядит плохо, поэтому я попытался оценить расширенную форму. Неожиданно это сработало, оценив до 6.

Почему это происходит?

Что еще более важно, что я делаю неправильно, чтобы получить исключение?

+0

@Elogent о, извините, я не копировал последнюю строку макроса. Теперь исправлено – phil

ответ

3

Второй вопрос: вы получаете исключение, потому что вы действительно пытаетесь присвоить let квалифицированное имя, в частности clj-match.trace/result.

Это происходит потому, что ваш синтаксис цитируемого (do …) формы, что макрос расширяется в в seq? случае использует result как имя локального связывания в let формы она производит. Этот буквальный символ result будет определяться читателем пространством имен, поскольку он встречается внутри формы с синтаксисом, и поэтому конечный результат будет (let [clj-match.trace/result …] …), что неверно (имена привязок let не должны иметь пространство имен). Вы можете использовать result#, чтобы избежать этого, или явно указать gensym символ за пределами формы с синтаксисом и не использовать его.

(Кстати, вы можете синтаксически цитаты, а не просто цитата, ваш trace символа расширения для того, чтобы убедиться, что он на самом деле относится к макросу, независимо от контекста, в котором расширение происходит.)

Что касается вашего эксперимента с расширением макроса - обычный вызов macroexpand-1 с вашей формой в качестве аргумента выявит выше, поэтому предположительно вы использовали какое-либо средство, предоставляемое CIDER или другим пакетом Emacs, чтобы расширить его встроенный? Может быть, это средство как-то плохо.

+0

Вы правы, что я использовал CIDER для макроэкспонирования.Это должно быть ошибка с ними. – phil

2

Макрос чтения расширяет все символы внутри своего тела, чтобы определить пространство имен.

user=> (macroexpand `(let [a 0] a)) 
(let* [user/a 0] user/a) 

user/a не является действительной местной привязкой.

Решение состоит в использовании функции gensym shorthand.

user=> (macroexpand `(let [a# 0] a#)) 
(let* [a__3__auto__ 0] a__3__auto__) 

Это труднее для человека, чтобы читать, но на самом деле генерирует действительный код.

Смежные вопросы