Common Lisp 中的“set”、“setq”和“setf”有什么区别?
最初,在 Lisp 中,没有词法变量——只有动态变量。而且没有 SETQ 或 SETF,只有 SET 函数。
现在写成:
(setf (symbol-value '*foo*) 42)
写成:
(set (quote *foo*) 42)
最终缩写为 SETQ (SET Quoted):
(setq *foo* 42)
然后出现了词法变量,并且 SETQ 也开始用于对它们进行赋值——因此它不再是 SET 的简单包装器。
后来,有人发明了 SETF(SET Field),作为一种为数据结构赋值的通用方式,以反映其他语言的左值:
x.car := 42;
将被写为
(setf (car x) 42)
为了对称性和通用性,SETF 还提供了 SETQ 的功能。在这一点上,说 SETQ 是低级原语,而 SETF 是高级操作是正确的。
然后发生了符号宏。因此,符号宏可以透明地工作,如果分配给的“变量”实际上是符号宏,则 SETQ 必须像 SETF 一样工作:
(defvar *hidden* (cons 42 42)) (define-symbol-macro foo (car *hidden*)) foo => 42 (setq foo 13) foo => 13 *hidden* => (13 . 42)
所以我们来到了今天:SET 和 SETQ 是旧方言的萎缩残骸,很可能会从 Common Lisp 的最终继承者中被淘汰。