Переназначает не-функцию функцией с set! создать новую рамку?

Меня смущает следующий код:

(define (even-or-odd-letrec x)
  ((lambda (internal-even? internal-odd?)
     (set! internal-even? (lambda (n)
                (if (= n 0) 'even
                    (internal-odd? (- n 1)))))
     (set! internal-odd? (lambda (n)
               (if (= n 0) 'odd
                   (internal-even? (- n 1)))))
     (internal-even? x))
   #f #f))

Насколько я читал, окружение выглядит следующим образом:

  1. Внутри окружения even-or-odd-letrec, internal-even? и internal-odd? изначально привязаны к #f. Их родительской средой является глобальная среда.
  2. set! затем меняет эти два значения на очевидные lambdas, но не меняет среды.
  3. Поскольку окружение не изменилось, любые вызовы internal-even? будут искать internal-odd? в глобальном окружении и ничего не найдут.

Так как же работает этот код?

3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
1
0
52
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Отвечая на заголовок вашего вопроса: нет, установка не создает новых кадров.

Параметр задает значение привязки в текущем фрейме среды. Какими бы ни были старые и новые ценности. Функция или нет, не имеет значения.

Опять же, set! не меняет значения. Он изменяет значения привязки. Привязка — это сочетание имени и его значения. Set!ting изменяет связанное значение этого имени.

Рассматриваемое как именованный указатель, после повторного set! имя указывает на новое значение — то значение, которое было передано set! в качестве второго аргумента.

Итак, вопреки тому, что вы говорите, set! делает сдача текущий фрейм среды - он изменяет свою привязку для заданного имени, которое установлено.

  +---------------+                  +---------------+
  |  n1 ---> v1   |                  |  n1 ---> x    |
  |  n2 ---> v2   |   (set! n1 x)    |  n2 ---> v2   | 
  |---------------|  ------------->  |---------------| 
  |  ..code...    |                  |  ..code...    |
  |_______________|                  |_______________|

«Любой звонок в internal-even? будет» ..... стоп! это не правильный взгляд на это.

Любая ссылка на internal-even? внутри фрейма, созданного lambda, будет разрешена путем поиска значения под именем internal-even? в том же фрейме, и все будет работать нормально.

Когда вы (set! internal-even? (lambda (...) ... internal-odd? ...)), это правда, что ценностьinternal-odd? все еще не то, чем должно быть, но это нормально, потому что его значение еще не просматривается, потому что internal-even? еще не запущен. Когда вычисляется лямбда-выражение (здесь, как часть вызова set!), его значением является функция, которая говорит: когда придет время, когда эта функция запустится, потом ищет в ней значение любого имени по мере необходимости.

При применении к двум значениям аргумента (lambda (internal-even? internal-odd?) ...) создает новую среду с привязками для internal-even? и internal-odd?. Все в этой среде, которое ссылается на internal-even? или internal-odd?, будет ссылаться на текущее значение этих привязок во время выполнения кода. set!мутирует эту среду, изменив значения привязок, так что текущие значения этих привязок теперь представляют собой две процедуры, которые сами ссылаются на текущие значения этих привязок.


На мой взгляд, самый простой способ понять это — реализовать небольшой интерпретатор. Это очень легко сделать: вы используете списки для сред, оценщику нужно довольно много обрабатывать if, lambda и set! как особые случаи. Каждый должен написать один из них.

Я думаю, что меня смущает то, что set! должен оценивать свой второй аргумент, и оценка этого второго аргумента вызовет бессмыслицу. Например, повторное связывание (и, следовательно, оценка) internal-even?, когда internal-odd? все еще установлено на #f, не даст вам того, что вы хотите.

J. Mini 23.04.2022 16:27

@ J.Mini в конце концов, вы объясняете свое замешательство!.... :) Я отредактировал свой ответ с объяснением.

Will Ness 23.04.2022 17:03

@J.Mini: как сказал Уилл Несс, при оценке такой формы, как (lambda (...) ...), нет просматривает значения переменных в теле функции: он может проверять, что эти переменные существовать (или будут существовать, в случае переменных, связанных функцией себя) и жалуются, если они этого не делают (например, Racket делает это), но они не просматриваются до тех пор, пока функция не будет вызвана, и значения, которые извлекаются, являются значениями, которые существуют в этот момент.

ignis volens 23.04.2022 17:07

Установка переменной не привязывает новое местоположение. Обратите внимание, однако, что привязка новой переменной не означает создание/увеличение кадра. Можно (как и в C) хранить переменные в регистрах, а не во фреймах, или вообще не хранить их, если вы можете доказать что-то о поведении переменной.

Другие вопросы по теме