Answers:
最初,在Lisp中,没有词法变量,只有动态变量。而且没有SETQ或SETF,只有SET函数。
现在写成:
(setf (symbol-value '*foo*) 42)
被写为:
(set (quote *foo*) 42)
最终缩写为SETQ(SET引用):
(setq *foo* 42)
然后发生了词法变量,并且SETQ也被用于为其赋值-因此它不再是SET的简单包装。
后来,有人发明了SETF(SET字段)作为将值分配给数据结构的通用方法,以反映其他语言的l值:
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的最终继承者那里得到引导。
set
是一个功能。因此,它不知道环境。set
无法看到词法变量。它只能设置其参数的符号值。setq
不再“设置引号”。这setq
是一种特殊的形式,而不是宏,这一事实表明了这一点。
(set ls '(1 2 3 4)) => Error - ls has no value
(set 'ls '(1 2 3 4)) => OK
(setq ls '(1 2 3 4)) => OK - make ls to (quote ls) and then have the usual set
(setf ls '(1 2 3 4)) => OK - same as setq so far BUT
(setf (car ls) 10) => Makes ls '(10 2 3 4) - not duplicated by setq/set
(setq ls '(((1))))
,(setf (car (car (car ls))) 5)
是未定义的行为,因为的值ls
是常量(例如在C中修改字符串文字)。之后(setq ls (list (list (list 1))))
,(setf (car (car (car ls))) 5)
就像ls->val->val->val = 5
在C中一样工作
setq
就像set
带引号的第一个arg (set 'foo '(bar baz))
一样(setq foo '(bar baz))
。setf
另一方面,确实是微妙的-就像“间接”。我建议http://www.nano.com/lisp/cmucl-tutorials/LISP-tutorial-16.html作为一种更好的方式开始理解它比任何答案在这里可以给......总之,虽然,setf
取将第一个参数用作“引用”,以便例如(aref myarray 3)
将(作为的第一个arg setf
)用于在数组内设置项目。
您可以使用setf
替代set
或setq
反之则不行,因为setf
还可以设置一个变量的各个元素的值,如果变量具有单个元素。参见下面的实例:
所有这四个示例都将列表(1、2、3)分配给名为foo的变量。
(set (quote foo) (list 1 2 3)) ;foo => (1 2 3)
(1 2 3)
(set 'foo '(1 2 3)) ;foo => (1 2 3) same function, simpler expression
(1 2 3)
(setq foo '(1 2 3)) ;foo => (1 2 3) similar function, different syntax
(1 2 3)
(setf foo '(1 2 3)) ;foo => (1 2 3) more capable function
(1 2 3)
setf
具有将列表中的成员设置foo
为新值的附加功能。
foo ;foo => (1 2 3) as defined above
(1 2 3)
(car foo) ;the first item in foo is 1
1
(setf (car foo) 4) ;set or setq will fail since (car foo) is not a symbol
4
foo ;the fist item in foo was set to 4 by setf
(4 2 3)
但是,您可以定义一个符号宏,以表示其中的单个项目 foo
(define-symbol-macro foo-car (car foo)) ; assumes FOO => (1 2 3)
FOO-CAR
foo-car ;foo-car is now a symbol for the 1st item in foo
1
(setq foo-car 4) ;set or setq can set the symbol foo-car
4
foo ;Lisp macros are so cool
(4 2 3)
您可以使用defvar
,如果您还没有定义的变量,并不想给它的值,直到后来在你的代码。
(defvar foo2)
(define-symbol-macro foo-car (car foo2))