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来代替setsetq但反之亦然,因为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)) 

人们可以把SETSETQ是低层次的结构。

  • SET可以设置符号的值。

  • SETQ可以设置variables的值。

然后SETF是一个macros,它提供了许多种设置的东西:符号,variables,数组元素,实例槽,…

对于符号和variables,可以认为SETF扩展为SETSETQ

 * (macroexpand '(setf (symbol-value 'a) 10)) (SET 'A 10) * (macroexpand '(setf a 10)) (SETQ A 10) 

所以SETSETQ被用来实现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)) 
Interesting Posts