Переназначает не-функцию функцией с 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? в глобальном окружении и ничего не найдут.

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

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
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) хранить переменные в регистрах, а не во фреймах, или вообще не хранить их, если вы можете доказать что-то о поведении переменной.

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