约尔格的回答指出了正确的方向。让我补充一点。
我将讨论与 Common Lisp 类似的 Lisp。
作为数据结构的符号
符号是 Lisp 中真实的数据结构。您可以创建符号,可以使用符号,可以存储符号,可以传递符号,并且符号可以是更大数据结构的一部分,例如符号列表。符号有名称,可以有值,也可以有函数值。
所以你可以获取一个符号并设置它的值。
(setf (symbol-value 'foo) 42)
通常有人会写(setq foo 42)
, or (set 'foo 42)
or (setf foo 42)
.
代码中表示变量的符号
But!
(defun foo (a)
(setq a 42))
or
(let ((a 10))
(setq a 42))
在上述两种形式的源代码中都有符号和a
像符号一样写并使用函数READ
读取该源会返回一个符号a
在一些列表中。但是setq
操作不设置符号值a
to 42
。这里的LET
和DEFUN
介绍一个VARIABLE a
我们用符号书写。就这样SETQ
然后操作将变量值设置为42
.
词汇绑定
所以,如果我们看一下:
(defvar foo nil)
(defun bar (baz)
(setq foo 3)
(setq baz 3))
我们引入一个全局变量FOO
.
在酒吧第一个SETQ
设置全局变量的符号值FOO
。第二SETQ
设置局部变量BAZ
to 3
。在这两种情况下我们都使用相同的SETQ
我们将变量写为符号,但在第一种情况下FOO
捐赠一个全局变量,并将这些值存储在符号值中。在第二种情况下BAZ
表示局部变量以及该值如何存储,我们不知道。我们所能做的就是访问变量来获取它的值。在 Common Lisp 中没有办法获取符号BAZ
并获取局部变量值。我们无法使用符号访问局部变量绑定及其值。这是 Common Lisp 中局部变量的词法绑定工作方式的一部分。
例如,这导致观察到,在没有记录调试信息的编译代码中,符号BAZ
离开了。它可以是处理器中的寄存器或以其他方式实现。符号FOO
仍然存在,因为我们将它用作全局变量。
符号的各种用途
符号是 Lisp 中的一种数据类型、一种数据结构。
变量是一个概念性的东西。全局变量基于符号。局部词法变量不是。
在源代码中,我们使用符号编写函数、类和变量的各种名称。
有一些概念重叠:
(defun foo (bar) (setq bar 'baz))
在上面的源代码中,defun
, foo
, bar
, setq
and baz
都是符号。
DEFUN
是提供宏的符号。FOO
是提供功能的符号。SETQ
是提供特殊运算符的符号。BAZ
是用作数据的符号。因此前面的引用BAZ
.
BAR
是一个变量。在编译后的代码中不再需要其符号。