CLtL2 阐明了范围和范围之间的区别。对于词法变量和特殊变量,我的看法是,词法变量是“无限范围的词法范围”,而特殊变量是“无限范围的动态扩展”。</p>
我的问题是:“词法和特殊变量”语义一般是如何在幕后实现的?我所说的“一般”是指一个一般的想法就足够了。鉴于 Lisp 的悠久历史,必须有许多优化已应用于实现这些基本概念。
为了启动讨论,我在下面大胆猜测。
一切都从环境开始。环境是一系列帧,每个帧都是一个将名称映射到位置的表(可以检索和存储其值);每个这样的映射都是一个名字到一个地方的绑定。框架通过封闭关系链接;内部框架中的名称可以覆盖外部框架中的相同名称。此外,Common Lisp 中的绑定默认是词法的,除非declare
-d/ declaim
-ed/ proclaim
-ed 是特殊的。
语义有两个方面:名称查找和新绑定的创建。
创建一个新的绑定。
lambda
表达式、let
/let*
、labels
/flet
、macrolet
和使用它们的宏创建绑定。词法绑定是通过创建一个新框架并使当前词法环境成为新创建的框架的封闭环境来创建的。一个特殊的绑定(必须显式声明)将一个新位置推到为当前包中的名称创建的堆栈顶部(堆栈可以通过名称上的哈希表定位)——堆栈用于实现动态范围,以便在构造表单退出时,可以通过弹出堆栈来解构绑定(问题是如何确保如此,也许unwind-protect
在引擎盖下有类似的东西?)。名称查找。除非明确声明为特殊,否则名称查找默认为在词法环境中查找——通过在绑定创建期间建立的框架链接。查找过程中第一个匹配的名称获胜。对于特殊名称(必须明确声明),查找是通过查看堆栈顶部来提供的。