1

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

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

我知道在编译期间检测到静态范围,而仅在运行时检测到动态范围。并且动态范围被认为难以调试,有时也难以推理。

如果我们将上述事实放在一边,我不确定我是否理解为什么静态范围通常被认为比动态范围更好?

4

3 回答 3

6

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

于 2012-08-19T19:36:47.087 回答
3

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

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

于 2012-08-19T22:27:43.163 回答
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+

现在,这两种行为都遵循简单、可预测的规则。但请注意,在词法范围的情况下,您可以查看 的定义,make-adder并能够将引用与本地n声明相关联,而无需了解将使用的上下文。在动态范围的情况下,情况并非如此。(事实上​​,在动态作用域下,to 的论点是完全多余的。)make-addermake-adder

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

于 2012-08-20T09:54:05.593 回答