用于动态范围?

时间:2010-06-05 06:32:06

标签: lisp scope elisp

我一直在用emacs lisp弄湿手,有时让我感到震惊的是动态范围。它有很多未来吗?我所知道的大多数语言都使用静态作用域(或者已经转向静态作用域,比如Python),可能因为我知道它更好,我倾向于喜欢它。是否存在动态范围更有用的特定应用程序/实例或示例?

2 个答案:

答案 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。

  • Common Lisp支持这两种形式的绑定,不过词法的使用方式更多
  • Scheme规范甚至没有指定动态绑定(只有词法),尽管许多实现都支持这两种。

此外,像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可能同样如此   好好调用任何编辑器命令   定义。所以所有的编辑   必须重写命令才能接受   并忽略其他参数。通过   现在,原始系统都没有   左!