【问题标题】:What is the difference between a variable and a symbol in LISP?LISP 中的变量和符号有什么区别?
【发布时间】:2011-04-05 03:35:35
【问题描述】:

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

【问题讨论】:

  • clisp 是 Common Lisp 的一个特殊实现,你的问题是关于语言的,所以我冒昧地更改了你的标签。

标签: functional-programming lisp common-lisp symbols


【解决方案1】:

Jörg 的回答指出了正确的方向。让我补充一点。

我会谈谈类似于 Common Lisp 的 Lisp。

符号作为数据结构

符号是 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。这里LETDEFUN 引入了一个我们用符号编写的VARIABLE a。因此SETQ 操作会将变量值设置为42

词法绑定

所以,如果我们看一下:

(defvar foo nil)

(defun bar (baz)
  (setq foo 3)
  (setq baz 3))

我们引入一个全局变量FOO

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

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

符号的各种用途

符号是一种数据类型,是 Lisp 中的一种数据结构。

变量是一个概念性的东西。全局变量基于符号。不是局部词法变量。

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

有一些概念上的重叠:

(defun foo (bar) (setq bar 'baz))

在上述 SOURCE 代码中,defunfoobarsetqbaz 都是符号。

DEFUN 是一个提供宏的符号。 FOO 是提供功能的符号。 SETQ 是提供特殊运算符的符号。 BAZ 是用作数据的符号。因此BAZ 之前的引用。 BAR 是一个变量。在编译代码中不再需要它的符号。

【讨论】:

    【解决方案2】:

    引用Common Lisp HyperSpec:

    symbol n. 一个objecttype symbol

    variable n.“变量”中的bindingnamespace

    binding n. namename 所表示的内容之间的关联。 (…)

    说明时间。

    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,它是一个从符号到值的关联表。评估一个符号意味着在当前环境中查找它。 (环境也是一流的对象,但这超出了此答案的范围。) binding 指的是环境中的特定条目。但是,还有一个复杂的问题。

    大多数 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) 的值本身就是任何带引号的表达式。当然,还有很多特殊形式不需要引用符号,包括setqletfletdefun等。

    【讨论】:

      【解决方案3】:

      符号是事物的名称。 变量是指向可变存储位置的可变指针。

      在您显示的代码 sn-p 中,leta 都是符号。在let 块的范围内,符号a 表示当前绑定到值1 的变量。

      但事物的名称并不是事物本身。符号a 不是变量。它是一个变量的名称。但是在这个特定的上下文中。在不同的上下文中,名称a 可以指代完全不同的事物。

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

      【讨论】:

      • +1 用于提及在不同上下文中表示不同事物的符号。这在尝试理解 x#'x'x 之间的区别时真的很有帮助。
      【解决方案4】:

      Lisp 使用类似于映射(键 -> 值)的 环境,但具有用于链接环境和控制绑定的额外内置机制。

      现在,symbols 几乎就是 keys(特殊形式的符号除外),并指向一个值,
      函数整数列表
      由于 Common Lisp 为您提供了一种更改值的方法,即在某些上下文中使用 setq 符号
      (你的例子)也是变量

      【讨论】:

        【解决方案5】:

        符号是一个 Lisp 数据对象。 Lisp 的“表单”是指要被评估的 Lisp 对象。当符号本身用作 Lisp 形式时,即当您评估符号时,结果是与该符号关联的值。值与符号相关联的方式是 Lisp 语言的深层部分。符号是否被声明为“特殊”会极大地改变评估的工作方式。

        词法值由符号表示,但您不能自己将这些符号作为对象来操作。在我看来,用“指针”或“位置”来解释 Lisp 中的任何内容都不是最好的方法。

        【讨论】:

          【解决方案6】:

          为上述答案添加旁注:

          Lisp 的新手通常不知道符号的确切用途,除了变量的名称。我认为最好的答案是它们就像枚举常量,只是你不必在使用它们之前声明它们。当然,正如其他人所解释的,它们也是对象。 (这对 Java 的用户来说应该不奇怪,其中枚举常量也是对象。)

          【讨论】:

          • 有趣的答案
          【解决方案7】:

          符号和变量是两个不同的东西。 就像在数学中的符号是一个值。变量的含义与数学中的含义相同。

          但您的困惑来自于符号是变量的元表示这一事实。

          如果你这样做了

          (setq a 42)
          

          你只需定义一个变量a。顺便说一句,普通 lisp 存储它的方式是抛出 符号结构

          通常的嘴唇符号是具有不同属性的结构。每一个都可以通过symbol-namesymbol-function等函数访问...

          如果是变量,您可以通过 ssymbol-value 访问他的值

          ? (symbol-value 'a)
          42
          

          这不是获取 a 值的常见情况。

          ? a
          42
          

          请注意,符号是自我评估的,这意味着如果您询问符号,您会得到符号而不是 symbol-value

          ? 'a
          A
          

          【讨论】:

            猜你喜欢
            • 2010-10-11
            • 1970-01-01
            • 2011-04-20
            • 2014-09-16
            • 1970-01-01
            • 2011-06-02
            • 1970-01-01
            相关资源
            最近更新 更多