Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
48
Добавлен:
23.03.2015
Размер:
396 Кб
Скачать
☆

4.5.2. Инвариант представления

В ориентированных на работу с типами языках (как, например, в языке CLLJ) контроль типов гарантирует, что если абстрактный объект типа передается как аргумент операции типа, то этот аб­страктный объект представляется объектом типа представления. Во многих случаях, однако, не все объекты представления яв­ляются законными представлениями абстрактных объектов. На­пример, для кластера intset (рис. 4.5) каждый массив независимо от значений является элементом Я', например, массивы [1: 1, 7,6], [1: 1, 6, 6] и [1:6, 1,7]. Однако в реализации intset мы ре­шили, что каждый элемент набора записывается в массив только один раз. Следовательно, законные представления наборов int­set в этом кластере не содержат дублирующих друг друга элемен­тов; [1: 1, 6, 6], например — незаконное представление.

Условие, которому удовлетворяют все законные объекты, называется инвариантом представления. Инвариант представле­ния 1 есть предикат

1: rep

bool.

Абстракции данных

i < j ^ high (r)

который принимает значение true для законных объектов пред­ставления. Например, для кластера intset мы можем дать следую­щий инвариант представления:

% Инвариант представления есть % Для всех целых i, j, таких, что low (r): о/о r [i]~=r [j]

Заметим, что для массива II: 1, 6, 6] 1 принимает значение false, а для массивов [1: 1, 7, 6] и [1: 6, 1, 7] —значение true. Заметим также, что мы не включаем в 1 условия, которые прини­мают значение true для всех массивов (например, size (r) == = high (r) — low (r) + 1), потому что это гарантируется про­цедурами работы с массивами и соответственно предполагается в реализации intset.

В качестве второго примера инварианта представления рас­смотрим альтернативное представление наборов intset, состоя­щее из булева массива размерности 100 и массива целых:

гер = record leis: array [bool], other.els: array tint], size: int]

Идея заключается в том, что для целых от 1 до 100 мы отме­чаем их принадлежность набору, записывая значение true в r.els ti 1. Не принадлежащие этому диапазону целые записываются в other.els точно так же, как в нашей предыдущей реализации intset. Так как невыгодно вычислять размер набора intset, про­сматривая все элементы массива els, мы записываем этот размер в представление в явном виде. Это представление хорошо, если почти все члены набора принадлежат диапазону 1—100. (В про­тивном случае пространство, требующееся для массива els, будет использоваться неэффективно.) Таким образом, мы имеем

% Функция абстракции есть о/о А (r) = {i-.other-els [i ] I low (r. other- els) ^ i s$ high (r.other, els)}

% U % {j U^js5 100 & r'els [j])

Здесь U обозначает математическое объединение двух набо­ров. Итак,

% Инвариант представления есть % size (r.els) = 100 & low (r.els) = I % & все элементы r.other не принадлежат диапазону I—100 % & в r.other нет дубликатов элементов % & r.size = size (r.other, els) -(-% (число элем. со знач. true в r.els)

Заметим, что поле size в этом представлении излишне: оно со­держит информацию, которая может быть получена из остальной части представления путем вычислений. Но, поскольку такая из­лишняя информация все же содержится в представлении, взаимо­связь этой информации с остальной частью представления должна быть объяснена в инварианте представления (например, послед­няя строка нашего инварианта представления).

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

% r.size= size (r.othei_els)+ cnt (r.els, low (т.els)) % где cnt (a, i) = if i »> high (a) then 0 % else if r [i] then I+cnt (a, i+1) % else cnt (a, i + 1)

Вспомогательная функция cnt определена здесь рекурсивно. Интересный инвариант представления имеет реализация поли­номов poly, представленная на рис. 4.7. Вспомним, что мы ре­шили не записывать нулевые коэффициенты справа и слева от значащих членов полинома и представлять нулевой полином пу­стым массивом. Следовательно, мы предполагаем, что старший и младший элементы массива — не нули. Кроме того, эти массивы всегда имеют неотрицательную нижнюю границу. И наконец, пустой массив (представляющий пустой полином) должен иметь верхнюю границу, равную нулю. Таким образом, мы имеем

% Инвариант представления есть % low (r) ^.0

% & if empty (т) then high (r) = 0 % else r (low (r) ]~=0 &r [high (r)] ~=0

Вспомним, что реализация операции degree предполагает, что верхняя граница массива равна степени полинома. Теперь мы видим это требование в инварианте представления.

Иногда все объекты представления законны. Тогда мы просто имеем

% Инвариант представления есть % true

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

Инвариант представления — это «инвариант» потому, что он всегда сохраняется для представлений абстрактных объектов, т. е. он сохраняется, если объект используется вне его реализа­ции. Инвариант представления не должен, однако, обязательно сохраняться всегда: он может быть нарушен при выполнении од­ной из операций типа. Например, операция poly$add может по­лучить массив с нулевым старшим и младшим элементом, но такие элементы удаляются из массива перед возвратом из операции add. Инвариант представления должен сохраняться при возврате из операций.

Между функцией абстракции и инвариантом представления имеется определенная взаимосвязь. Функция абстракции имеет смысл только для законных представлений, так как только они представляют абстрактные объекты. Следовательно, нет необ­ходимости определять ее для незаконных представлений. Например, как мы упоминали раньше, функция абстракции для поли­номов имеет некую область определения — она определена только в случае, если массив имеет неотрицательную нижнюю границу. Этому требованию удовлетворяют все законные представления полиномов, что отражено в инварианте представления.

Существует соглашение о том, что должно быть отражено в инварианте представления. Инвариант представления должен отражать все требования, от которых зависят операции, но может не отражать дополнительные требования. Например, все кон­кретные объекты для реализации, представленной на рис. 4.5, имеют нижнюю границу, равную, 1, но от этого не зависит реали­зация никаких операций, поэтому нет необходимости отражать это в инварианте представления. Хорошо представлять себе, что операции реализуют различные люди, которые не общаются друг с другом. Тогда понятно, что инвариант представления дол­жен содержать все требования, которые необходимо знать этим различным людям.

При реализации абстракции данных инвариант представле­ния — одна из первых вещей, о которых должен подумать про­граммист. Он должен быть выбран до реализации операций, в противном случае различные реализации не будут согласованы друг с другом. Чтобы гарантировать согласованность, инвариант представления должен быть написан и включен в программу как комментарий. Написание инварианта представления вынуждает того, кто занимается реализацией, ясно выразить то, что он хочет, и увеличивает тем самым вероятность того, что операции будут реализованы корректно.

Все операции должны реализовываться с учетом инварианта представления. Например, предположим, что мы реализуем опе­рацию insert так:

insert == proc (s: cvt, x: inl) rep$addh (s, x) end insert

Эта реализация может создать объект с дублирующимися элементами. Если мы знаем, что инвариант представления за­прещает такие объекты, то эта реализация очевидно некорректна. Инвариант представления также полезен для того, кто изу­чает реализацию. Например, в альтернативной реализации набора intset мы можем решить подвергать массив представления сортировке. В этом случае мы будем иметь

% Инвариант представления есть % Для всех i, j, таких, что low (г) sg; i < j ^ high (r) % r [i] <r [j]

Все операции тогда будут реализовываться иначе, чем на рис. 4.5. Инвариант представления говорит тому, кто изучает реализацию, почему операции реализованы именно так, как они реализованы.

Соседние файлы в папке POSIBNIK