【问题标题】:How does Lisp dynamically assign symbols? Underlying data structure/mechanism of a Lisp symbol?Lisp 如何动态分配符号? Lisp 符号的底层数据结构/机制?
【发布时间】:2023-04-01 07:56:01
【问题描述】:

Lisp 允许您在类似

的列表中定义符号,例如 A 和 B
(setf mylist '(+ 1 2 A))

然后您可以随时返回并将 A 设置为一个值,例如。 (set 'A 100)。此时您可以执行(eval mylist) 并返回 103。然后您可以反复将 A 重新分配给任何新值。

看起来 Lisp 既保存了文字“A”(符号的名称),也保存了它的赋值。这允许动态变量分配/重新分配。这有点像查找列表。允许这样做的底层数据结构或机制是什么?

编辑:具体来说,这是如何在内部完成的(或在外部因为包似乎直接参与)?寻找一个深入的技术答案,重点是它是如何在 Lisp-2 中实现的。

【问题讨论】:

  • 是什么让你觉得它被实现并且一直以一种方式实现?
  • 来自 Stackoverflow 常见问题解答:“您应该只根据您面临的实际问题提出实用、可回答的问题。”您的问题含糊不清,尚不清楚答案是否会对您有所帮助。最好读一本关于实现编程语言的书。
  • @Rainer 谢谢,我希望现在更清楚了。
  • 不过,从阅读有关编程语言实现的书开始阅读,这是他们立即回答的基本问题。

标签: list dynamic lisp runtime symbols


【解决方案1】:

请注意,'(+ 1 2 A) 不是变量,而是计算结果为对象的形式 (quote (+ 1 2 A))。列表中的 A 是符号,但不是变量。

变量是用符号表示的存储位置。

回复:像 Lisp 这样的语言如何在运行时进行这种评估?

(Common) Lisp 有两种变量:动态变量和词法变量。动态变量可以在运行时进行评估,因为您可以获取一个符号并确定它是否具有动态变量绑定,然后检索或分配该绑定。

词法变量是在编译时“烘焙”的变量:没有可移植的方法来通过名称反映它们。

这两种变量都有不同的用途。

动态变量可以存储在与符号相关联的位置,称为其值单元。 (这个术语实际上出现在 ANSI Common Lisp 中)。该符号用作检索单元格(如果有的话)的一种键。例如,值单元格可以是某个 cons 单元格的 cdr 字段,该字段存储在哈希表中,其中键是符号。各种实现都是可能的。

Lisp 支持动态变量的本地重新绑定有一个复杂性:即您可以使用let 或其他绑定构造来为隐藏任何现有绑定的动态变量创建本地绑定。当构造退出时(以任何方式:包括通过throw 等的非本地退出),隐藏的绑定被恢复。这个动态范围必须以某种方式实现,这意味着动态变量查找不一定只是将指针从符号追逐到值单元格。

更复杂的是,多线程 Lisps 的用户希望每个线程绑定动态变量。

这里可能有更多信息:http://en.wikipedia.org/wiki/Scope_%28computer_science%29#Dynamic_scoping

【讨论】:

  • 很好的答案卡兹。你对符号与变量的看法是对的,我编辑了 qst 以明确它是关于符号而不是变量。所以你是说它是一个存储在哈希表中的缺点单元格?
  • 我并不是说这是存储在哈希表中的缺点,但这是可能的。值绑定可能只是从符号对象内指向类似于 cons 的东西的直接指针。该指针将被理解为符号的值绑定(与值单元格的关联)。 (makunbound <symbol>) 可以用nil 覆盖该指针,使符号没有值单元格/绑定。 (但您始终必须牢记对动态重新绑定的看法,以及线程局部动态变量的可能性。必须以某种方式将这些要求纳入表示。)
【解决方案2】:

在 Common Lisp 中,符号本身就是对象,能够拥有带有与其相关联的值的命名属性。读取时会创建符号(interned 在当前包中),如下所示:

> 'a
A

您可以使用(describe 'a)(inspect 'a)(在此处使用 CLISP)检查它们。您可以使用(set 'a 1) 设置此符号。但您也可以在此之后致电(defun a (x) (+ 1 x))。检查符号'a 现在发现它同时包含一个值和一个函数定义。这反映了 Common Lisp 对变量的值和函数具有单独的命名空间。符号将这些额外信息存储在它们的属性列表中:

[19]> (symbol-value 'a)
1
[20]> (symbol-function 'a)
#<FUNCTION A (X) (DECLARE (SYSTEM::IN-DEFUN A)) (BLOCK A (+ X 1))>
[21]> (symbol-plist 'a)
(SYSTEM::DEFINITION
 ((DEFUN A (X) (+ X 1)) .
  #(NIL NIL NIL NIL ((DECLARATION OPTIMIZE DECLARATION)))))

[44]> (setf (get 'a 'prop1) 12)
12
[45]> (symbol-plist 'a)
(PROP1 12 SYSTEM::DEFINITION
 ((DEFUN A (X) (+ X 1)) .
  #(NIL NIL NIL NIL ((DECLARATION OPTIMIZE DECLARATION)))))

另见

http://www.lispworks.com/documentation/HyperSpec/Body/f_get.htm#get http://www.lispworks.com/documentation/HyperSpec/Body/f_intern.htm#intern

【讨论】:

  • 非常有趣的威尔。一个 Lisp 符号可以同时定义一个值和一个编译函数。
  • @annoying_squid 是的,这就是所谓的 Lisp-2。方案例如是 Lisp-1,Scheme 中变量名和函数名有一个共同的命名空间。
  • 一个Lisp符号可以同时定义一个值和一个函数,当然也可以同时定义不同词法作用域的不同值,甚至可以同时定义一个动态变量和词法变量,等等。更不用说同一个符号可以同时是一个类的名称,类槽,命名块,tagbody标签,重新启动,加上一些用户定义的抽象的名称,如语法中的规则等。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-11
  • 1970-01-01
  • 2019-09-28
  • 1970-01-01
  • 2020-01-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多