我正在尝试将列表传递给Lisp中的函数,并在函数内更改该列表的内容,而不会影响原始列表.我已经读过Lisp是按值传递的,这是真的,但还有其他事情我不太明白.例如,此代码按预期工作:
(defun test ()
(setf original '(a b c))
(modify original)
(print original))
(defun modify (n)
(setf n '(x y z))
n)Run Code Online (Sandbox Code Playgroud)
如果你调用(测试),即使(修改)返回(xyz),它也会打印(abc).
但是,如果您尝试仅更改列表的一部分,则无法正常工作.我认为这与列表中的内容在内存中相同或者类似的内容有关?这是一个例子:
(defun test ()
(setf original '(a b c))
(modify original)
(print original))
(defun modify (n)
(setf (first n) 'x)
n)Run Code Online (Sandbox Code Playgroud)
然后(测试)打印(xbc).那么如何更改函数中list参数的某些元素,就好像该列表是该函数的本地列表一样?
lisp function common-lisp parameter-passing pass-by-reference
我现在已经了解了数组和arefLisp.到目前为止,它很容易掌握,它就像一个魅力:
(defparameter *foo* (make-array 5))
(aref *foo* 0) ; => nil
(setf (aref *foo* 0) 23)
(aref *foo* 0) ; => 23
Run Code Online (Sandbox Code Playgroud)
令我百思不解的是aref"神奇"当你把这种情况发生aref和setf.似乎aref知道它的调用上下文,然后决定是否返回一个值或一个可以使用的地方setf.
无论如何,目前我只是认为这是理所当然的,并且不要考虑内部工作方式太多.
但是现在我想创建一个将*foo*数组元素设置为预定义值的函数,但是我不想对*foo*数组进行硬编码,而是想要移交一个地方:
(defun set-23 (place)
…)
Run Code Online (Sandbox Code Playgroud)
所以基本上这个函数集放置到23,任何地方.我最初的天真的方法是
(defun set-23 (place)
(setf place 23))
Run Code Online (Sandbox Code Playgroud)
并使用以下方式调用:
(set-23 (aref *foo* 0))
Run Code Online (Sandbox Code Playgroud)
这不会导致错误,但也不会发生任何变化*foo*.我的猜测是aref解析的调用nil(因为数组当前是空的),所以这意味着
(setf nil 23)
Run Code Online (Sandbox Code Playgroud)
运行,但是当我在REPL中手动尝试时,我收到一个错误告诉我:
NIL是常量,不能用作变量
(这绝对有道理!)
所以,最后我有两个问题:
set-23功能发挥作用?我也有想法使用thunk来推迟执行aref,就像: …
我想将引用(指针)保存到我保存在另一个变量中的某些数据的一部分:
(let ((a (list 1 2 3)))
(let ((b (car (cdr a)))) ;here I want to set b to 2, but it is set to a copy of 2
(setf b 4))
a) ;evaluates to (1 2 3) instead of (1 4 2)
Run Code Online (Sandbox Code Playgroud)
我可以使用宏,但如果我想在列表中间更改一些数据并且我不是很灵活,那么将会有很多代码要执行:
(defparameter *list* (create-some-list-of-arrays))
(macrolet ((a () '(nth 1000 *list*)))
(macrolet ((b () `(aref 100 ,(a))))
;; I would like to change the macro a here if it were possible
;; but then b would mean something …Run Code Online (Sandbox Code Playgroud) 考虑一下这段代码:
(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和返回参考价值的价值(听起来令人困惑).
我的怀疑是否正确?如果我是正确的,那么如何知道什么只是对价值和实际价值的引用?