我想一个列表传递给Lisp的功能,并且在函数内部改变该列表中的内容,而不会影响原有的列表中。 我读过Lisp是传递的价值,这是真的,但有别的事情上,我不太明白。 例如,该代码按预期工作:
(defun test ()
(setf original '(a b c))
(modify original)
(print original))
(defun modify (n)
(setf n '(x y z))
n)
如果调用(测试),它打印(ABC),即使(修改)的回报(XYZ)。
但是,如果你试图改变只是名单的一部分,它不工作的方式。 我认为这事做与具有相同的内容是在内存中随处可见或类似的东西,同样的名单? 下面是一个例子:
(defun test ()
(setf original '(a b c))
(modify original)
(print original))
(defun modify (n)
(setf (first n) 'x)
n)
然后(测试)打印(XBC)。 那么,如何改变一个列表参数的一些元素的功能,因为如果该列表是局部的功能?
SETF修改的地方 。 n
可以是一个地方。 列表中的第一个元素n
点,也可以是一个地方。
在这两种情况下,通过召开列表original
被传递到modify
其参数n
。 这意味着, original
在功能test
和n
在功能modify
现在持有相同的列表,这意味着,无论original
和n
现在指向它的第一个元素。
SETF修改后n
在第一种情况下,它不再指向该列表,而是一个新的列表。 清单指向original
不受影响。 新的列表,然后通过返回modify
,但由于该值未分配到任何东西,它淡出存在,并且将很快被垃圾收集。
在第二种情况下,修改SETF不n
,但该列表的第一个元素n
点。 这是相同的列表original
点,所以,后来,你也可以看到通过这个变量修改的列表。
为了复制一个列表,使用COPY-LIST 。
Lisp的列表是基于利弊细胞。 变量等指针缺点细胞(或其它的Lisp对象)。 改变某个变量将不会改变其他变量。 更改利弊细胞会在那里有那些利弊细胞引用的所有地方可见。
一本好书是Touretzky, Common Lisp的:一个温柔的介绍符号计算 。
还有,吸引名单和利弊细胞的树木软件。
如果你传递一个列表,这样的功能:
(modify (list 1 2 3))
然后,你有三种不同的方式使用的列表:
利弊细胞的破坏性变形
(defun modify (list)
(setf (first list) 'foo)) ; This sets the CAR of the first cons cell to 'foo .
结构共享
(defun modify (list)
(cons 'bar (rest list)))
上述返回在列表中通过共享结构的列表:其余的元素都在这两个列表相同。
仿形
(defun modify (list)
(cons 'baz (copy-list (rest list))))
上述功能BAZ类似的酒吧,但没有列表的细胞是共享的,由于该表被复制。
不用说,破坏性的修饰通常应避免,除非有真正的理由这样做(如保存内存时,它是值得的)。
笔记:
从来没有破坏性修改常量列表
不 '做(让((L'(ABC)))(SETF(第l)“吧))
原因:该列表可以被写保护,或者可以与其他列表(由编译器布置)被共享等。
也:
引入变量
像这样
(let ((original (list 'a 'b 'c)))
(setf (first original) 'bar))
或像这样
(defun foo (original-list)
(setf (first original-list) 'bar))
从来没有SETF未定义的变量。
这几乎是相同的这个例子在C:
void modify1(char *p) {
p = "hi";
}
void modify2(char *p) {
p[0] = 'h';
}
在这两种情况下,指针传递,如果你改变了指针,你改变指针值的参数拷贝(它的堆栈上),如果你改变的内容,你改变任何对象的值指出。
你可能有问题,因为即使Lisp是通过按值对对象的引用被传递,就像Java或Python。 你的缺点单元包含修改,所以你修改原件和当地一个引用。
海事组织,你应该尝试写功能更实用的风格,以避免此类问题。 尽管Common Lisp是多范型多功能风格是一个比较合适的方式。
(defun定义修改(N)(利弊“×(CDR n))的
文章来源: In common-lisp, how do I modify part of a list parameter from within a function without changing the original list?