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

Функция инвариант представления

В ориентированных на работу с типами языках (как, например, в языке CLU) контроль типов гарантирует, что если абстрактный объект типа передается как аргумент операции типа, то этот аб­страктный объект представляется объектом типа представления. Во многих случаях, однако, не все объекты представления яв­ляются законными представлениями абстрактных объектов. На­пример, для кластера intset имеем массивы

[1: 1, 7,6], [1: 1, 6, 6] и [1:6, 1,7]. Однако в реализации intset мы ре­шили, что каждый элемент набора записывается в массив только один раз.

Следовательно, законные представления наборов int­set в этом кластере не содержат дублирующих друг друга элемен­тов; [1: 1, 6, 6], например — незаконное представление.

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

Функция ИНВАРИАНТ ПРЕДСТАВЛЕНИЯ есть

( Для всех целых i и j таких, что

low (r)<= i < j <= high (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 [int], size: int

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

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

Инвариант представления есть 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 определена здесь рекурсивно.

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

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

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

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

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

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

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

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

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

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

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