了解编译器中递归闭包的建模

Understanding modeling of recursive closures in compilers

我得到了关于为类 lisp 语言建模递归闭包的两种方法的描述。假设我有以下代码:

(letrec ((f (fun (l) … (map f l) …)))) …)

对于对应于 f 的闭包,我可以:

  1. f当做一个自由变量,放在自己的环境中导致循环闭包。
  2. 使用平面闭包,环境就是闭包,可以直接重用。

我正在使用平面闭包的概念,它在第一个单元格中存储一个指向函数的指针,在其余单元格中存储自由变量。但是我对第二个选项感到困惑,因为在我看来,第一次和第二次调用接收不同的参数。那么他们怎么可能获得相同的闭包并且不需要将递归调用作为自由变量来区分它们?

也许您可以解释一下在典型编译器的后续步骤中如何解决这个问题?

每次调用 f 都会为 l 创建一个具有新值的新闭包(假设词法作用域)。 f 主体中的闭包通常不会包含 f,但父级会包含,因此您最终会查找调用堆栈。

我写了一篇 post 对此进行了更详细的介绍:http://cinigl.io/posts/nested-variable-scoping