理解闭包和方法论

Understanding Closure and Methodology

我正在构建一个解释器,现在我需要实现它来处理闭包。我非常理解这个概念,但我对为什么要这样设计它们有疑问。

就闭包而言 designed/interpreted 需要 3 件事:

  1. 变量
  2. 变量绑定到的逻辑主体
  3. 在闭包实例化期间保存的环境,这是为了在评估闭包变量时绑定主体中存在的自由变量。

我明白为什么需要所有这些东西,我只是想知道为什么在创建闭包时进行替换时需要第三项是做同样的事情?有什么我没有考虑到的吗?

基本上我要问的是为什么不在闭包创建时用相应的环境值替换自由变量而不是完全传递环境?

我想有点晚了,但是哦...

这取决于您的计算模型(例如评估策略)。 如果所有数据结构[可以被变量绑定,实际上是封闭的]在您的语言中都是不可变的,那么您的方法应该有效。 它适用于纯词汇 lisp 方言(例如方案的功能子集),漂亮而流畅。

在以下情况下它可能不起作用:

  • 您通过引用传递参数,正如评论中已经提到的那样。按值调用很好。对不可变对象的引用也很好。
  • 您的环境绑定 and/or 查找会导致一些副作用。那将是相当奇特的,但谁知道呢?

此外,请注意,您不必封闭整个环境,只需封闭函数主体的自由变量(简单!)。

[我知道]将闭包作为 body+environment 实现的唯一原因是:

  • 您可能想要传递对可变对象的引用。这种情况发生 i.a。在 js 和 python 中使用字典;随着时间的推移改变关闭有点可怕,但是哦。

  • 你不需要写替换函数。请注意,它必须保持范围界定正确,因此必须类似于您的评估函数 [如果您的计算模型是可替换的]——那为什么要重复一遍呢?值也有这种微妙的性质:在应用顺序 ("eager evaluation") 的情况下,当你替换正文中的值时,你需要将它提升到表达谁的值是东西(如果有任何机会你是实现 LISP 变体,考虑符号——您不替换值 HI!,而是表达式 (quote HI!)。这不适用于所有数据结构都自行评估的情况,例如数字或真值在大多数 LISP 中)。这些不是一般的问题,但会给您的解释器带来一些复杂性,简单就好

  • 绑定值可能会消耗内存,并且您包含的变量 [作为自由变量] 出现不止一次 - 您的主体会明显变大(例如,您的值是位图或声音样本或一些巨大的矩阵或......你明白了)。这与惰性评估的计算重复问题类似,但是是内存,而不是时间。这通常也不是问题,因为计算机内存很大。

我 运行 不知道还有什么可能会破坏,但如果你不检查你的计算模型 "on paper" (通过等式推理)你应该实施它并尝试最棘手的案例 [如果其中任何一项适用]:副作用、惰性求值、引用、可变对象、上述的组合。它们绝对不是障碍,只是值得检查的地方。 希望对您有所帮助,祝您翻译顺利!

PS 如果您想考虑这类问题,请查看去功能化(Danvy 和 Nielsen 的 "Defunctionalization at Work" 是一本非常容易阅读的书,您应该对第一部分感到满意一些灵感)