Песочница

Связывания, область, ячейки и изменение

Каждое лексическое связывание — изменяемая ячейка. Замыкания захватывают кадры и видят последующие изменения той же ячейки через `set!`.

Когда это нужно

Связывание даёт результату имя, создаёт локальную область или намеренно сохраняет состояние между вызовами. Обычно достаточно define и let; используйте set!, только если совместное изменение входит в модель.

Проверьте запуском

LISPEX
(define x 1)
(define get (lambda () x))
(set! x 2)
(get)

Наблюдаемый результат

OUTPUT
2

Разбор примера

get захватывает глобальную ячейку x, а не замороженную копию числа 1. set! записывает 2 в ту же ячейку, поэтому следующий вызов видит 2. Новая внутренняя x лишь затенила бы внешнюю.

Как рассуждать

  • Поиск выбирает ближайшую лексическую ячейку; затенение не изменяет внешнее связывание.
  • letrec выделяет ячейки до инициализаторов и выдаёт E321 при чтении неинициализированной ячейки.
  • Повторный верхнеуровневый define обновляет существующую глобальную ячейку, сохраняя ссылки старых замыканий.

Быстрый выбор

ФормаНазначениеГде вычисляются инициализаторы
defineверхнеуровневое имя или именованная процедуратекущая верхняя область
letнезависимые локальные значениявнешняя область
let*локальные значения с зависимостями по порядкувсе предыдущие связывания
letrecвзаимно рекурсивные локальные процедурывсе выделенные ячейки; раннее чтение ошибочно
set!изменение существующей ячейкиновое связывание не создаётся

Частая ошибка

set! для несвязанного имени даёт E303 и не создаёт связывание.

Текущие границы

  • Внутренний маркер неинициализированности нельзя представить гостевым значением.

Куда дальше

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

Процедуры · Руководство по замыканиям