lisp - 无法更改列表
问题描述
例如,我有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))
,它不会影响 on *some-stack*
。你能解释一下为什么吗?
解决方案
setf
用一个符号作为地方 like(setf stack (cons element stack))
扩展为(setq 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)))))
请注意,我仅setf
在此处进行了扩展。两者都defun
变得dolist
非常可怕的扩展,使代码更难读。系统完全扩展了表单,因此运行的代码没有宏。
setq
更新绑定,因此当它更新时,它更新stack
的是它,而不是*some-stack*
. 如果你这样做,这正是发生的事情(stack-push *some-stack* "a")
:
- 你传递函数
*some-stack*
和"a"
. 它评估它的论点。 *some-stack*
评估为具有cons
单元格的地址 A,例如。("b")
."a"
是位于地址 B 的文字- 参数被绑定到新的绑定。
stack
指向A,元素指向B。 - 由于
element
指向 B(not (listp element)) ; ==> t
并且代码遵循结果。 - 在
(setf stack (cons element stack))
运行时之前更改为(setq stack (cons element stack))
. (cons element stack)
cons
以 B 和 A 作为参数调用。返回地址为 C 的新单元格("a" "b")
setq
更新以便绑定stack
指向 C。stack-push
返回最后一个评估值,它是setq
第二个参数 C的结果。
在函数中没有提到*some-stack*
. 绑定永远不会被引用或更新。只有stack
更新指向的新值。
由于这是一个函数,因此您可以使用文字调用您的函数,如果参数是要更新的变量,这通常不起作用。
(stack-push '("b") "a") ; ==> ("a" "b")
有一种形式叫push
. 它不是一个函数。你可以看到它做了什么:
(macroexpand '(push "a" *some-stack*))
; ==> (setq *some-stack* (cons "a" *some-stack*))
因此,push
要工作,您需要第二个参数是setf
可以的。尝试使用文字会扩展为无法运行的代码。对于类型,您可以制作自己的setf
扩展器,这样就setf
可以了push
。
推荐阅读
- google-chrome - 如何(破解和)将 Google Doc 的绘图窗口最大化到全屏?
- r - 将 RGB 栅格拆分为多个部分,并根据条件将文件保存在 GeoTiff 中
- botframework - 如何将机器人连接到通信应用程序?
- android - 为什么 Application.getContext() 返回 null?
- java - Jackson 有条件的自定义序列化器和反序列化器
- c++ - Electron 应用程序:错误:%1 不是有效的 Win32 应用程序
- intellij-idea - 如何删除我的 IntelliJ 2019.1 许可证?
- linux - 如何获取流入数据库中当前值与先前值之间的差异
- c++ - 为使用 dlopen() 加载的类自动创建包装器
- configuration - 设置所有功能的 url