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))))
答案 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))