有哪些动态范围语言的例子?选择这种设计的原因是什么?是因为它易于实施吗?
5 回答
Mathematica 是另一种通过Block
构造动态作用域的语言。这在使用公式时实际上非常有用。它允许您编写诸如
In[1]:= expr = a*t^2 + b*t+ c;
In[2]:= Block[{a = 1, b = -1, c = 2}, Table[expr, {t, 5}]]
Out[2]= {2, 4, 8, 14, 22}
a
如果变量喜欢和t
在词法上作用域,这根本不起作用。它与 Mathematica 的规则重写系统配合得特别好,除其他外,如果它没有对它们的现有定义,它将使变量不被计算(作为符号表达式)。
Mathematica 可以使用该构造伪造词法范围Module
,但这实际上是用新的、据称唯一的符号重写表达式(如果您预测下一个唯一符号将是什么,可能会导致冲突,这在大多数情况下很容易)。这表示
Module[{x = 4},
Table[x * t, {t, 5}]]
将变成这样的东西:
Block[{x$134 = 4},
Table[x$134 * t, {t, 5}]
Emacs Lisp,在它的一个库中,有一个构造(实际上是一个 Lisp 宏)调用lexical-let
,它使用完全相同的技巧来伪造词法作用域。
编译语言时,真正的词法作用域具有性能优势,而使用 ELisp 或 Mathematica 的假词法是无法获得的,因为您需要在动态变量与其当前值之间进行一些映射,这意味着进行查找(通过哈希表或属性列表或其他东西)和附加的间接层。
编辑:如果您只有词法变量,则可以通过在进入范围时存储全局词法变量的原始值并保证在退出范围时恢复旧值来伪造动态范围。为了确保这一点,您需要像 LispUNWIND-PROTECT
或finally
块这样的东西。我也看到过使用 C++ 析构函数完成此操作,主要是作为练习。
动态范围的语言更容易实现。要访问不在当前激活记录/堆栈帧中的变量,只需遵循控制链接即可。然后不需要静态/词法访问链接,从而使堆栈帧更小。
动态变量在运行时可能是“不可预测的”,因为需要知道实际堆栈帧的顺序才能知道将使用哪个变量。仅通过查看代码的静态结构无法获得此信息。如果程序的实际调用图在实现时不容易预测,那么很容易被抓住。这就是今天大多数语言都有静态作用域的原因(然而,大多数异常系统都是动态的,因为这是最实用的)。
但是在某些情况下,动态范围的变量非常有用。例如,在重定向输出时,您可以使用动态变量为本地代码和从那里调用的所有代码设置标准输出。
(let ((*standard-output* *some-other-stream*))
(stuff))
在这个 common-lisp 示例(来自 Seibel)中,标准输出在 let 形式的持续时间内绑定到另一个流(在其封闭的括号内)。当执行离开时,它会回到之前的状态。请参阅http://gigamonkeys.com/book/variables.html Peter Seibels 免费且优秀的书籍 Practical Common Lisp,以获得很好的讨论。用赛贝尔自己的话说:
动态绑定使全局变量更易于管理,但重要的是要注意它们仍然允许远距离操作。绑定一个全局变量有两个远距离的影响——它可以改变下游代码的行为,它也开启了下游代码将一个新值分配给在堆栈上建立的绑定的可能性。只有当您需要利用这些特性中的一个或两个时,才应该使用动态变量。
所有的 shell 语言(bash、ksh 等)都使用动态范围。
动态范围是/更容易用解释器实现。大多数早期的 Lisp 解释器都使用动态作用域。几年后,词法作用域被发现具有优势,但最初主要在 Lisp 编译器中实现。出现了几种实现,它们在解释代码中实现了动态范围,在编译代码中实现了词法范围。有些提供了一种特殊的语言结构来提供闭包。像 Scheme 和 Common Lisp 这样的 Lisp 方言要求解释代码和编译代码之间没有区别,因此基于解释的实现也必须实现词法范围。
早期的 Smalltalk 实现实现了动态范围。各种 Lisp 方言实现都实现了动态范围(Interlisp、UCI Lisp、Lisp Machine Lisp、MacLisp,...)。
过去 20 年来几乎所有新的 Lisp 方言都默认甚至完全使用词法作用域。一些出版物已经详细描述了如何使用词法范围实现 Lisp - 所以没有理由不使用词法范围。
嗯,有很多网站讨论赞成和反对的,所以我不去那里。
XSLT 是一种有趣的语言,它有一些与动态作用域有些相似的特性。尽管 XSLT 的模板和变量等是词法范围的,但 XSLT 当然是关于 XML 的 - 并且 xml 树中的当前位置是“动态范围的”,因为上下文节点是全局的,因此不会评估 XPath 表达式根据 XSLT 的词法范围,但根据它的动态评估。