
24.2. Абстракция данных при помощи экзистенциальных типов 289
inc = λi :{ x: Nat }. {x = succ ( i . x )}}}
as { Counter ,
{ new : Counter , get : Counter -> Nat , inc : Counter - > Counter }};
coun t e r A D T : { Counter ,
{ new : Counter , get : Counter - >Nat , inc : Counter -> Count er }}
будучи совершенно уверенными, что вся программа останется правильно типизированной, поскольку
мы наверняка знаем, что оставшаяся часть программы никак не может обратиться к экземплярам
Counter иначе как через get и inc.
Опыт показывает, что стиль программирования, основанный на абстрактных типах данных, может
принести громадные улучшения в надежности и легкости сопровождения больших систем. Тому есть
несколько причин. Во-первых, такой стиль ограничивает область видимости изменений в программе.
Как мы только что видели, можно заменить одну реализацию АТД другой, возможно, меняя при этом
как тип представления, так и реализацию операций, никак не влияя на остальную программу, поскольку
правила типизации для экзистенциальных пакетов обеспечивают независимость остальной программы
от внутреннего представления АТД. Во-вторых, такой стиль помогает программистам ограничивать
зависимости между частями программы, делая сигнатуры АТД как можно меньше. Наконец, и может
быть, это самое важное, этот стиль заставляет программистов думать о проектировании абстракций.
Упражнение 24.2.1 Рекомендуется, : Используя приведенный нами пример в качестве об-
разца, определите абстрактный тип стеков чисел, с операциями new, push (поместить значение на
стек), top (вернуть значение на вершине стека), pop (вернуть новый стек с удаленной вершиной) и
isempty. Используйте в качестве представления тип List, введенный в Упражнении 23.4.3. Напи-
шите простую программу, которая создает стек, записывает в него два числа, и получает верхний
элемент стека. Лучше всего выполнять это упражнение интерактивно. Запустите интерпрета-
тор fullomega и скопируйте содержимое файла test.f (где определяется конструктор типов List
и связанные с ним операции) в начало собственного файла.
Упражнение 24.2.2 Рекомендуется, : Постройте АТД изменяемых счетчиков, используя ссы-
лочные ячейки, определенные в Главе 13. Пусть операция new будет не константой, а функцией, при-
нимающей аргумент типа Unit и возвращающей счетчик, а возвращаемый тип операции inc пусть
будет не Counter, а Unit. (Интерпретатор fullomega поддерживает как экзистенциальные типы,
так и ссылки.)
24.2.2. Экзистенциальные объекты
Идиома «упаковать, а затем открыть», которую мы видели в предыдущем подразделе, типична для
программирования с использованием экзистенциальных пакетов в качестве АТД. Пакет определеяет
абстрактный тип и связанные с ним операции, а мы открываем каждый пакет немедленно после его
создания, связывая при этом типовую переменную, обозначающую абстрактный тип, и открывая аб-
страктный доступ к операциям над АТД. В этом подразделе мы увидим, как простая разновидность
объектно-ориентированной абстракции данных может быть представлена в виде другой программист-
ской идиомы, основанной на экзистенциальных типах. Эта объектная модель далее разрабатывается в
Главе 32.
Мы снова будем использовать в качестве основного примера простые счетчики, как мы делали и в
случае с экзистенциальными АТД, и в наших предыдущих опытах с объектами в Главах 18 и 19. Мы
снова выбираем чисто функциональный стиль, так что посылка сообщения inc объекту не изменяет
его внутреннее состояние, а возвращает новый счетчик с увеличенным внутренним состоянием.
Объект-счетчик состоит из двух основных компонент: числа, являющегося внутренним состоянием
счетчика, и пары методов, get и inc, используемых для работы с этим состоянием. Нам также нужно
добиться того, чтобы единственным способом обращения к состоянию или его изменения был вызов
одного из этих двух методов. Этого можно добиться, если завернуть состояние и методы в экзистенци-
альный пакет и абстрагироваться от типа состояния. Например, объект-счетчик, имеющий значение 5,
можно записать как
rev. 104