Как реализовать замыкания в интерпретаторе LISP

2

В настоящее время я работаю над интерпретатором LISP, написанным на Java. Теперь я застрял в закрытии. Я хочу включить такие блокировки:

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

Итак, (x 20) должен возвращать 30. Но, угадайте, что, он возвращает 1020 в моем интерпретаторе. Я думаю, что ошибка в моем классе лямбда. Это выглядит так:

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).

  • 1
    Закрытие должно (по определению) содержать закрытые значения.
  • 1
    Я придумал версию JScheme 1998 года, которая может делать замыкания. Возможно, вы захотите взглянуть на код на github.com/ravn/jscheme-1998
Показать ещё 1 комментарий
Теги:
lisp
closures
interpreter

2 ответа

4
Лучший ответ

Этот класс отлично работает, но он не сохраняет значения среды, чтобы обеспечить закрытие. У кого-то есть идея, как это сделать? И где это сделать? В конструкторе или в методе eval?

Да, класс должен сохранять среду. Вообще говоря, переменная-член.:)

Он должен быть в конструкторе, потому что среда привязана во время построения лямбда, а не во время eval.

В eval время исходная среда недоступна: новая среда.

Если ваш диалект лексически ограничен, ваш лямбда не нуждается в параметре среды. Помните, что такое лямбда? Это функция. Для оценки форм требуется среда. Оценка функций не выполняется; оценка функции является вызовом функции и принимает только аргументы. Среды не переходят в функции; функциональные тела оцениваются в инкапсулированном пространстве со своей собственной частной средой. (Наличие функции eval на лямбда даже кажется неправильным, вы хотите, чтобы это было названо call или что-то в этом роде. Интерпретируемая лямбда использует службы оценщика, но она не одна.)

Внутри лямбды действие будет состоять в том, чтобы оценить формы тела лямбды. Они будут использовать хранимую среду (не все, что было передано).

Вы должны создать среду, в которой параметры лямбда имеют привязки к значениям аргумента. Это вложено в захваченную среду. (I.e. аргумент под названием x затеняет захваченную переменную под названием x).

(У вас уже есть какой-то способ вложенности среды, например, для создания новых привязок, которые относятся к внешней среде.)

Если вы хотите поддерживать динамическое масштабирование в дополнение к лексическому, не должно быть необходимости передавать среду для этого; это может быть сделано неявно. Локальная переменная потока может поддерживать динамическую среду или что-то в этом роде.

(Детали зависят от дизайна интерпретатора, в некоторых проектах всегда присутствует некоторый объект контекста (представляющий интерпретатор). Если вы переходите, скажем, к байт-коду виртуальной машины с явным стеком, вам понадобится.)

2

Я настоятельно рекомендую прочитать книгу Christian Queinnec Lisp в Small Pieces, в которой подробно описаны многие способы реализации Lisp (или схемы как) оценщики, интерпретаторы, компиляторы.

Вам нужно будет обрабатывать по-разному закрытые значения из локальных значений.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню