Избегание захвата символов при использовании макросов для генерации функций (или других макросов) - PullRequest
4 голосов
/ 28 мая 2010

Я немного сбит с толку относительно того, когда именно будет происходить захват символов с помощью макросов clojure. Предположим, у меня есть макрос, который определяет функцию из ключевых слов. В этом тривиальном примере

(defmacro foo [keywd1 keywd2] `(defn ~(symbol (name keywd1)) 
                  [~(symbol (name keywd2))] (* 2 ~(symbol (name keywd2))))) 

Я звоню (foo: bar: baz), и это расширяется в (defn bar [baz] (* 2 baz)).

Итак, теперь вопрос - может ли это привести к захвату символов? Если да, то при каких обстоятельствах? Я знаю, что для предотвращения захвата символов предпочтительнее использовать gensym (например, bar #), но в некоторых случаях (не так много, но все же) я хотел бы иметь довольно макроразложение без автоматически генерируемых символов.

Бонусный вопрос: изменится ли ответ, если мы рассмотрим макрос, который создает макросы?

1 Ответ

4 голосов
/ 28 мая 2010

В вашем примере захват символов не происходит, потому что укажите переменные части в качестве параметров. Таким образом, разработчик может выбирать имена самостоятельно.

Захват символов происходит, когда ваш макрос вводит новые локальные объекты, которые не указаны пользователем. Рассмотрим следующий (действительно глупый и бессмысленный пример):

(defmacro foo
  [name & body]
  `(defn ~name
     [~'bar]
     (println ~'bar)
     ~@body))

В этом случае панель захвачена. Теперь предположим, что у пользователя есть такой код:

(def bar 5)
(foo baz (* 2 bar))
(baz 7)

Это не дало бы того, чего можно было бы ожидать. Поскольку глобальная панель, пользователь, ссылающийся на, получает тень от локальной панели, представленной макросом Как вы уже сказали: в этом случае нужно использовать бар # для введения локального.

Так что захват всегда обозначается ~ '. Макрос написание макросов ничего не меняет. Просто добавьте еще один уровень: ~~ '.

...