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

4.7.Списки

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

Неограниченные списки содержат элементы некоторого про­извольного типа. Для них имеются операции создания пустого списка, формирования нового списка, состоящего из данного элемента и элементов уже существующего списка, и декомпози­ции списка на первый элемент и остальные элементы. Специфи­кация представлена на рис. 4.12.Заметим, что списки —неиз­меняемые; такие операции, какcons, не модифицируют свои ар­гументы, а возвращают новый список.list =datatype[t:type]iscreate,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) и одинаково расположенные элементы.endlistРис. 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:listit]]

Тип данных пара (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) %Инвариант представления есть%truecreate = proc ( ) returns(cvt)return(rep$make.none(nil))endcreate

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 требует, чтобы

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

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).Разделение допустимо, так как списки неизменяемые.

а Окружение

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

б Окружение

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

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

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

first(х) -first(у)

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

rest(х) ==rest(у)

Соседние файлы в папке Б. Лисков