макрос lisp расширяется с частичным eval - PullRequest
1 голос
/ 01 июля 2011

У меня следующий код, который меня сейчас смущает, надеюсь, кто-нибудь подскажет мне разницу и как это исправить.

(defmacro tm(a)
   `(concat ,(symbol-name a)))

(defun tf(a)
       (list (quote concat) (symbol-name a)))

Я просто думаю, что они должны иметь одинаковый эффект, но на самом деле они кажутся не такими.
Я пытаюсь следующий звонок:

CL-USER> (tf 'foo)
(CONCAT "FOO")

CL-USER> (tm 'foo)
value 'FOO is not of the expected type SYMBOL.
[Condition of type TYPE-ERROR]

Итак, в чем проблема?

То, что я хочу, это:

(tm 'foo)  ==>  (CONCAT "FOO")

Ответы [ 2 ]

4 голосов
/ 01 июля 2011

Первая проблема заключается в том, что читатель расширяет 'foo до (quote foo), который является не символом, а списком. Макрос пытается развернуть (tm (quote foo)). Список (quote foo) передается в качестве параметра a в функцию расширения макроса, которая пытается получить ее symbol-name. Список не является допустимым аргументом для symbol-name. Следовательно, расширение макроса завершается неудачей.

Вторая проблема состоит в том, что хотя (tm foo) (примечание: без кавычек) расширяет до (concat "FOO"), эта форма будет затем выполняться REPL, так что это также не то же самое, что ваша tf функция. Конечно, это неудивительно, потому что макросы выполняют разные функции, чем функции.

2 голосов
/ 01 июля 2011

Во-первых, обратите внимание, что

`(concat ,(symbol-name a))

и

(list (quote concat) (symbol-name a))

делают одно и то же.Они являются эквивалентными частями кода (синтаксис обратной цитаты не ограничен телами макросов!): Оба создают список, первым элементом которого является символ CONCAT, а вторым элементом является имя символа любой переменной, на которую ссылается A.

Понятно, что это имеет смысл, только если A относится к символу, который, как указал Сванте, не так в примере с вызовом макроса.

You может, конечно, извлечь символ из списка (QUOTE FOO), но это не позволяет вам вызывать макрос следующим образом:

(let ((x 'foo))
  (tm x))

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

Во-вторых, макрос работает следующим образом: они принимают фрагменты кода (например, (QUOTE FOO)) в качестве аргументов исоздать новый фрагмент кода, который после макроразложения (более или менее) заменяет вызов макроса в исходном коде.Часто полезно повторно использовать аргументы макроса в сгенерированном коде, помещая их туда, где они будут оцениваться позже, например, в

(defmacro tm2 (a)
  `(print (symbol-name ,a)))

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

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

...