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

Macros 在宏中保存参数的符号名称,macros,common-lisp,Macros,Common Lisp,Paul Grahams ANSI Common Lisp书中的一个练习是:定义一个宏,该宏接受一个变量列表和一个代码体,并确保在对代码体求值后变量恢复为其原始值 我在这个练习中遇到的问题是如何保存输入变量的符号名。下面我有一个开始,我只保存符号绑定到的值 (defmacro save-run (varlist &body body) `(let ((valuelist (list ,@varlist))) (format t "valuelist: ~A" valuelis

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的提示)。但在梵蒂娜的回答中隐藏变量可能更优雅

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

要获取符号列表,只需引用
VARLIST
的内容即可:

(defmacro save-run (varlist &body body)
  `(let ((namelist ',varlist)
         (valuelist (list ,@varlist)))
    (format t "namelist: ~A~%" namelist)
    (format t "valuelist: ~A~%" valuelist)))
(defmacro save-run (varlist &body body)
  (let ((valuelist (gensym)))
    `(let ((,valuelist (list ,@varlist)))
       ,@body
       (setf (values ,@varlist) (values-list ,valuelist)))))
然而,我怀疑这在最终定义中不会有用。在运行时,您无法对符号列表进行太多处理。相反,请在宏展开中寻找插入列表的好位置

此外,您可能希望使用
GENSYM
而不是硬编码变量名
VALUELIST

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

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

您在
varlist
中有一个变量列表,因此类似的方法可能会起作用:

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

我真的很喜欢梵蒂娜的方法。下面是一个扩展为相同代码的实现,但使用mapcar而不是loop宏:

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

很好,我不知道你可以这样组合引号和逗号。对不起,我应该说不要使用名称列表,你需要值列表。我的错。我喜欢它,比保存和恢复更优雅。你不需要
(progn,@body)
。只要
,@body
也会有同样的效果。如果您使用
(setf(values,@varlist)…)
而不是
(multiple value setq,varlist…)
那么一些变量可以是符号以外的位置,例如
(save run((cdr x))…)
不确定您在这里的意思。我查看了文档,setf只能接受偶数个成对分配的参数,而不是列表。