Простое и глубокое связывание - это точки зрения интерпретатора Lisp псевдокода.Скоупинг - просто указательная арифметика.Динамическая область и статическая область одинаковы, если нет свободных переменных.
Статическая область зависит от указателя на память.Пустые среды не содержат символа для оценки ассоциаций;обозначается словом «Конец».Каждый раз, когда интерпретатор читает назначение, он освобождает место для связи между символом и значением.
Указатель среды обновляется, чтобы указывать на последнюю построенную связь.
env = End
env = [u,42] -> End
env = [v,69] -> [u,42] -> End
env = [w,17] -> [v,69] -> [u,42] -> End
Позвольте мне записатьэта область памяти среды как AAA .В моем интерпретаторе Lisp, когда мы встречаемся с процедурой, мы берем указатель окружения и кладем его в наш карман.
env = [add,[closure,(lambda(z)(setq u (+ v u z)),*AAA*]]->[w,17]->[v,69]->[u,42]->End.
Это почти все, что есть, пока не будет вызвана процедура add
.Интересно, что если add
никогда не вызывается, вы просто стоите себе указатель.
Предположим, что программа вызывает add(8)
.ОК, давай покатимся.Окружающая среда AAA сделана текущей.Среда ->[w,17]->[v,69]->[u,42]->End
.
Параметры процедуры add
добавляются в начало среды.Среда становится [z,8]->[w,17]->[v,69]->[u,42]->End
.
Теперь тело процедуры add
выполняется.Свободная переменная v
будет иметь значение 69 .Свободная переменная u
будет иметь значение 42 .z
будет иметь значение 8 .
u := v + u + z
u
будет присвоено значение 69 + 42 + 8 , становящееся 119 .
Среда будет отражать это: [z,8]->[w,17]->[v,69]->[u,119]->End
.
Предположим, что процедура add
выполнила свою задачу.Теперь среда восстанавливается до прежнего значения.
env = [add,[closure,(lambda(z)(setq u (+ v u z)),*AAA*]]->[w,17]->[v,69]->[u,119]->End.
Обратите внимание, что процедура add
имела побочный эффект изменения значения свободной переменной u
.Потрясающе!
Что касается динамического определения объема: оно просто гарантирует, что закрытие пропускает динамические символы, тем самым избегая захвата и превращения в динамический.
Затем поместите присвоение в динамическое начало кода.Если динамическое значение совпадает с именем параметра, оно маскируется значением, переданным в параметре.
Предположим, у меня была динамическая переменная с именем z
.Когда я звонил add(8)
, z
был бы установлен на 8 независимо от того, что я хотел.Вероятно, поэтому динамические переменные имеют более длинные имена.
Ходят слухи, что динамические переменные полезны для таких вещей, как возврат, с использованием конструкций let Lisp.