除了Logo和Emacs Lisp之外,还有哪些纯粹的动态作用域语言?

16

有哪些动态作用域语言的例子?为什么选择这种设计?是因为它易于实现吗?


从前,我所知道的所有Lisp版本都具有动态作用域。elisp是那个时代的最后幸存者之一。 - David Thornley
6个回答

11

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}

如果变量像at具有词法作用域,那么这根本行不通。它在Mathematica的规则重写系统中特别有效,如果没有现有定义,它会将变量保留为未评估的(作为符号表达式)。Module结构可以模拟词法作用域,但实际上是使用新的、独特的符号重写表达式(如果您预测下一个独特符号将是什么,在大多数情况下这很容易导致冲突)。这意味着......
Module[{x = 4}, 
  Table[x * t, {t, 5}]]

将被转换成类似于这样的内容:
Block[{x$134 = 4},
  Table[x$134 * t, {t, 5}]

在Emacs Lisp的一个库中,有一个叫做lexical-let的结构(实际上是一个Lisp宏),用来模拟词法作用域。但是,与ELisp或Mathematica的虚假词法不同,真正的词法作用域在编译语言时具有性能优势,因为您需要一些映射来表示动态变量及其当前值,这意味着需要进行查找(通过哈希表或属性列表等)和额外的间接层。
编辑:如果只有词法变量,则可以通过在进入作用域时将全局词法变量的原始值存储起来,并保证在退出作用域时恢复旧值来模拟动态作用域。为了确保这一点,您需要像Lisp的UNWIND-PROTECTfinally块这样的东西。我也看到过使用C++析构函数来实现这个目的,主要是作为练习。

9
动态作用域语言更易于实现。要访问不在当前激活记录/堆栈帧中的变量,只需跟随控制链接。静态/词法访问链接则不需要,从而使堆栈帧更小。
动态变量在运行时可能是“不可预测的”,因为需要知道实际堆栈帧的顺序才能知道将使用哪个变量。通过仅查看代码的静态结构无法获得此信息。如果程序的实际调用图在实现时不容易预测,则很容易被捕捉到。这就是为什么大多数语言今天都具有静态作用域(但大多数异常系统是动态的,因为这是最实用的)。
但是,在某些情况下,动态作用域变量非常有用。例如,在重定向输出时,您可以使用动态变量设置本地代码和从那里调用的所有代码的标准输出。
(let ((*standard-output* *some-other-stream*))
 (stuff))

在这个Common Lisp的例子中(来自Seibel),标准输出被绑定到另一个流,只在let表达式(在其封闭括号内部)的持续时间内有效。当执行离开let时,它会回到之前的状态。请参阅Peter Seibels免费且优秀的书籍《Practical Common Lisp》http://gigamonkeys.com/book/variables.html,进行深入讨论。用Seibels自己的话说:
“动态绑定使全局变量更加可管理,但是需要注意它们仍然允许远程操作。绑定全局变量具有两种远程影响--它可以改变下游代码的行为,并且还打开了下游代码将新值分配给在堆栈上方建立的绑定的可能性。只有在需要利用这些特性之一或两者时才应使用动态变量。”

4
所有的shell语言(bash,ksh等)都使用动态作用域。

fish shell是一个值得注意的例外。 - UTF_or_Death

3
动态作用域在解释器中更易实现。大多数早期的Lisp解释器都使用动态作用域。经过几年的发展,发现词法作用域具有优势,但最初主要是在Lisp编译器中实现的。出现了一些实现在解释代码中使用动态作用域,在编译代码中使用词法作用域的实现。其中一些提供了一个特殊的语言结构来提供闭包。Lisp方言如Scheme和Common Lisp要求解释代码和编译代码之间没有区别,因此基于解释器的实现也必须实现词法作用域。
早期的Smalltalk实现实现了动态作用域。所有Lisp方言实现都实现了动态作用域(Interlisp、UCI Lisp、Lisp Machine Lisp、MacLisp等)。
近20年来,几乎所有新的Lisp方言默认或仅使用词法作用域。有几篇出版物详细描述了如何实现带有词法作用域的Lisp - 因此没有理由不使用词法作用域。

3

好的,有许多网站讨论了优缺点,这里不再赘述。

一种有趣的语言,它具有某些类似于动态作用域的特性是XSLT;虽然XSLT的模板、变量等都是词法作用域的,但XSLT当然是关于XML的 - 当前在xml树中的位置是“动态作用域”,因此上下文节点是全局的,XPath表达式的求值不是按照XSLT的词法作用域进行,而是按照它的动态评估进行。


0

m4具有pushdef/popdef,这是一种典型的动态作用域实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接