(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
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)
6 回答
最初,在Lisp中,没有词汇变量 - 只有动态变量 . 并且没有SETQ或SETF,只有SET功能 .
现在写的是:
被写成:
最终abbreviavated到SETQ(SET引用):
然后发生了词法变量,并且SETQ也被用于赋值给它们 - 所以它不再是SET的简单包装器 .
后来,有人发明了SETF(SET Field)作为向数据结构赋值的通用方法,以镜像其他语言的l值:
将写成
为了对称性和通用性,SETF还提供了SETQ的功能 . 在这一点上,说SETQ是低级原语,SETF是高级操作是正确的 .
然后符号宏发生了 . 因此符号宏可以透明地工作,我们意识到如果分配给的“变量”实际上是一个符号宏,SETQ将必须像SETF一样:
所以我们到达现在:SET和SETQ是老式方言的萎缩遗骸,并且可能会从Common Lisp的最终继承者中启动 .
setq
就像set
,引用第一个arg -(set 'foo '(bar baz))
就像(setq foo '(bar baz))
. 另一方面,setf
确实很微妙 - 它就像一个"indirection" . 我建议http://www.n-a-n-o.com/lisp/cmucl-tutorials/LISP-tutorial-16.html作为开始理解它的一种更好的方式,而不是这里的任何答案都可以...简而言之,setf
将第一个参数作为"reference",以便例如(aref myarray 3)
将在数组中设置项目(作为setf
的第一个arg) .您可以使用
setf
代替set
或setq
但不反之亦然,因为如果变量具有单个元素,setf
也可以设置变量的各个元素的值 . 见下面的exaples:所有四个示例都将列表(1,2,3)分配给名为foo的变量 .
setf
具有将foo
中列表成员设置为新值的附加功能 .但是,您可以定义一个符号宏来表示
foo
中的单个项目如果尚未定义变量并且不想在代码中稍后给它赋值,则可以使用
defvar
.人们可以认为
SET
和SETQ
是低级构造 .SET
可以设置符号的值 .SETQ
可以设置变量的值 .然后
SETF
是一个宏,它提供了多种设置:符号,变量,数组元素,实例槽,...对于符号和变量,可以认为
SETF
扩展为SET
和SETQ
.所以
SET
和SETQ
用于实现SETF
的一些功能,这是更通用的结构 . 当我们考虑符号宏时,其他一些答案会告诉您稍微复杂的故事 .我想在之前的答案中添加setf是宏,它根据作为第一个参数传递的内容调用特定函数 . 将setf的宏扩展结果与不同类型的参数进行比较:
对于某些类型的参数,将调用“setf function”: