Новосибирский Государственный Университет
Опубликован: 05.02.2007 | Доступ: свободный | Студентов: 2223 / 413 | Оценка: 4.30 / 4.23 | Длительность: 10:15:00
Лекция 10:

Свойства атомов и работа с памятью

< Лекция 9 || Лекция 10: 12 || Лекция 11 >

Деструктивные (разрушающие) операции

Идеальный Лисп универсален в смысле теории вычислимых функций от символьных выражений. Но для практичности системы программирования Лиспу требуется дополнительный инструмент, увеличивающий выразительную силу и эффективность языка.

В частности, идеальный Лисп не имеет возможности модифицировать структуру списка. Единственная базисная функция, влияющая на структуру списка - это cons, а она не изменяет существующие списки, а создает все новые и новые. Функции, описанные в чистом Лиспе, такие как subst, в действительности не модифицируют свои аргументы, но делают модифицированную копию оригинала.

Идеальный Лисп работает как расширяемая система, в которой информация как бы никогда не пропадает. Set внутри Prog лишь формально смягчает это свойство, сохраняя ассоциативный список и моделируя присваивания теми же CONS.

Теперь же Лисп обобщается с точки зрения структуры списка добавлением разрушающих средств - деструктивных базисных операций над списками rplaca и rplacd. Эти операции могут применяться для замены адреса или декремента любого узла в списке подобно стандартным присваиваниям. Они используются ради их воздействия на память и относятся к категории псевдо-функций.

(rplaca x y) заменяет адресную часть x на y. Ее значение - x, но x, отличное от того, что было раньше. На языке значений rplaca можно описать равенством

(rplaca  x y) = (cons y (cdr x))

Но действие совершенно различно: никакие cons не вызываются и новые слова не создаются.

(rplacd x y) заменяет декремент x на y.

Деструктивные операции должно применять с осторожностью! Они могут совершенно преобразить существующие определения и основную память. Их применение может породить циклические списки, возможно, влекущие бесконечную печать или выглядящие бесконечными для таких функций как equal и subst.

Такие функции используются при реализации списков свойств атома и ряда эффективных, но небезопасных, функций Clisp-а, таких как nconc, mapc и т.п.

Для примера вернемся к функции grp. Это преобразующая список функция, которая преобразует копию своего аргумента, реорганизуя подструктуру


в структуру из тех же атомов:


Выше приведенное определение функции делает это созданием новой структуры и использует для этого четыре cons. Из-за того, что в оригинале только три слова, по крайней мере один cons необходим, а grp можно переписать с помощью rplaca и rplacd.

Изменение состоит в следующем:


Пусть новое машинное слово строится как (cons (cadr x) (cddr x)). Тогда указатель на него заготавливает форма:

(rplaca (cdr x) (cons (cadr x) (cddr x)))

Другое изменение состоит из удаления указателя из второго слова на третье. Оно делается как (rplaca (cdr x) NIL).

Новое определение функции pgrp можно определить как соотношение:

(pgrp x)=(rplacd(rplaca(cdr x)(cons(cadr x)(cddr )x)))NIL)

Функция pgrp используется в сущности ради ее действия. Ее значением, неиспользуемым, является подструктура ((B C)). Поэтому необходимо, чтобы pgrp выполнялось, а ее значение игнорировалось.

Расширенный деструктивными функциями Лисп хорошо приспособлен к оптимизации программ. Любые совпадающие подвыражения можно локализовать и вынести за скобки.

"Сборка мусора" - повторное распределение памяти

Самым интересным, можно сказать революционным, механизмом работы с памятью в Лиспе бесспорно явилась "сборка мусора". С начала 60-ых годов методам такой работы посвящены многочисленные исследования, продолжающиеся до наших дней и сильно активизировавшиеся в связи с включением похожего механизма в реализацию языка Java.

Общая идея всех таких методов достаточно проста:

  • пока памяти хватает, о ней можно не беспокоиться и располагать новые данные в новых блоках памяти,
  • если памяти вдруг не оказалось, то надо выполнить "сборку мусора", при которой можно найти блоки, ставшие бесполезными для программы,
  • если память нашлась, ее снова можно беззаботно тратить.

Специальная программа "сборка мусора" выполняет анализ достижимости всех блоков памяти просто пометкой узлов, видимых из конечного числа рабочих регистров системы программирования. К таким регистрам относятся промежуточные результаты вычислений, активная часть стека, ассоциативный список, таблица атомов и др. После пометки все непомеченные узлы объединяются в список свободной памяти, передающий их для повторного использования новым вызовам функции CONS. Такая автоматизация не лишена недостатков, но они обнаруживаются лишь в сравнительно сложных процессах, требования которых мы сейчас сознательно не рассматриваем.

Таблица 10.2. Clisp. Свойства атомов. Встроенные функции.
(Gensym ) Создает новый уникальный атом
(Get Атом Индикатор) Выдает адрес свойства Атома, помеченного заданным Индикатором.
(Set Форма Данное ) Устанавливает значение переменной, одноименной с атомом, полученным при вычислении Формы.
Setf
(Setq Атом Данное ) Устанавливает значение Атома-переменной
Symbol-function
Symbol-plist
Symbol-value
Remprop
(Nconc Список … ) Сцепляет списки без копирования, т.е. заменяя последний Nil очередного списка на указатель следующего списка.
(Rplaca Пара Объект ) Заменяет левый элемент Пары на Объект.
(Rplacd Пара Объект ) Заменяет правый элемент Пары на Объект.

Выводы:

  • Списки свойств атомов обеспечивают прямой доступ к значениям и определениям, а также к произвольным свойствам, как встроенным, так и программируемым.
  • Деструктивные операции могут повысить эффективность вычислений ценой надежности программирования.
  • Автоматическое перераспределение памяти позволяет программисту не отвлекаться от решения своих задач на технические проблемы, связанные с планированием структур данных.
< Лекция 9 || Лекция 10: 12 || Лекция 11 >