Common Lisp中`set`,`setq`和`setf`之间的区别?
Common Lisp中的“set”,“setq”和“setf”有什么区别?
最初,在Lisp中,没有词汇variables – 只有dynamicvariables。 并没有SETQ或SETF,只是SET函数。
现在写成:
(setf (symbol-value '*foo*) 42)
被写为:
(set (quote *foo*) 42)
最终被缩写为SETQ(SET引用):
(setq *foo* 42)
然后发生了词汇variables,并且SETQ也被用于赋值给它们 – 所以它不再是一个简单的SET包装器。
后来,有人发明了SETF(SET Field)作为赋值给数据结构的通用方法,以反映其他语言的l值:
x.car := 42;
会写成
(setf (car x) 42)
为了对称性和通用性,SETF还提供了SETQ的function。 在这一点上,说SETQ是一个低级原语,而SETF是一个高级操作,那是对的。
然后符号macros发生。 因此,符号macros可以透明地工作,人们认识到,如果被赋予的“variables”实际上是符号macros,那么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的最终接class人开始。
(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
就像set
了引用的第一个arg – (set 'foo '(bar baz))
就像(setq foo '(bar baz))
。 另一方面, setf
确实很微妙 – 就像是一个“间接”。 我build议http://www.nano.com/lisp/cmucl-tutorials/LISP-tutorial-16.html作为一个更好的方法来开始理解它比任何答案可以给;…总之,虽然, setf
需要第一个参数作为“参考”,以便例如(aref myarray 3)
将工作(作为setf
的第一个参数)来设置一个数组内的项目。
您可以使用setf
来代替set
或setq
但反之亦然,因为setf
也可以设置variables的单个元素的值(如果variables具有单独的元素)。 见下面的例子:
所有这四个例子都将把列表(1,2,3)分配给名为foo的variables。
(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
中的列表成员设置为新值的附加function。
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
单个项目的符号macros
(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
如果你还没有定义这个variables,并且不想在你的代码之后给它一个值。
(defvar foo2) (define-symbol-macro foo-car (car foo2))
人们可以把SET
和SETQ
是低层次的结构。
-
SET
可以设置符号的值。 -
SETQ
可以设置variables的值。
然后SETF
是一个macros,它提供了许多种设置的东西:符号,variables,数组元素,实例槽,…
对于符号和variables,可以认为SETF
扩展为SET
和SETQ
。
* (macroexpand '(setf (symbol-value 'a) 10)) (SET 'A 10) * (macroexpand '(setf a 10)) (SETQ A 10)
所以SET
和SETQ
被用来实现SETQ
的一些function,这是更一般的结构。 当我们考虑符号macros时,其他一些答案会告诉你更复杂的故事。
我想添加到以前的答案,即setf是macros调用具体函数取决于作为其第一个parameter passing。 将setf的macros扩展与不同types的参数进行比较的结果:
(macroexpand '(setf a 1)) (macroexpand '(setf (car (list 3 2 1)) 1)) (macroexpand '(setf (aref #(3 2 1) 0) 1))
对于某些types的参数“setf function”将被调用:
(defstruct strct field) (macroexpand '(setf (strct-field (make-strct)) 1))