lisp - 两个简单的推送功能;一个永久改变全局变量,另一个不改变,为什么?

标签 lisp common-lisp sbcl

下面是两个对传入的变量使用 push 的简单函数:

(defun push-rest (var) (push 99 (rest var)))

(defun just-push (something) (push 5 something))

第一个将永久改变传递的var。第二个没有。对于正在学习这种语言的作用域行为的人来说,这非常令人困惑:

CL-USER> (defparameter something (list 1 2))    
SOMETHING
CL-USER> something
(1 2)
CL-USER> (just-push something)
(5 1 2)
CL-USER> something
(1 2)
CL-USER> (push-rest something)
(99 2)
CL-USER> something
(1 99 2)

push-rest 中,为什么 var 的范围不像在 just-push 中那样局限于函数,当它们都使用相同的函数时,?

最佳答案

根据 Peter Siebel 的 Practical Common Lisp,第 6 章。变量:This可能对您有很大帮助:

As with all Common Lisp variables, function parameters hold object references. Thus, you can assign a new value to a function parameter within the body of the function, and it will not affect the bindings created for another call to the same function. But if the object passed to a function is mutable and you change it in the function, the changes will be visible to the caller since both the caller and the callee will be referencing the same object.

还有一个脚注:

In compiler-writer terms Common Lisp functions are "pass-by-value." However, the values that are passed are references to objects.

(按值传递本质上也意味着复制;但我们不是在复制对象;我们是在复制对象的引用/指针。)

正如我在另一条评论中指出的:

Lisp 不传递对象。 Lisp 将对象引用的副本传递给函数。或者您可以将它们视为指针。 setf 将函数创建的新指针分配给其他对象。未触及先前的指针/绑定(bind)。但是,如果函数改为对这个指针进行操作,而不是设置它,那么它也会对指针指向的原始对象进行操作。如果您是 C++ 专家,那么这对您来说可能更有意义。

关于lisp - 两个简单的推送功能;一个永久改变全局变量,另一个不改变,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20345812/

相关文章:

common-lisp - 将 Spotify 窗口分配给 StumpWM 中的组

common-lisp - 如何使用 Caveman2 设置响应状态代码?

loops - Clisp - 将伪代码翻译成实际的 lisp 代码

lisp - lisp中的循环指针

lisp - 为什么 defun 与 (setq <name> <lambda>) 不同?

shell - 使用预定义的 lisp 代码从 shell 启动 emacs

scheme - 解决方案中的奇数重复

performance - 列表长度的时间复杂度

sockets - 原子地写入套接字

testing - 如何在 SBCL 中运行测试文件