我一直在用emacs lisp弄湿手,有时让我感到震惊的是动态范围。它有很多未来吗?我所知道的大多数语言都使用静态作用域(或者已经转向静态作用域,比如Python),可能因为我知道它更好,我倾向于喜欢它。是否存在动态范围更有用的特定应用程序/实例或示例?
答案 0 :(得分: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))
(如果你使用过这种东西的话 很多,你把它封装在一个宏 - 但幸运的是,它已经完成了 “与输出到临时缓冲器”。)
这是因为'foo'使用了 动态绑定名称 '标准输出',所以你可以 替换你自己的绑定 用于修改'foo'行为的名称 - 以及'foo'的所有功能 调用
在没有动态绑定的语言中, 你可能会添加一个可选项 'foo'的参数指定一个缓冲区 然后'foo'会把它传递给任何人 打电话给'打印'。但如果'foo'打电话 其他自己称之为的功能 '打印'你必须改变那些 功能也是如此。如果'打印'有 另一种选择,比如'印刷级', 你必须添加它作为可选项 争论也是......或者,你 能够记住旧的价值 '标准输出',替代你的新 值,调用'foo'然后恢复 旧的价值。记住处理 使用'throw'的非本地退出。什么时候 你会看到这个,你会看到 你已经实现了动态 结合!
也就是说,词汇绑定对于99%的情况更好。请注意,现代Lisps不是动态绑定 - 仅限于Emacs lisp。
此外,像Lisp这样受到启发的Python和Ruby等现代语言通常以直接的方式支持词法绑定,动态绑定也可用但不那么简单。
答案 1 :(得分: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可能同样如此 好好调用任何编辑器命令 定义。所以所有的编辑 必须重写命令才能接受 并忽略其他参数。通过 现在,原始系统都没有 左!