передать список макросам в Common Lisp - PullRequest
2 голосов
/ 20 июня 2019

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

(defmacro gen (str-lst)
  `(defun ,(intern (string-upcase (car str-lst))) () (print "foo")))

(gen '("foo" "bar"))

Полученная ошибка:

*** - DEFUN / DEFMACRO: QUOTE является специальным оператором и не может быть переопределен. Доступны следующие перезапуски: ABORT: R1
Прервать основной цикл

Как мне изменить мой код и что не так с моим кодом?

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

(defmacro easy-one (str-lst)
  `(mapc #'(lambda (str) (print str)) ,str-lst))
(easy-one '("foo" "bar"))

1 Ответ

7 голосов
/ 20 июня 2019

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

(gen ("foo" "bar"))

Когда вы цитируете это, вы выполняете

(get (quote ("foo" "bar")))

Значение str-list - это список (quote ("foo" "bar")), поэтому (car str-list) - это символ QUOTE. В результате макрос расширяется до

(defun quote () (print "foo"))

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

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

(mapc #'(lambda (str) (print str)) '("foo" "bar")))

Здесь список будет использоваться при запуске расширения, а не при расширении макроса. Его нужно заключить в кавычки, чтобы он не оценивался как вызов функции.

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

...