LISP中变量​​和符号之间有什么区别?

Gau*_*nia 22 lisp functional-programming symbols common-lisp

在范围方面?内存中的实际实现?语法?例如,if(let a 1)是'a'变量还是符号?

Rai*_*wig 21

Jörg的答案指向了正确的方向.让我补充一点.

我将讨论与Common Lisp类似的Lisps.

符号作为数据结构

符号是Lisp中的真实数据结构.您可以创建符号,可以使用符号,可以存储符号,可以传递符号,符号可以是较大数据结构的一部分,例如符号列表.符号具有名称,可以具有值并且可以具有函数值.

所以你可以拿一个符号并设置它的值.

(setf (symbol-value 'foo) 42)
Run Code Online (Sandbox Code Playgroud)

通常一个人会写(setq foo 42),(set 'foo 42)或者(setf foo 42).

代码中的符号表示变量

但!

(defun foo (a)
  (setq a 42))
Run Code Online (Sandbox Code Playgroud)

要么

(let ((a 10))
   (setq a 42))
Run Code Online (Sandbox Code Playgroud)

在源代码中的上述两种形式中都有符号,并且a像符号一样编写,并使用函数READ来读取该源a在某些列表中返回符号.但该setq操作不会将符号值设置a42.在这里,LETDEFUN引入变量 a,我们用符号写.因此,SETQ操作然后将变量值设置为42.

词汇绑定

所以,如果我们看一下:

(defvar foo nil)

(defun bar (baz)
  (setq foo 3)
  (setq baz 3))
Run Code Online (Sandbox Code Playgroud)

我们介绍一个全局变量FOO.

在bar中,第一个SETQ设置全局变量的符号值FOO.第二个SETQ将局部变量设置BAZ3.在这两种情况下,我们都使用相同的SETQ,我们将变量写为符号,但在第一种情况下,FOO捐赠全局变量,并将值存储在符号值中.在第二种情况下,BAZ表示局部变量以及值如何存储,我们不知道.我们所能做的就是访问变量以获取其值.在Common Lisp中,无法BAZ获取符号并获取局部变量值.我们无法使用符号访问局部变量绑定及其值.这是局部变量的词法绑定如何在Common Lisp中起作用的一部分.

这导致例如观察,在没有记录调试信息的编译代码中,符号BAZ消失.它可以是处理器中的寄存器,也可以通过其他方式实现.符号FOO仍然存在,因为我们将它用作全局变量.

符号的各种用途

符号是数据类型,是Lisp中的数据结构.

变量是概念性的东西.全局变量基于符号.本地词汇变量不是.

在源代码中,我们使用符号为函数,类和变量编写各种名称.

有一些概念上的重叠:

(defun foo (bar) (setq bar 'baz))
Run Code Online (Sandbox Code Playgroud)

在上面的源代码,defun,foo,bar,setqbaz是所有符号.

DEFUN是一个提供宏的符号. FOO是一个提供功能的符号. SETQ是提供特殊操作员的符号. BAZ是用作数据的符号.因此之前的报价BAZ. BAR是一个变量.在编译的代码中,不再需要其符号.


Gil*_*il' 13

引用Common Lisp HyperSpec:

符号 ñ.一个对象类型 的符号.

变量 ñ."变量"命名空间中绑定.

结合 ñ.名称名称所表示的名称之间的关联.(......)

解释时间.

Lisp调用的符号与许多语言调用变量的内容非常接近.在第一近似中,符号具有值; 在计算表达式时x,表达式的值是符号的值x; 当你写作时(setq x 3),你给一个新值x.在Lisp术语中,(setq x 3)将值3绑定到符号x.

大多数语言都没有的Lisp特性是符号是普通对象(符号是编程语言术语中的第一类对象).在您编写时(setq x y),值将x变为y赋值时的值.但你可以写(setq x 'y),在这种情况下,值x是符号y.

从概念上讲,存在一个环境,它是从符号到值的关联表.评估符号意味着在当前环境中查找它.(环境也是一流的对象,但这超出了本答案的范围.)绑定是指环境中的特定条目.但是,还有一个复杂的问题.

大多数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,等.


Jör*_*tag 11

一个符号是一个东西的名称.甲变量是一个可变指针一个可变的存储位置.

在代码片段你显示,无论是leta有符号.在let块的范围内,符号a表示当前绑定到该值的变量1.

但事物的名称本身并不是事物.符号a不是变量.它是变量的名称.但只有在这个特定的背景下.在不同的上下文中,名称a可以指代完全不同的东西.

示例:jaguar根据上下文,符号可以表示

  • 对,这个答案指向了正确的方向. (2认同)