我目前正在研究用 Java 编写的 LISP 解释器。现在我坚持关闭。我想启用这样的闭包:
(define a 1000)
(define closure (lambda (a) (lambda (b) (+ a b))))
(define x (closure 10))
(x 20) --> 30
因此,(x 20)
应该返回 30
。但是,你猜怎么着,它在我的解释器中返回 1020。我认为错误出在我的 lambda 类中。它看起来像这样:
public class LLambda extends LOperation {
private LList parameters;
private LList definitions;
public LLambda(LList parameters, LList definitions) {
this.parameters = parameters;
this.definitions = definitions;
}
public LObject eval(Environment environment, LObject tokens) {
environment = environment.copy();
for(int i = 0; i < parameters.size(); i++) {
LSymbol key = LSymbol.create(parameters.get(i));
LObject object = ((LList) tokens).get(i);
object = object.eval(environment, tokens);
environment.put(key, object);
}
return definitions.eval(environment, tokens);
}
}
这个类工作正常,但它不存储环境值来启用闭包。有人知道该怎么做吗?在哪里做?在构造函数中还是在 eval 方法中?
而且,如果我不执行此操作:
environment = environment.copy();
闭包有效,但它破坏了一些其他测试。
谢谢。
(我也可以上传整个源代码或在 GIT 中免费提供)。
最佳答案
此类工作正常,但它不存储环境值以启用闭包。有人知道该怎么做吗?在哪里做?在构造函数中还是在 eval 方法中?
是的,类应该存储环境。一般来说,一个成员变量。 :)
它应该在构造函数中,因为环境是在构造 lambda 时绑定(bind)的,而不是在 eval 时。
在评估时,原始环境不可用:新环境可用。
如果你的方言是纯词法范围的,那么你的 lambda 不需要环境参数。请记住,什么是 lambda?它是一个函数。 表单的评估需要一个环境。 函数的评估没有;函数的评估是一个函数调用,它只接受参数。环境不会传递给函数;函数体在具有自己私有(private)环境的封装空间中求值。 (在 lambda 上存在 eval
函数甚至看起来是错误的;您希望将其命名为 call
或类似的名称。解释的 lambda 使用 评估者的服务;但它不是一个。)
在您的 lambda 中,操作将是评估 lambda 主体的形式。这些将使用存储的环境(而不是传入的任何内容)。
您必须建立一个环境,让 lambda 参数绑定(bind)到参数值。这嵌套在捕获的环境中。 (即一个名为 x
的参数隐藏了一个名为 x
的捕获变量)。
(您必须已经有一些嵌套环境的方法;即构建一些引用外部环境的新绑定(bind)。)
如果除了词法之外还想支持动态作用域,则不需要为此传递环境;它可以隐式完成。线程局部变量可以维护动态环境或类似的东西。
(细节取决于解释器设计;在某些设计中,总是传递一些上下文对象(代表解释器)。如果你去,比如说,一个带有显式堆栈的字节码虚拟机,你将需要那个.)
关于java - 如何在 LISP 解释器中实现闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10161802/