就范围而言?内存中的实际实现?语法?例如,if(let a 1)是'a'变量还是符号?
答案 0 :(得分:20)
Jörg的答案指向了正确的方向。让我补充一点。
我将讨论与Common Lisp类似的Lisps。
符号作为数据结构
符号是Lisp中的真实数据结构。您可以创建符号,可以使用符号,可以存储符号,可以传递符号,符号可以是较大数据结构的一部分,例如符号列表。符号具有名称,可以具有值并且可以具有函数值。
所以你可以拿一个符号并设置它的值。
(setf (symbol-value 'foo) 42)
通常有人会写(setq foo 42)
,或(set 'foo 42)
或(setf foo 42)
。
代码中的符号表示变量
但是!
(defun foo (a)
(setq a 42))
或
(let ((a 10))
(setq a 42))
在源代码的上述两种形式中都有符号,a
被写成符号,并使用函数READ
来读取该源在某些列表中返回符号a
。但setq
操作不会将a
的符号值设置为42
。这里LET
和DEFUN
引入了我们用符号编写的 VARIABLE a
。因此,SETQ
操作会将变量值设置为42
。
词汇绑定
所以,如果我们看一下:
(defvar foo nil)
(defun bar (baz)
(setq foo 3)
(setq baz 3))
我们引入了一个全局变量FOO
。
在条形图中,第一个SETQ
设置全局变量FOO
的符号值。第二个SETQ
将局部变量BAZ
设置为3
。在这两种情况下,我们使用相同的SETQ
并将变量写为符号,但在第一种情况下,FOO
捐赠全局变量,并将值存储在符号值中。在第二种情况下,BAZ
表示局部变量以及值如何存储,我们不知道。我们所能做的就是访问变量以获取其值。在Common Lisp中,无法获取符号BAZ
并获取局部变量值。我们无法使用符号访问局部变量绑定及其值。这是局部变量的词法绑定如何在Common Lisp中起作用的一部分。
这导致例如观察,在没有记录调试信息的编译代码中,符号BAZ
消失了。它可以是处理器中的寄存器,也可以通过其他方式实现。符号FOO
仍然存在,因为我们将它用作全局变量。
符号的各种用途
符号是数据类型,是Lisp中的数据结构。
变量是概念性的东西。全局变量基于符号。本地词汇变量不是。
在源代码中,我们使用符号为函数,类和变量编写各种名称。
存在一些概念上的重叠:
(defun foo (bar) (setq bar 'baz))
在上面的SOURCE代码中,defun
,foo
,bar
,setq
和baz
都是符号。
DEFUN
是提供宏的符号。
FOO
是提供功能的符号。
SETQ
是提供特殊运算符的符号。
BAZ
是用作数据的符号。因此BAZ
之前的引用。
BAR
是一个变量。在编译的代码中,不再需要其符号。
答案 1 :(得分:12)
解释时间。
Lisp所谓的符号与许多语言调用变量的内容非常接近。在第一近似中,符号具有值;当您评估表达式x
时,表达式的值是符号x
的值;当您撰写(setq x 3)
时,您会为x
分配一个新值。在Lisp术语中,(setq x 3)
将值3绑定到符号x
。
大多数语言都没有的Lisp功能是符号是普通对象(符号是编程语言术语中的第一类对象)。当您编写(setq x y)
时,x
的值将变为y
在分配时的值。但是你可以写(setq x 'y)
,在这种情况下,x
的值是符号y
。
从概念上讲,有一个environment,它是从符号到值的关联表。评估符号意味着在当前环境中查找它。 (环境也是一流的对象,但这超出了本答案的范围。)绑定是指环境中的特定条目。但是,还有一个复杂的问题。
大多数Lisp方言都有多个名称空间,至少是变量名称空间和函数名称空间。事实上,一个环境可以包含一个符号的多个条目,每个命名空间一个条目。严格来说,变量是变量名称空间中的环境中的条目。在日常的Lisp术语中,当符号作为变量绑定是您感兴趣的时候,它通常被称为变量。
例如,在(setq a 1)
或(let ((a 1)) ...)
中,a
是一个符号。但由于构造作用于符号a
的变量绑定,因此在此上下文中将a
称为变量是很常见的。
另一方面,在(defun a (...) ...)
或(flet ((a (x) ...)) ...)
中,a
也是一个符号,但这些结构会对其功能绑定起作用,因此不会考虑a
变量。
在大多数情况下,当符号在表达式中不加引号时,通过查找其变量绑定来评估它。主要的例外是在函数调用(foo arg1 arg2 ...)
中,使用foo
的函数绑定。带引号的符号'x
或(quote x)
的值本身就像任何引用的表达式一样。当然,有很多特殊形式,您不需要引用符号,包括setq
,let
,flet
,defun
等。
答案 2 :(得分:10)
符号是一个东西的名称。 变量是指向可变存储位置的可变指针。
在您显示的代码段中,let
和a
都是符号。在let
块的范围内,符号a
表示当前绑定到值1
的变量。
但事物的名称本身并不是事物。符号a
不是变量。它是变量的名称。但仅在此特定上下文中。在不同的上下文中,名称a
可以指代完全不同的东西。
示例:符号jaguar
可能会根据上下文表示
答案 3 :(得分:4)
Lisp使用类似于map(key - > value)的环境,但使用额外的内置机制来链接环境和控制绑定。
现在,符号非常多,键(特殊形式符号除外),并指向一个值,
即功能,整数,列表等。
由于Common Lisp为您提供了一种更改值的方法,即使用setq
,在某些上下文中使用符号
(您的示例)也是变量。
答案 4 :(得分:3)
符号是Lisp数据对象。 Lisp“form”表示要评估的Lisp对象。当符号本身用作Lisp形式时,即当您评估符号时,结果是与该符号相关联的值。值与符号相关联的方式是Lisp语言的深层部分。该符号是否被声明为“特殊”或极大地改变了评估的工作方式。
词法值由符号表示,但您无法自己将这些符号作为对象进行操作。在我看来,用“指针”或“位置”来解释Lisp中的任何内容并不是最好的方法。
答案 5 :(得分:1)
符号和变量是两个不同的东西。 就像在数学符号中一样是一种价值。变量与数学中的含义相同。
但是你的困惑来自于符号是变量的元表示的事实。
如果你这样做
(setq a 42)
您只需定义一个变量a。顺便提一下,常见的lisp存储它的方式是抛出结构的符号。
在常见的嘴唇中,符号是具有不同属性的结构。每个人都可以通过symbol-name
,symbol-function
...
如果是变量,您可以通过s symbol-value
? (symbol-value 'a)
42
这不是获取a。
值的常见情况? a
42
请注意,符号是自我评估的,这意味着如果您询问符号,则会得到符号而不是symbol-value
? 'a
A
答案 6 :(得分:1)
在上述答案中添加旁注:
除了作为变量的名称之外,Lisp的新手通常不确定符号的确切含义。我认为最好的答案是它们就像枚举常量一样,除了你在使用它们之前不必声明它们。当然,正如其他人所解释的那样,它们也是对象。 (这对Java用户来说似乎并不奇怪,其中枚举常量也是对象。)