例如,我有函数stack-push
将元素推送到堆栈上。
(defun stack-push (stack element)
(if (not (listp element))
(setf stack (cons element stack))
(dolist (current-el (reverse element))
(setf stack (cons current-el stack)))))
但当我像
(stack-push *some-stack* '(a b c d e))
那样调用它时,它不会影响*some-stack*
你能解释一下原因吗? 最佳答案
setf
将符号扩展为(setf stack (cons element stack))
这通常在创建函数时发生你的功能变成:
(defun stack-push (stack element)
(if (not (listp element)
(setq stack (cons element stack))
(dolist (current-el (reverse element))
(setq stack (cons current-el stack)))))
注意,这里我只扩展了
(setq stack (cons element stack))
setf
和defun
都变得非常可怕的扩展,这使得代码更不可读系统完全展开窗体,以便运行的代码没有宏。dolist
更新绑定,因此当它更新时,它会更新,而不是如果你这样做了,下面就是具体的情况:传递函数
setq
和stack
它计算它的参数。*some-stack*
计算为具有(stack-push *some-stack* "a")
单元格的地址A,例如*some-stack*
。"a"
是位于地址B的文本参数绑定到新绑定
*some-stack*
指向A,元素指向B。因为
cons
指向B("b")
并且代码遵循结果。in
"a"
在运行时更改为stack
之前。element
使用B和A作为参数调用(not (listp element)) ; ==> t
返回地址为C(setf stack (cons element stack))
的新单元格(setq stack (cons element stack))
更新,以便绑定(cons element stack)
指向c。cons
返回最后一个计算值,这是第二个参数C("a" "b")
的结果。函数中没有提到
setq
绑定从不被引用或更新只有stack
更新了要指向的新值。由于这是一个函数,所以可以用文本调用函数,如果参数是一个要更新的变量,文本通常不起作用。
(stack-push '("b") "a") ; ==> ("a" "b")
有一种形式叫做
stack-push
它不是一个函数你可以看到它的作用:(macroexpand '(push "a" *some-stack*))
; ==> (setq *some-stack* (cons "a" *some-stack*))
因此,要使
setq
起作用,您需要第二个参数是可以实现的尝试使用文字将扩展为不可命名的代码对于类型,您可以创建自己的*some-stack*
扩展程序,以便stack
和push
工作。关于lisp - 无法更改 list ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50201198/