如何将闭包实现到LISP解释器中

时间:2012-04-15 11:55:05

标签: java lisp closures interpreter

我目前正在研究用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中免费提供。)

2 个答案:

答案 0 :(得分:4)

此类工作正常,但它不存储环境值以启用闭包。有人知道怎么做吗?在哪里做?在构造函数或eval方法中?

是的,该课程应该存储环境。一般来说,是一个成员变量。 :)

它应该在构造函数中,因为环境在构造lambda时绑定,而不是在eval时间。

在eval时间,原始环境不可用:新环境是。

如果您的方言纯粹是词法范围,那么您的lambda不需要环境参数。记住,什么是lambda?这是一个功能。 表单的评估需要一个环境。 函数的评估没有;函数的求值是一个函数调用,只需要参数。环境不会传递到功能中;函数体在具有自己的私有环境的封装空间中进行评估。 (在lambda上存在eval函数甚至看起来是错误的;您希望将其命名为call或类似的东西。解释的lambda 使用评估程序的服务;但它不是一个。)

在lambda中,动作将是评估lambda体的形式。这些将使用存储的环境(不是传入的任何内容)。

您必须建立一个lambda参数绑定到参数值的环境。这嵌套在捕获的环境中。 (即,一个名为x的参数会影响一个名为x的捕获变量。

(你必须已经有一些嵌套环境的方法;即构建一些引用外部环境的新绑定。)

如果你想支持除词法之外的动态范围,那么就不需要为此传递环境;它可以隐含地完成。线程局部变量可以维护动态环境或类似的东西。

(细节取决于解释器设计;在某些设计中,总会有一些上下文对象传递(代表解释器)。如果你去一个具有显式堆栈的字节码虚拟机,你将需要。)

答案 1 :(得分:2)

我强烈建议阅读Christian Queinnec的书Lisp in Small Pieces,其中详细描述了实现Lisp(或类似Scheme)评估器,解释器和编译器的许多方法。

您需要处理来自本地值的不同闭合值。