elisp问题: setcar第一个参数为什么不需要quote?

初学elisp, 对于setcar感到非常困惑: setcar第一个参数为什么不需要quote? 下面这个例子, 调用setcar难道不会对foo进行求值么? 但是foo无法被求值, 因为它的第一个元素不是函数. 我的理解就是, 如果list没有quote, 就会把第一个元素作为函数, 然后调用函数. 我一度以为setcar是宏, 虽然我还没学宏, 但是看文档setcar并不是宏, 这怎么解释呢?

(setq foo '(1 2 3))
(setcar foo 'a)
(setcar (cdr foo) 'b)
(setcar (nthcdr 2 foo) 'c)
foo

foo 可以被求值, 求值结果就是 foo 这个变量的内容

谢谢! 但对这个代码还有个问题, 与原问题无关, 那就是setcar是创建了一个新的list, 还是在原来的list基础上做的修改?

后者

Lisp 的 list 是单链表. 比如一个 (list 1 2 3 4 5)

可以表示为 (cons 1 (cons 2 (cons 3 (cons 4 (cons 5 '()))))) 在实际上,类似于一个含有两个 field 的结构, 第一个 field 保存当前的位置的 Lisp object, 另外一个 field 保存一个指向下一个链表 node 的引用.

setcarsetcdr 是有副作用的, 他们效果相当于直接修改这些 field 的内容.

但是,绝大部分链表的操作都可以用 pure 的方法实现, 这也是链表本身存在的意义.

另外你的例子里面, foo 是 quote object, 在 Emacs 里面, quote object 是常量, 不应该使用 setcar setcdr 修改.

现在再来看这个问题, 补充说明我现在的想法(一个多月没碰 elisp, 昨天又开始看), foo 本身不是 list, 它是 symbol, symbol eval 后才得到 list. 因此这仍然符合函数一定要 eval 的特点. 至于它为什么改变了 list, 因为函数可以有副作用也可以没有, 这里属于有副作用的情况.

1 个赞