在宏中保存参数的符号名称

时间:2011-12-02 22:13:03

标签: macros common-lisp

Paul Grahams 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)

编辑:这是一个解决方案,保存并恢复变量(使用下面的finnw提示)。但是像Vatine的答案那样遮蔽变量可能更优雅。

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

3 个答案:

答案 0 :(得分:3)

要获取符号列表,您需要做的就是引用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)))))

答案 1 :(得分:2)

就个人而言,我会为我们要保存的变量引入另一个绑定层。

你有varlist中的变量列表,所以这样的事情可能有效:

(defmacro save-run (varlist &body body)
  `(let ,(loop for var in varlist
               collect (list var var))
     ,@body))

答案 2 :(得分:1)

我真的很喜欢Vatine的做法。这是一个扩展为相同代码的实现,但使用mapcar而不是循环宏:

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