为什么静态作用域通常被认为比动态作用更好?

时间:2012-08-19 19:02:22

标签: lisp scheme

我不确定我是否理解正确,为什么在旧版本的Lisp中没有实现静态作用域,只有动态作用域。已经发明了Scheme的Sussman和Guy L. Steele Jr.只实现了静态范围。

我发现有时候静态变量更方便使用,因为它们可以用作完美的状态持有者,尽管我们应该小心避免不希望的名称冲突,因为这是不希望的副作用。

我知道在编译期间检测到静态作用域,而动态作用域仅在运行时检测到。并且动态范围被认为是难以调整的,有时甚至是为了推理。

如果我们抛开上述事实,我不确定我理解为什么静态范围通常被认为比动态范围更好?

3 个答案:

答案 0 :(得分:6)

动态范围的根本问题在于它不是组合,从而违反了抽象。特别是,一段代码(比如一个函数)的行为通常取决于它的调用位置,以及调用者站点可见的定义。因此,调用者必须小心不要定义与被调用者使用的(非本地)冲突的名称。因此,调用者必须知道每个被调用者的实现细节。这造成了可怕的模块化。特别是,对函数实现的更改可能会破坏所有调用者。

答案 1 :(得分:3)

对于程序员来说,词法作用范围更好,因为它使他们能够推理更好地了解他们的程序。特别是,他们可以从源代码(本地)推断出程序,而不是动态行为。

此外,您可以使用动态绑定功能(如参数)将约束形式的动态范围添加到语言中。 SRFI-39是Scheme的一般提案。另请参阅“球拍指南”中的parameters。这使您可以在词法范围的语言中获得动态作用域的大部分好处(这是更好的默认值)。

答案 2 :(得分:3)

考虑以下定义:

(define (make-adder n)
  (lambda (x) (+ x n)))

现在,当你致电(make-adder 2)时,你会找回一个功能。这个功能有什么作用?我们来看看:

(let ((add2 (make-adder 2)))
  (let ((n 10))
    (add2 n)))
;=> ?

上述代码将评估什么?这取决于范围规则:

  1. 在词法范围的Scheme中,结果将为12,因为n定义中的make-adder与示例代码中的n不同。
  2. 在(假设的)动态范围的方案中,结果将为20,因为n在调用10时已经反弹到+
  3. 现在,这两种行为都遵循简单,可预测的规则。但请注意,在词法范围的情况下,您可以查看make-adder的定义,并且能够将对n的引用与其声明 local 相关联,而不知道将使用make-adder的上下文。在动态范围的情况下,情况并非如此。 (事实上​​,make-adder的论证在动态范围界定下完全是多余的。)

    因此,在推理make-adder的行为时,词法范围是一个优势,这就是为什么它通常(但不总是)首选。