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

4.7.Списки

Наш следующий пример —'другой параметризованный тип, в котором требования налагаются на индивидуальные операции) а не на тип как целое. Кроме того, мы продемонстрируем рекур­сивную реализацию. -

Неограниченные списки содержат элементы некоторого про­извольного типа. Для них имеются операции создания пустого списка, формирования нового списка, состоящего из данного элемента и элементов уже существующего списка, и декомпози­ции списка на первый элемент и остальные элементы. Специфи­кация представлена на рис. 4.12.Заметим, что списки —неиз­меняемые; такие операции, как cons,не модифицируют свои ар­гументы, а возвращают новый список.list = data type [t: type] is create, cons, first, rest, empty, equal Описание

Списки —это неизменяемые неограниченные последовательности элементов типа t.

Операции create = proc () returns (list [t])

effectsВозвращает пустой список.cons == proc (i: t, x: list [t]) returns (list [t]) effectsВозвращает список, у которого первый элемент i,а остальные

элементы —элементы x. first = proc (x: list [t]) returns (t) requires xне пустeffectsВозвращает первый элемент x. rest == proc (x: list [t]) returns (list [t]) requires x —не пуст.

effectsВозвращает список, содержащий все элементы x,кроме первого.empty = proc (x: list [t]) returns (bool)

effectsВозвращает значение true,если x —пуст, и значение false —в про-тивном случае.

equal = proc (x,у; list [t]) requires tимеет операциюequal: proctype (t, t) returns (bool), т. e.условие равенства t. effectsВозвращает значение true,если xи у содержат одинаковые (в соотв.

с t$equal)и одинаково расположенные элементы.end list Рис. 4.12.Спецификация абстракции данных для списков.

Заметим, что списки как целое не налагают никаких требова­ний на тип параметра. Таким образом, list [intset]—законный тип. Однако операция equalдолжна проверять элементы на ра­венство, поэтому она в предложении requiresналагает на tтребо­вания. Следовательно, list [intset 1имеет все операции списков, кроме операции equal,так как intsetне имеет операции equal. Поскольку ограничивающие требования предъявлены только к операции equal,возможно создавать списки элементов любого типа (даже intset),но без операции equal.Определять списки та­ким образом можно потому, что они, как массивы, представляют собой очень общий группирующий механизм (массивы также имеют требования на частные операции вместо общих требований).

Удобный способ для реализации списков —это связанные пары, где первый элемент пары содержит элемент списка, а второй — ссылку либо на другую пару, либо на специальное значение, ука­зывающее, что больше пар нет. Пример дан на рис. 4.13,а, где мы предполагаем, что t —целое число. Заметим, что если второй элемент пары указывает на другую пару, мы можем рассматри­вать эту вторую пару как начало списка, содержащего все эле­менты первоначального списка, кроме первого. Фактически, даже когда второй элемент не указывает на другую пару, мы тем не менее можем рассматривать его как указывающий на список — на пустой список. Такой подход иллюстрируется на рис. 4.13,б. В любом случае второй элемент пары указывает на другой список, и представление списков, таким образом, является рекурсивным.

На языке CLUпару можно представить следующим образом)pair = struct [elem: t, rest: list it]]

Тип данных пара (pair)подходит для представления списков, имеющих по крайней мере один элемент, но не подходит для пред­ставления пустых списков. Пустой список должен рассматри­ваться как особый случай: список либо имеет какие-то элементы и тогда представляется парой, либо список пуст. Для того чтобы

Рис, 4.13.Связанные пары: а—связанные пары, представляющие список(3 7 4);бпредставление связанных пар, рассматриваемое рекурсивно, выразить концепцию списка, который либо имеет элементы, либо не имеет, нам необходим тип данных, который отражает это «либо-либо». Понятие oneofязыка CLUпредоставляет необхо­димое средство, и мы имеем

rep == oneof (some: pair, none: null] Пустой список представляется, как имеющий тип null.

list = cluster [t: type] is create, cons, first, rest, empty, equal rep = oneof [some: pair, none: null ] pair == struct [elem: t, rest: list [t]]

%Типичный список—это последовательность [sl,...,sn] %Функция абстракции есть

%А (г) === [ ]если тег г есть none % A (r) = [v.elem]Ц A (v. rest)если тег rесть some, %где v = value.some (r) %Инвариант представления есть% true create = proc ( ) returns (cvt) return (rep$make .none (nil)) end create

cons== proc (i: t, x: list [t]) returns (cvt) return (repgmake.some (pair$ {elem: i, rest: x))) end cons first = proc (x: cvt) returns (t) tagcase x

tag some (p: pair): return (p: elem) tag none: %Язык CLUтребует, чтобы

"/«если нет «других» ответвлений.end end first

rest = proc (x: cvt) returns (list [t]) tagcase x ' tag some (p: pair): return (p. rest) tag none: end end rest

empty = proc (x: cvt) returns (bool) return (rep$is_iione (x)) end empty

equal == proc (x, y: list [t]) returns (bool)

where t has equal: proctype (t, t) returns (bool) if empty (x) then return (empty (y)) elseif empty (y) then return (false) elseif first (x) = first (y) % t$equal

then return (rest (x) = rest (y)) % list [tl $equal else return (false) end end equal end list

все теги были указаны, даже

Рис. 4,14.Реализация списков.

Кластер списка показан на рис. 4.14.Как обычно, мы начи­наем с определения представления: гео = oneof [some: pair, none: null ] pair == struct (elern: t, rest: list [t]]

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

Мы включили в кластер как комментарии описания функции абстракции и инварианта представления. Здесь определение функции абстракции дано в рекурсивном виде. (Вспомним, что операция value_someтипа oneof;она возвращает данные своего аргумента, если тег есть some.)

Операция createпросто создает представление списка с те-гом noneи возвращает его; эта операция автоматически (так как указано cvt)применяет к возвращаемому объекту операцию up и делает его абстрактным объектом. Операция consсоздает представление в тегом some;новая пара содержит в первом поле новый элемент, а во втором —ссылку на список, являющийся ее аргументом. Таким образом, заново созданный список разде­ляет заданный в качестве аргумента список с обратившимся к опе­рации cons(рис. 4.15).Разделение допустимо, так как списки неизменяемые.

R Окружение

Вселенная объектов

О Опругкепае

Вселенная рёъектов

Рис. 4.15.Разделение в списках:апредставление списка (3)со ссылкой на переменную 1;брезультат вычисления m: list; ==list $ sons (4, 1).

Теперь обратим внимание на предложение where,которое следует за заголовком операции equal.В нем представлена син­таксическая часть информации предложения requiresспецифи­кации. Требуемая операция используется в

first(х) - first(у)

Операция equalреализуется рекурсивно —она, используя короткую форму записи, обращается к самой себе.

rest(х) == rest(у)

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