- •1.Введение
- •1.1.Декомпозиция и абстракция
- •1.2.Абстракция
- •1.2.1.Абстракция через параметризацию
- •1.2.2.Абстракция через спецификацию
- •1.2.3.Виды абстракций
- •3.Процедурная абстракция
- •3.2.Спецификации
- •3.3.Спецификации процедурных абстракций
- •3.4.Реализация процедур
- •3.5.Более обобщенные процедуры
- •3.6.Создание процедурных абстракций
- •3.7.Заключение
- •4.Абстракции данных
- •4.1.Спецификации для абстракций данных
- •4.2.1.Реализация на языке clu
- •4.2.2.Замечания по поводу операций up и down
- •4.3.Использование абстракций данных
- •4.4.Реализация полиномов
- •4.5.Пояснения для понимания реализаций
- •4.5.1.Функция абстракции
- •4.5.2.Инвариант представления
- •4.6.3.Сохранение инварианта представления
- •4.5.4.Изменяемые представления
- •4.6.Параметризованные абстракции данных
- •4.7.Списки
- •4.8.Упорядоченные списки
4.6.3.Сохранение инварианта представления
Для того чтобы продемонстрировать корректность реализации типа, мы должны, в частности, показать, что инвариант представления сохраняется для всех законных объектов представления. Мы можем сделать это следующим образом. Прежде всего мы покажем, что инвариант сохраняется для объектов, возвращаемых операциями (как, например, операцией poly$create), которые возвращают объект типа, но не имеют аргументов типа. Для всех других операций мы можем предположить, что при их вызове инвариант сохраняется для всех аргументов, являющихся объектами типа; тогда мы должны показать, что он сохраняется при возврате как для аргументов типа, так и для возвращаемых объектов типа.
Например, реализация набора intset(рис. 4.5)имеет инвариант
%Для всех целых i, j,таких, что low (r) i < j bigh (r) % r [i]~=r lj]
Операция intset$createотвечает этому инварианту потому, что заново созданный массив пуст. Операция memberтакже сохраняет этот инвариант, так как мы знаем, что инвариант сохраняется для аргумента sи что эта операция не модифицирует s. Операция insertтакже сохраняет инвариант, так как
1)инвариант сохраняется для ее аргумента sпри обращении;
2)при вызове операции memberиз операции insertинвариант сохраняется потому, что он сохраняется в операции member;и
3)операция insertдобавляет х к s,только если выражение^member (s,х) имеет значение true;следовательно, так как набор sудовлетворяет инварианту при вызове, он также удовлетворяет инварианту после добавления к нему х.
В качестве второго примера рассмотрим реализацию полиномов poly,представленную на рис. 4.7.Вспомним, что инвариант есть
% low (r) Ss О
% & if empty (s) then high (r) == 0 % else г How (r) ] ~ = 0 & г [high (г) I ~ == 0
Операция poly$createсохраняет инвариант потому, что она создает нулевой полином. Операция millсохраняет инвариант потому, что
1)при вызове инвариант сохраняется для р и q;
2)случай, когда р или q —нулевой полином, распознается и создается соответствующее представление; и
3)в противном случае ни р, ни qне содержат нулей ни в старшем, ни в младшем члене; следовательно, ни младший элемент возвращаемого массива (bottom(р)* bottom (q)),ни старший элемент (top(р)* top (q))не может быть нулем.
Здесь мы предполагаем, что абстрактные объекты нельзя модифицировать вне их реализации. Если это возможно, то мы не можем предполагать, что инвариант сохраняется при вызове операции, так как какие-то модули могут его изменить.
4.5.4.Изменяемые представления
Изменяемость (или неизменяемость) —это свойство абстракции, которое должно сохраняться реализацией. Изменяемые абстракции должны иметь изменяемые представления, иначе будет невозможно обеспечить требуемую изменяемость. Однако неизменяемые абстракции не обязательно должны иметь неизменяемые представления. Например, полиномы неизменяемы, но имеют изменяемое представление. Изменяемые представления приемлемы, если модификации, сделанные в представлении, не могут быть замечены пользователями абстракций.
Иногда полезно создавать объект, изменяя его представление, однако, когда объект создан, его представление больше не модифицируется. Так, например, созданы полиномы. Изменяемость также полезна дляблагоприятных побочных эффектов,являющихся модификациями, которые не видны вне реализации. Например, давайте представим рациональное число парой целых:
гер =• record lnum, denom: int]
Функция абстракции есть
%типичное рациональное число есть n/d %Функция абстракции есть%А (г) = r.num/r.denom
Исходя из этого представления, мы должны принять несколько решений: что делать с нулевым знаменателем, как хранить отрицательные рациональные числа и хранить ли рациональные числа в сокращенной форме (т. е. когда числитель и знаменатель не имеют общего делителя). Мы решаем: исключить нулевой знаменатель, представлять отрицательные рациональные числа с помощью отрицательного числителя инехранить представления в сокращенной форме (для ускорения таких операций, как умножение). Таким образом, имеем
%Инвариант представления есть% r.denom >О
Давайте также решим находить сокращенную форму при проверке двух рациональных чисел на равенство. Это мы можем сделать, используя процедуру gcd.
gcd = proc (n, d: int) returns (int) requires nи dдолжны быть положительнымиeffectsВозвращает макс. общий делитель nи d.
Реализация операции equalпредставлена на рис. 4.9.Однажды найденные, сокращенные формы записываются в представление, так как это ускоряет работу при последующих обращениях к операции equal.
rep == record [nurn, denom: int] equal == proc (rl, r2: cvt) returns (bool) if rl.nurn =: 0 then return (r2.niim = 0) elseif r2.niim == 0 then return (false) end reduce (rl) reduce (r2)
return (rl.num == r2.num cand rl.denom = r2.denom) end equal
% reduce —внутренняя программа, приводящая ее аргумент к сокращенной
%формеreduce proc (r: rep) g: int :== gcd (in1$abs (r.num), r.denom) r.num :== r.num/g r.denom := r.denom/g etid reduce Рис, 4.9.Благоприятный побочный эффект.
Модификация представления, осуществляемая операцией equal, —благоприятный побочный эффект. Такие побочные эффекты часто используются для улучшения эффективности. Они возможны, если функция абстракции отображает различные элементы в один, так как тогда имеется много объектов представления, которые представляют один и тот же абстрактный объект. Иногда полезно внутри реализации переходить от одного такого объекта представления к другому. Такой переход законен, так как новое представление соответствует тому же самому абстрактному объекту.