Сохранение имен символов аргумента в макросе - PullRequest
2 голосов
/ 03 декабря 2011

Одним из упражнений в книге Пола Грэхама ANSI Common Lisp является следующее: Определите макрос, который принимает список переменных и тело кода и гарантирует, что переменные вернутся к своим исходным значениям после того, как тело кода будет оценено.

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

(defmacro save-run (varlist &body body)
  `(let ((valuelist (list ,@varlist)))
    (format t "valuelist: ~A" valuelist)))

(let ((a 5)(b 6))
  (values '(a b))
  (save-run (a b) 
        (setf a 7)
        (setf b 8)))

[507]> valuelist: (5 6)

Edit: вот решение, в котором переменные сохраняются, а затем восстанавливаются (используя советы из finnw ниже). Но затенение переменных, как в ответе Ватина, возможно, более элегантно.

(defmacro save-run (varlist &body body)
  `(let ((valuelist (list ,@varlist)))
     ,@body
     (multiple-value-setq ,varlist (values-list valuelist))))

Ответы [ 3 ]

3 голосов
/ 03 декабря 2011

Чтобы получить список символов, все, что вам нужно сделать, это процитировать содержимое VARLIST:

(defmacro save-run (varlist &body body)
  `(let ((namelist ',varlist)
         (valuelist (list ,@varlist)))
    (format t "namelist: ~A~%" namelist)
    (format t "valuelist: ~A~%" valuelist)))

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

Также вы можете захотеть использовать GENSYM вместо жестко заданного имени переменной VALUELIST:

(defmacro save-run (varlist &body body)
  (let ((valuelist (gensym)))
    `(let ((,valuelist (list ,@varlist)))
       ,@body
       (setf (values ,@varlist) (values-list ,valuelist)))))
2 голосов
/ 03 декабря 2011

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

У вас есть список переменных в varlist, поэтому что-то вроде этого может работать:

(defmacro save-run (varlist &body body)
  `(let ,(loop for var in varlist
               collect (list var var))
     ,@body))
1 голос
/ 04 декабря 2011

Мне очень понравился подход Ватина. Вот реализация, которая расширяется до того же кода, но использует mapcar вместо макроса цикла:

(defmacro save-run (varlist &body body)
  `(let ,(mapcar #'list varlist varlist)
     ,@body))
...