代码:
(defun test ()
(let ((l '(1)))
(push 2 l)
(nreverse l)))
之后,对 (test)
求值两次,第一次返回 '(1 2)
,第二次返回 '(2 1 2)
。
试着做了一些实验:
放一个 message
在里面:
(defun test ()
(let ((l '(1)))
(message "l is %s" l)
(push 2 l)
(nreverse l)))
可知第一次求值时,l
是 '(1)
;第二次就是 '(1 2)
了。
把 (let ((l '(1)))
换成 (let ((l (list 1)))
,好了。
拿掉 nreverse
,好了。
Emacs 版本是 26.3。这是为什么呢?
结果上看类似全局变量,或者 C 的静态变量。quoted object 不只是列表,其它类似字符串、数组、哈希表?都有这个现象,数字跟 nil 应该没问题
(defun foo ()
(let ((s "A"))
(cl-incf (aref s 0))
s))
;; => foo
(foo)
;; => "B"
(foo)
;; => "C"
(foo)
;; => "D"
bing
2020 年6 月 10 日 13:55
5
nreverse为啥设计成这样,是有特殊作用,还是设计错误
可是这个let
在test
里面,每次let不是应该生成一个全新的l
吗……
也就是开发过程中,quote 或者 backquote 都是静态变量。如果想要声明一般变量需要显式调用 (list 1 2 3)
或者 (vector 1 2 3)
。我一直以为 '(1 2 3) 和 (list 1 2 3) 是等价的,这可能对 elisp 并不适用
cireu
2020 年6 月 11 日 04:54
9
带插值的backquote会被翻译成list+append,所以不是静态的。不带插值的backquote会直接翻译成quote
2 个赞
zsxh
2020 年6 月 11 日 06:32
10
同疑问,let 声明的变量难道是一直记录在这个作用域内,不是每次重新生成的
看了之前主题的两个链接,感觉就是 quote object 初始化返回的是个指针地址,后面在同一作用域调用时,还是这个地址,只是指向的东西被改的面目全非了,不知道理解的对不对
1 个赞
当你把 nreverse 用于 quote object 时,函数就不纯了。
文档有说:
quote
returns the argument, without evaluating it. (quote x)
yields x
.
Warning : quote
does not construct its return value, but just returns the value that was pre-constructed by the Lisp reader (see info node Printed Representation ).
This means that (a . b)
is not identical to (cons 'a 'b)
: the former does not cons. Quoting should be reserved for constants that will never be modified by side-effects, unless you like self-modifying code.
所以,你的函数相当于:
``` elisp
(defvar gl '(1))
(defun test ()
(let ((l gl))
(push 2 l)
(nreverse l)))
2 个赞
准确的说,'(1 2 3)
等于 immutable 的 (list 1 2 3)
。
Special Form:quote object
This special form returns object, without evaluating it. The returned value might be shared and should not be modified. See Self-Evaluating Forms .
感觉是早期 Elisp 实现的问题,默认认为 quote 的返回为常量,然后修改这个“常量”程序又不会报错。想起来 Xah 的一个视频