Joh*_*han 1 macros reference common-lisp
考虑一下这段代码:
(defvar lst '(1 1))
(defmacro get-x (x lst)
`(nth ,x ,lst))
(defun get-y (y lst)
(nth y lst))
Run Code Online (Sandbox Code Playgroud)
现在让我们假设我想要更改名为lst的列表元素的值,使用get-x的car和使用get-y的cdr.当我尝试用get-x(使用setf)更改值时,一切都很顺利但是如果我用get-y尝试它会发出错误信号(缩短):
; 陷入STYLE-WARNING:; 未定义的功能:(SETF GET-STUFF)
为什么会这样?
我自己也怀疑,这是因为宏只是展开和函数第n简单地返回到列表中,并在另一方面,功能元素的值的参考评估函数调用到第n和返回参考价值的价值(听起来令人困惑).
我的怀疑是否正确?如果我是正确的,那么如何知道什么只是对价值和实际价值的引用?
宏版本不会发生错误,因为正如您所假设的那样,表达式(setf (get-x some-x some-list) some-value)将(在编译时)扩展为类似的东西(setf (nth some-x some-list) some-value)(不是真的,但是-expansion 的细节setf很复杂),并且编译器知道,如何处理它(即,有一个合适的setf扩展器为功能定义nth).
但是,在这种情况下get-y,编译器没有setf扩展器,除非你提供一个.最简单的方法是
(defun (setf get-y) (new-value x ls) ; Note the function's name: setf get-y
(setf (nth x ls) new-value))
Run Code Online (Sandbox Code Playgroud)
注意,有关setf-expanders 的一些约定:
setf函数的第一个参数提供setf函数都应该返回新值作为结果(因为这是整个setf表单应该返回的内容)顺便说一下,在Common Lisp中没有像"参考"那样的概念(至少在C++意义上没有),尽管曾经有Lisp方言有定位.广义位置表单(即,setf及其机制)与普通C++样式引用的工作方式完全不同.如果您对细节感到好奇,请参阅CLHS.