Это не тот ответ, который, похоже, вызывает здесь голосование "за", но я от всей души призываю вас найти ответ на свой вопрос, прочитав учебник Шрирама Кришнамурти (бесплатно!) (Онлайн!), Языки программирования: приложение и интерпретация .
Я перефразирую книгу очень, очень кратко, суммируя развитие крошечных крошечных переводчиков, через которые она вас ведет:
- язык арифметических выражений (AE)
- язык арифметических выражений с именованными выражениями (WAE);
реализация этого включает в себя разработку функции substitution , которая может
заменить имена на значения
- язык, который добавляет функции первого порядка (F1WAE): использование функции предполагает замену
значения для каждого из имен параметров.
- Тот же язык, без подстановки: оказывается, что «окружения» позволяют избежать накладных расходов при упреждающей замене.
- язык, который устраняет разделение между функциями и выражениями, позволяя
функции, которые должны быть определены в произвольных местоположениях (FWAE)
Это ключевой момент: вы реализуете это, и затем вы обнаруживаете, что с заменой это работает нормально, но с окружениями это не работает. В частности, чтобы исправить это, вы должны обязательно связать с определением оцененной функции среду, которая была на месте, когда она была оценена. Эта пара (fundef + Environment-of-Definition) является тем, что называется «замыканием».
Уф!
Хорошо, что происходит, когда мы добавляем изменяемые привязки к изображению? Если вы попробуете это сами, вы увидите, что естественная реализация заменяет среду, которая связывает имена со значениями, средой, которая связывает имена с привязками. Это ортогонально понятию замыканий; поскольку замыкания захватывают среды, а среды теперь отображают имена на привязки, вы получаете описанное вами поведение, благодаря которому мутация переменной, захваченной в среде, является видимой и постоянной.
Опять же, я очень призываю вас взглянуть на PLAI .