Shared structures

"quote就是构造一个list"似乎不对 quote会对多层生效吗 继续讨论:

C-h v 常常遇到 #1=some-value #1# 这样的值,如:

(let ((s "HELLO"))
  (list s s))
;; => (#1="HELLO" #1#)

(let ((l (list 1)))
  (list l l))
;; => (#1=(1) #1#)

使用同一个值两次时,Emacs 只保存第一次的值,第二次使用引用(Shared)。字符串、数组、列表是这样的,数字、符号则不会。

与此相关的一个常见问题:'(1 2 3)(list 1 2 3) 的区别:

(mapcar (lambda (x) (cons x (list 1 2 3)))
        '(a b c))
;; => ((a 1 2 3) (b 1 2 3) (c 1 2 3))

如果要用 '(1 2 3) 得到和 (list 1 2 3) 一模一样的结果需要用:

(list (cons 'a '(1 2 3))
      (cons 'b '(1 2 3))
      (cons 'c '(1 2 3)))
;; => ((a 1 2 3) (b 1 2 3) (c 1 2 3))

下面这样是不行的:

(mapcar (lambda (x) (cons x '(1 2 3)))
        '(a b c))
;; => ((a . #1=(1 2 3)) (b . #1#) (c . #1#))

M-x disassemble 很容易看出 '(1 2 3)(list 1 2 3) 的区别:

(defun foo (x)
  (cons x '(1 2 3)))

byte code for foo:
  args: (x)
0       varref    x
1       constant  (1 2 3)
2       cons      
3       return    

(defun bar (x)
  (cons x (list 1 2 3)))

byte code for bar:
  args: (x)
0       varref    x
1       constant  1
2       constant  2
3       constant  3
4       list3     
5       cons      
6       return    

大致可以认为一个 Quoted Object 是一个「常量」,跟所在的执行环境绑定在了一起。但问题在于这个「常量」没有强制性,Emacs 不会阻止用户修改常量,比如 foo 的定义会被这样一种方式修改:

(defun foo (x)
  (cons x '(1 2 3)))

(setf (nth 1 (foo 100)) 1111)

byte code for foo:
  args: (x)
0       varref    x
1       constant  (1111 2 3)
2       cons      
3       return    

所以如果你的代码中有 '(1 2 3),第一次执行它是 (1 2 3),第二次就不能确定了,不像 (list 1 2 3) 每次执行都是 (1 2 3)

而如果只可能执行一遍,比如给变量设置初值,'(1 2 3)(list 1 2 3) 没有区别:

(defvar foo '(1 2 3))
(defvar bar (list 1 2 3))
2赞

把quoted object作为常量就更容易理解了