2010-06-05 59 views
8

我一直在用emacs lisp弄湿自己的双手,有时候让我往上走的一件事就是动态范围。它有很大的未来吗?我知道的大多数语言都使用静态范围(或者已经转向静态范围,如Python),可能因为我知道它更好,我倾向于选择它。有动态范围更有用的特定应用程序/实例或示例吗?用于动态范围?

+2

很多[这里有用的答案](http://stackoverflow.com/questions/321000/dynamic-scoping-why) - 也许这是足够接近,是重复的? – 2010-06-05 06:43:47

+0

是的,看起来像。我的错。 – hatmatrix 2010-06-05 08:22:29

回答

14

这个问题有很好的讨论here。与您的问题有关的最有用的部分是:

动态绑定非常适合修改子系统的行为 。 假设您使用的功能'foo' 使用'print'生成输出。 但有时你想 捕获你的 选择的缓冲区中的输出。动态绑定,这是 简单:

(let ((b (generate-new-buffer-name " *string-output*")))) 
    (let ((standard-output b)) 
     (foo)) 
    (set-buffer b) 
    ;; do stuff with the output of foo 
    (kill-buffer b)) 

(如果你使用这种事情 很多,你将其封装在一个宏 - 但幸运的是,它已经完成的 “与输出到临时缓冲”。)

这工作,因为“富”使用 动态名称 “标准输出”的结合,这样你就可以 替换自己对于T绑定帽子 的名称来修改'foo' 的行为以及'foo' 调用的所有功能。

在语言没有动态绑定, 你可能会添加一个可选 参数“富”来指定一个缓冲区 然后“富”将传递到任何 调用“打印”。但是,如果'foo'调用 其他函数,它们本身被称为 '打印',你也必须改变这些函数。如果'打印'有 另一个选项,说'打印级', 你必须添加,作为一个可选的 参数以及...或者,你 可以记住旧的价值 '标准输出',替换您的新值 值,请调用'foo',然后恢复旧值 。请记住使用'throw'处理 非本地出口。当 你完成了这个,你会看到 ,你已经实现了动态 绑定!

这就是说,词汇绑定是恕我直言,99%的情况下好得多。请注意,现代Lisp不是动态绑定的 - 只能像Emacs lisp一样。

  • Common Lisp的支持结合两种形式,但词汇一个使用更
  • 该计划规范甚至不指定动态绑定(仅限词汇之一),但许多实现支持。

另外,受到Lisp启发的现代语言(如Python和Ruby)通常直接支持词法绑定,动态绑定也可用,但不那么直接。

7

如果您阅读Emacs paper(1981年写),有一个特定的部分"Language Features for Extensibility"解决这个问题。在Emacs中,还增加了缓冲区本地(文件本地)变量的范围。

我引用下面的最相关的部分:

Formal Parameters Cannot Replace Dynamic Scope

一些语言的设计者认为, 动态绑定应避免和 明确的参数传递应该 代替。假设函数A 绑定了变量FOO,并且调用了函数B,该函数调用函数 C,并且C使用FOO的值。 据说A应该传递值作为 的参数B,其应该通过它 作为参数传递给C.

这不能以可扩展 系统然而做,由于 作者系统无法知道什么参数都是 。想象一下, 函数A和C是用户 扩展的一部分,而B是 标准系统的一部分。标准系统中不存在变量FOO ;它是 是扩展的一部分。要使用 明确的参数传递就 需要添加新的参数B, 这意味着改写B和一切 调用B.在最常见的情况, B为编辑命令分派 循环,这是从一个可怕的叫 个地方。

更糟糕的是,C还必须通过一个 附加参数。 B没有将名称 指向C(编写B 时不存在C)。它可能在命令调度 表中找到指向C的指针 。这意味着相同的呼叫 ,有时调用C可能同样 以及任何编辑命令调用 定义。因此,所有编辑 命令都必须重写为接受 并忽略其他参数。现在通过 ,原来的系统都不是 了!

+0

优秀的报价!这真的是动态绑定有用的绝佳例子。感谢分享! – 2010-06-06 04:22:05

+0

非常感谢 - 说明 – hatmatrix 2010-06-09 06:35:53