在共口齿不清,我怎么修改列表参数的一部分,在一个函数中,而不改变原来的名单?(In common-l

2019-07-19 18:56发布

我想一个列表传递给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)。 那么,如何改变一个列表参数的一些元素的功能,因为如果该列表是局部的功能?

Answer 1:

SETF修改的地方n可以是一个地方。 列表中的第一个元素n点,也可以是一个地方。

在这两种情况下,通过召开列表original被传递到modify其参数n 。 这意味着, original在功能testn在功能modify现在持有相同的列表,这意味着,无论originaln现在指向它的第一个元素。

SETF修改后n在第一种情况下,它不再指向该列表,而是一个新的列表。 清单指向original不受影响。 新的列表,然后通过返回modify ,但由于该值未分配到任何东西,它淡出存在,并且将很快被垃圾收集。

在第二种情况下,修改SETF不n ,但该列表的第一个元素n点。 这是相同的列表original点,所以,后来,你也可以看到通过这个变量修改的列表。

为了复制一个列表,使用COPY-LIST 。



Answer 2:

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未定义的变量。



Answer 3:

这几乎是相同的这个例子在C:

void modify1(char *p) {
    p = "hi";
}

void modify2(char *p) {
    p[0] = 'h';
}

在这两种情况下,指针传递,如果你改变了指针,你改变指针值的参数拷贝(它的堆栈上),如果你改变的内容,你改变任何对象的值指出。



Answer 4:

你可能有问题,因为即使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?