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

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

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

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

I:rep→bool

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

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

%Для всех целых i, j,таких, чтоlow (r) <=i<j<=high[j]

% 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 [els: array [bool], other.els: array tint], size: int]

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

%Функция абстракции есть

% А (r) = {r_other_els [i ] | low (r. other_ els) <= i <= high (r_other_els)}

% U

% {j | 1<= j <= 100 & r.els [j])

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

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

% size (r.els) = 100 & low (r.els) = 1

% & все элементы r.other не принадлежат диапазону 1-100

% & в r.other нет дубликатов элементов

% & r.size = size (r.other, els) +

% (число элем. со знач. true в r.els)

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

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

% r.size= size (r.other_els)+ cnt (r.els, low (r.els))

% где cnt (a, i) = if i »> high (a) then 0

% else if r [i] then 1+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(г) <=i <j<=high(r)

%r[i] <r[j]

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

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