普通Lisp,参考值和实际值 [英] Common Lisp, reference to value and actual value

查看:103
本文介绍了普通Lisp,参考值和实际值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑这段代码:

(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:

  1. 新值始终作为setf函数的第一个参数提供
  2. 所有setf函数都应返回新值作为其结果(这就是整个setf表单应返回的形式)
  1. The new value is always provided as the first argument to the setf function
  2. All setf functions are supposed to return the new value as their result (as this is, what the entire setf 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆