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

4.9.5. Операции egual, similar и copy

Может показаться, что абстракции данных должны предо­ставлять операции copy и equal автоматически, т. е. что каждый тип автоматически должен быть обеспечен этими операциями и что их реализации должны быть сгенерированы компилятором. Однако автоматически такие реализации сгенерированы быть не могут, так как они зависят от интерпретации представления, т. е. от функции абстракции.

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

{num: I, denom: 21

равно рациональному числу, представленному записью {пит: 13, denom: 26}.

Копирование не может быть реализовано автоматически по­тому, что не всегда ясно, из чего состоит объект. Например,

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

при копировании упорядоченного списка нужно ли нам копи­ровать только верхний узел, чтобы копия разделяла правое и левое поддеревья с оригиналом, или мы должны копировать также и правое и левое поддеревья? Правильный ответ зависит от значения типа.

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

Мы используем имя similar для операции, которая имеет дело со взаимосвязью ос и Р, а именно с фактом совпадения значений двух объектов. Мы требуем, чтобы результат операции copy совпадал по значению со своим аргументом, но не разделял с этим аргументом никаких компонентов. Так, объект z мог быть получен при вызове copy (х).

В отношении имен equal, copy и similar встроенные в язык CLU типы отвечают этим соглашениям. Должны отвечать им и определяемые пользователями типы. Таким образом, если тип данных intset предоставляет эти операции, их спецификации должны быть такими, как показано на рис. 4.19, а их реализации— как на рис. 4.20. Отметим, что операция similar сравнивает зна­чения двух своих аргументов и проверяет, содержат ли они одни и те же элементы. Операции equal и copy могут быть реализованы в терминах операций equal и copy для массивов.

Рис, 4,18. Две концепции равенства.

102 Глава 4

equal = proc (si, s2: intset) returns (bool) effects Возвращает значение true, если si и s2— один и тот же объект intset.

similar =^ргос (si, s2: intset) retunis (bool)

effects Возвращает значение true, если si и s2 содержат одинаковые эле­менты.

сору = ргос (s: intset) returns (intset) effects Возвращает новый объект intset, содержащий те же элементы, что и s

Рис. 4.19. Спецификации операций equal, copy и similar для наборов целых чисел intset.

equal = proc (si, s2: cvt) returns (bool) return (si = s2) % используется rep$equal end equal

similar = proc (si, s2: Intset) returns (bool) return (subset (si, s2) cand subset (s2, si)) end similar

% subset — это внутренняя программа, которая возвращает значение true, если % si принадлежит s2. subset = proc (si, s2: cvt) returns (bool) i; int := rep$low (si) while i (== rep$high (si) do

if— member (up (s2), si ti]) then return (false) end i := i+ I end end subset

copy = proc (s: cvt) returns (cvt) return (rep$copy (s)) end copy

Рис. 4.20. Реализации операций equal, similar ii copy для наборов целых чисел intset.

4.10. Заключение

В этой главе обсуждались абстракции данных: что они такое, как специфицировачь их свойства и как реализовать их; второе и третье в-основном на языке CLU. Подробно рассмотрены четыре примера. Наборы целых чисел и упорядоченные списки — изме­няемые, а списки и полиномы — неизменяемые. Реализации спи­сков,и упорядоченных списков иллюстрируют использование пара­метров типов и рекурсивных структур данных.

Кроме того, мы обсуждали некоторые важные аспекты реали­заций типов данных. В общем случае не все объекты типа пред­ставления являются законными представлениями абстрактных объектов; инвариант представления определяет законные пред­ставления. Функция абстракции определяет значение представле-ння, устанавливая отображение законных объектов представления в абстрактные объекты. Инвариант представления и функция абстракции должны быть включены как комментарии в реализа­цию. Они полезны при. начале реализации, так как Вынуждают того) кто осуществляет реализацию, ясно выразить ва'е предполо-

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

жения. Они также полезны для того, кто разбирается в реали­зации позже, так как объясняют то, что необходимо знать о пред­ставлении.

И наконец, мы рассмотрели некоторые аспекты, которые необ­ходимо иметь в виду при конструировании типов данных. Необ­ходимо тщательно обдумать, должен ли тип быть изменяемым или нет, а также то, какие операции он должен иметь, чтобы они обеспечивали потребности пользователя. Мы также обсуждали индукцию типа данных и как она используется для доказатель­ства свойств объектов, а также обсуждали необходимость обеспе­чить для типа операции equal и copy.

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

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

Дополнительная литература

Morris, James Н., Jr., 1973. Types are not sets. In Conference Record of ACM Symposium on Principles of Programming Languages, pp. 120—124.

Hoare, С. A. R., 1972. Proof of correctness of data representations. Acta In-formatica 1 (1): 271—281. Reprinted in Programming Methodology. A Collection of Articles by Members of IFIP WG2.3, edited by David Cries (New Yorkt Springer-Verlag), 1978.

Упражнения 4.1. Реализуйте процедуру

(jiff = proc (p-poly) returns (poly) effects Возвращает полином, являющийся результатом

104 Глава 4

дифференцирования р, например: diff (x»+7х+6) = Зх»+7

(см. спецификацию для полиномов на рис. 4.3). 4.2. Специфицируйте и реализуйте процедуру

reverse == ргос (1: list) returns (list),

которая реверсирует порядок элементов в списке (списки определяются на рис. 4.12).

4.3. Предположим, что наборы целых чисел intset были реализованы с ис­пользованием массивов целых чисел, как это показано на рис. 4.5, но элементы массивов представления хранятся в возрастающем порядке. Создайте инвариант представления и функцию абстракции для этой реализации.

4.4. Предположим, что полиномы (рис. 4.3) были реализованы так, что нулевой полином представляется массивом [0: 0]. Создайте инвариант представ­ления и функцию абстракции для этой реализации.

4.5. Реализуйте наборы целых чисел (рис. 4.2), используя упорядоченные списки (рис. 4.16). Не забудьте включить инвариант представления и функцию абстракции.

4.6. Предположим, известно, что полиномы (рис. 4.3) обычно содержат много нулевых членов между старшим и младшим. Создайте эффективную для такой ситуации реализацию. (Подсказка; могут быть полезны списки.) Не за­будьте включить инвариант представления и функцию абстракции.

4.7. Полиномы (рис. 4.3) должны иметь операции parse (синтаксический ана­лиз) и unparse, похожие на подобные операции для целых и действительных чи­сел. Придумайте внешнюю форму полиномов, специфицируйте эти операции и затем реализуйте их как часть реализации, представленной на рис. 4.7, или реа­лизации упражнения 6.

4.8. Специфицируйте и реализуйте операции edual, similar и copy для упо­рядоченных списков (рис. 4.16).

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

create = ргос (n: int) returns (queue) enq = ргос (q: queue, elem: t) deq == ргос (q; queue) returns (t)

Операция create создает новую очередь с максимальным размером n, опера­ция enq добавляет элемент к очереди и операция deq удаляет первый элемент очереди. Элементы очереди имеют некоторый произвольный тип t. Создайте спе­цификацию очереди, включив туда дополнительные операции, необходимые для полноты. Реализуйте вашу спецификацию. Задайте инвариант представления и функцию абстракции.

4.10. Специфицируйте и реализуйте тип для рациональных чисел. Не за­будьте включить операции equal, similar и copy. Задайте инвариант представле­ния и функцию абстракции.

4.11. Задайте такой неформальный аргумент, чтобы реализация полиномов (рис. 4.7) сохраняла инвариант представления.

4.12. Задайте такой неформальный аргумент, чтобы реализация упорядо­ченных списков (рис. 4.17) сохраняла инвариант представления.

4.13. Абстрактный инвариант списков (рис. 4.12) таков, что размер списка всегда неотрицательный. Задайте неформальный аргумент, который 'устанавли­вает этот инвариант.

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

4.14. Предположим, что мы хотим вычислить значение полинома в данной точке:

eval == ргос (р: poly, х: int) returns (int) effects Возвращает значение р в точке х, напр., poly$eval (х»+Зх, 2) = 10

Подумайте, должна ли для полиномов иметься операция equal? 4.15. Разделите операции списков (рис. 4.12) на четыре категории, описан­ные в разд. 4.9.2. Полный ли этот тип? Подсказка: рассмотрите процедуру, реа­лизующую соединение двух списков, как, например, concat((l 2), (34))== = (1 2 3 4).)

4.16. Разделите на четыре категории операции упорядоченных списков (рис. 4.16). Полный ли этот тип?

4.17. Студент предложил тип matrix с операциями для сложения, умноже­ния и инверсирования матриц. Эти матрицы изменяемые; например, операция invert модифицирует свой аргумент, и при возврате из операции в нем содержится инверсированная матрица. Второй студент требует, чтобы абстракция матриц не была изменяемой. Обсудите это.

4.18. Студент утверждает, что если программы вне реализации типа не могут модифицировать представление, абстракция данных дает нам все, что она только может дать. Обсудите это.

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