How to implement closure in the LISP interpreter

I am currently working on a LISP interpreter written in Java. Now I'm stuck in closing. I want to enable these locks:

(define a 1000) (define closure (lambda (a) (lambda (b) (+ ab)))) (define x (closure 10)) (x 20) --> 30 

So (x 20) should return 30 . But guess what, it returns 1020 in my interpreter. I think the error is in my lambda class. It looks like this:

 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); } } 

This class works fine, but it does not preserve the environment to provide closure. Does anyone have an idea how to do this? And where to do it? In the constructor or in the eval method?

And if I do not do this:

 environment = environment.copy(); 

Closing works, but it interrupts some other tests.

Thanks.

(I can also download the whole source or give it for free in GIT).

+2
source share
2 answers

This class works fine, but it does not preserve the environment to provide closure. Does anyone have an idea how to do this? And where to do it? In the constructor or in the eval method?

Yes, the class should keep the environment. Generally speaking, a member variable. :)

It must be in the constructor because the environment is bound during lambda build, not during eval.

At eval time, the source environment is not available: the new environment.

If your dialect is lexically limited, your lambda does not need an environment parameter. Remember what lambda is? This is a function. Form evaluation requires an environment. Function evaluation is not performed; function evaluation is a function call and takes only arguments. Environments do not go into functions; functional bodies are evaluated in an encapsulated space with their own private environment. (Having the eval function on a lambda even seems wrong, you want it to be called call or something like that. The interpreted lambda uses the evaluator services, but it is not alone.)

Inside the lambda, the action will be to evaluate the body shape of the lambda. They will use the stored environment (not everything that was transferred).

You must create an environment in which lambda parameters are bound to argument values. It is embedded in a captured environment. (Ie argument called x obscures the captured variable called x ).

(You already have some way of nesting the environment, for example, to create new bindings that relate to the external environment.)

If you want to support dynamic scaling in addition to lexical, there should not be a need to pass the environment for this; this can be done implicitly. A local thread variable may support a dynamic environment or something like that.

(The details depend on the design of the interpreter, in some projects there is always some context object (representing the interpreter). If you go, say, to the bytecode of a virtual machine with an explicit stack, you will need to.)

+4
source

I highly recommend reading the Christian Queinnec Lisp book in Small Pieces , which describes in detail many ways to implement Lisp (or schemes like) evaluators, interpreters, compilers.

You will need to handle differently closed values ​​from local values.

+2
source

All Articles