sicp.io
3.1.4 · Издержки введения присваивания

Утрата ссылочной прозрачности при присваивании

Зависимость от предыстории, зависимость от порядка и чувствительные к псевдонимам наблюдения, когда вызовы меняют сохраненные ячейки памяти.

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

Какие рассуждения о подстановке и изменении порядка становятся неверными, когда выражение может изменять состояние?

  • Сравнение повторных вызовов с состоянием и повторных чистых вызовов
  • Распознавание того, что одинаковые выражения исходного кода со временем могут давать разные значения
  • Явное задание двух расписаний вычисления вместо опоры на порядок операндов
  • Наблюдение за тем, как более ранний вызов изменяет смысл последующего вызова
  • Фиксация точного конечного расписания и порядка его вычисления

Два вызова одной и той же процедуры withdraw с одним и тем же аргументом возвращают 90, а затем 80, поскольку первый вызов изменяет захваченный balance. Поэтому замена обоих вызовов одним ранее вычисленным значением изменила бы программу. Чистая процедура withdraw-value не имеет скрытой предыстории, поэтому два вызова с одним и тем же явным balance возвращают 90.

Зонд порядка делает зависимость от расписания явной с помощью связываний let. Сначала вызов с сообщением 0 изменяет состояние, а затем сообщение 1 считывает его. Если первым вызывается сообщение 1, оно наблюдает прежнее состояние. Ни один из выводов здесь не зависит от того, какой порядок операндов выбирает вычислитель. Обе последовательности записаны раздельно и сравниваются как данные.

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

    Программа с повторениями возвращает (90 80 90 90). Явные расписания возвращают ((0 1 1) (0 0 0)).

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

    Найдите присваивание balance между двумя одинаковыми вызовами с состоянием, а затем убедитесь, что чистые вызовы не создают постоянной ячейки памяти. При сравнении расписаний проследите за первым вызовом перед вторым и определите точную операцию чтения, значение которой изменяется.

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

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

    Добавьте сообщение reset в зонд порядка и сравните zero-reset-one с zero-one-reset. Объясните, какая алгебраическая подстановка или изменение порядка вызовов изменили бы каждое из наблюдений.

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

    Запишите каждый вызов во вложенном let, чтобы расписание стало частью исходного кода, а не предположением о вычислении аргументов.

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

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