普通Lisp,参考值和实际值 [英] Common Lisp, reference to value and actual value
问题描述
考虑这段代码:
(defvar lst '(1 1))
(defmacro get-x (x lst)
`(nth ,x ,lst))
(defun get-y (y lst)
(nth y lst))
现在让我们假设我想更改名为 lst 的列表元素的值,该列表使用 get-x 的 car 和 cdr 和 get-y . 当我尝试使用 get-x (使用 setf )更改值时,一切正常,但是如果我尝试使用 get-y 进行更改,则表示错误(缩短):
Now let us assume that I want to change the value of the elements of the list called lst, the car with get-x and the cdr with get-y. As I try to change the value with get-x (with setf) everything goes fine but if I try it with get-y it signals an error (shortened):
;捕获的样式警告: ;未定义的函数:(SETF GET-STUFF)
; caught STYLE-WARNING: ; undefined function: (SETF GET-STUFF)
为什么会这样?
我本人怀疑发生这种情况是因为宏只是扩展而函数 nth 仅返回对列表中元素值的引用,而函数则对函数调用进行求值到 nth 并返回参考值的值(声音令人困惑).
I myself suspect that this happens because the macro simply expands and the function nth simply returns a reference to the value of an element in the list and the function on the other hand evaluates the function-call to nth and returns the value of the referenced value (sounds confusing).
我猜对了吗? 如果我是正确的,那么人们将如何知道仅是对值和实际值的引用?
Am I correct in my suspicions? If I am correct then how will one know what is simply a reference to a value and an actual value?
推荐答案
宏版本不会发生错误,因为正如您所假设的,表达式(setf (get-x some-x some-list) some-value)
将被扩展(在编译时)为类似(setf (nth some-x some-list) some-value)
(不是真的,但是 setf
-扩展很复杂),并且编译器知道如何处理(即,为函数nth
定义了一个合适的setf
扩展器).
The error does not happen with the macro version, because, as you assumed, the expression (setf (get-x some-x some-list) some-value)
will be expanded (at compile-time) into something like (setf (nth some-x some-list) some-value)
(not really, but the details of setf
-expansion are complex), and the compiler knows, how to deal with that (i.e., there is a suitable setf
expander defined for function nth
).
但是,对于get-y
,编译器没有setf
扩展器,除非您提供扩展器.最简单的方法是
However, in the case of get-y
, the compiler has no setf
expander, unless you provide one. The easiest way to do so would be
(defun (setf get-y) (new-value x ls) ; Note the function's name: setf get-y
(setf (nth x ls) new-value))
请注意,关于setf
-扩展器有一些约定:
Note, that there are a few conventions regarding setf
-expanders:
- 新值始终作为
setf
函数的第一个参数提供 - 所有
setf
函数都应返回新值作为其结果(这就是整个setf
表单应返回的形式)
- The new value is always provided as the first argument to the
setf
function - All
setf
functions are supposed to return the new value as their result (as this is, what the entiresetf
form is supposed to return)
顺便说一句,在Common Lisp中没有引用"的概念(至少在C ++中不是这样),尽管曾经有Lisp方言具有定位.通用场所形式(即setf
及其机器)的工作方式与普通C ++样式引用非常不同.如果您对详细信息感到好奇,请参阅CLHS.
There is, BTW, no such concept as a "reference" in Common Lisp (at least not in the C++ sense), though there once were Lisp dialects which had locatives. Generalized place forms (ie., setf
and its machinery) work very differently from plain C++ style references. See the CLHS, if you are curious about the details.
这篇关于普通Lisp,参考值和实际值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!