sicp.io
5.1.5 · Вычислитель с явным управлением

Вычислитель с явным управлением на регистрах

Контроллер регистровой машины реализует eval и apply. Регистры exp, env, val, proc, argl, continue и unev раскрывают состояние вычислителя.

Вопрос для размышления

Что меняется, когда вычислитель больше не выражается рекурсией хост-языка и должен сохранять каждое continuation явно?

  • Диспетчеризация гостевого синтаксиса через явный контроллер eval-dispatch
  • Передача данных вычислителя через exp, env, val, proc, argl, continue и unev
  • Сохранение и восстановление незавершенной работы с операторами и операндами в машинном стеке
  • Применение примитивов и представленных составных процедур через отдельные пути контроллера
  • Восстановление continue перед вычислением последнего выражения последовательности
  • Наблюдение одинаковой максимальной глубины стека для двух хвостовых рекурсивных запусков разной длины
  • Направление if, set! и define через явные метки контроллера
  • Запуск полной гостевой программы и остановка halt с пустым стеком вычислителя

Контроллер начинает с загрузки глобального окружения и финального continuation, затем многократно выполняет диспетчеризацию по выражению в exp. Простые значения помещают свой результат в val и переходят по continue. Применения сохраняют continuation и окружение вызывающего кода, вычисляют оператор и операнды, строят argl и входят в apply-dispatch. Примитивные процедуры вызывают реализацию хост-языка, а составные процедуры устанавливают новое окружение и направляют свое тело через ev-sequence.

Вычисление последовательности является хвосторекурсивным, так как ev-sequence-last-exp восстанавливает continuation вызывающего кода перед отправкой финального выражения обратно в eval-dispatch. Поэтому два запуска sum-iter достигают одинаковой измеренной максимальной глубины стека вычислителя, хотя один из них выполняет больше рекурсивных вызовов. Отдельные пути контроллера сохраняют и восстанавливают выражение, окружение и continuation вокруг if, set! и define. Финальная гостевая программа объединяет рекурсию, состояние лексического замыкания, изменение состояния и чистую остановку. Эти наблюдения описывают данный конечный симулятор и контроллер, а не аппаратные задержки или все возможные реализации вычислителя.

Код SICP22,000 из 1,048,576 байт UTF-8
Примеры
Результат
Вывод
Значение
Диагностика
Трасса выполнения0 / 0 событий
    Запуски происходят внутри браузера с отображением результата программы и трассы выполнения.
    Ожидаемый результат

    Программа возвращает ((core 42 #t #t) (tail 15 210 #t #t #t) (state 9 9 #t) (run (120 41 42) #t #t)). Равенство в блоке tail фиксирует измеренную максимальную глубину стека вычислителя для n = 5 и n = 20 в этом контроллере.

    На что обратить внимание в трассе

    Следуйте из eval-dispatch к меткам для конкретного синтаксиса, затем найдите save и restore вокруг вычисления оператора и операндов. В запусках с хвостовой рекурсией проследите, как ev-sequence-last-exp восстанавливает continue перед началом рекурсивного применения. В запуске с состоянием проследите вычисление значений определения и присваивания до изменения глобального связывания. В финальном запуске отличите стек рекурсивного factorial от измененного захваченного связывания замыкания счетчика и убедитесь, что машина останавливается по halt без оставшихся сохраненных значений вычислителя.

    Попробуйте сами

    Измените программу и сравните результат.

    Добавьте хвостовую рекурсивную процедуру product-iter и запустите ее с двумя разными размерами входных данных. Сравните максимальную глубину стека, итоговые значения и состояние пустого стека с предоставленными наблюдениями для sum-iter.

    Показать подсказку

    Сохраняйте рекурсивный вызов последним выражением тела процедуры. Если после этого вызова ожидается еще одна операция, контроллер должен будет сохранить дополнительную незавершенную работу.

    Завершить этот урок

    В этой главе пройдено 0 из 23 урока0%