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

Более обобщенные процедуры

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

Польза от применения типов в качестве параметров очевидна. Это следует из того факта, что многие встроенные типы данных, например массивы, записи и процедуры, параметризованы через типы.

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

Некоторые спецификации для параметризованных процедур показаны на рис. 3.7.Отметим, что эти спецификации отличаются от непараметризованных процедур только заголовком, который со­держит дополнительную часть, содержащую параметры. Пред­ложениеrequiresпомимо прочих ограничений содержит ограничения, накладываемые на параметры. Если ограничения отсут­ствуют, то предложениеrequiresможет быть опущено. Например, абстракцияsortтребует, чтобы параметрtимел операциюIt, упорядочивающую t.Аналогично процедураsearchтребует, чтобы ее параметр поддерживал как операцию, так и операциюequal. (Ltесть имя, используемое для операций, для которых допускается сокращенная форма <,aequalесть имя операции с сокращенной формой =.)

sort = pi-ос [t: type] (a: array [t])-returns (array [t])

requires t имеет операцию

It: proctype (t, t) returns (bool) которая упорядочивает t.

modifies a

effectsВозвращает новый массив с теми же границами, что и а, и со­держащий элементы а, расположенные в возрастающем порядке; по­рядок устанавливается черезt$lt.

search = proc [t: type] (a: array [t], x: t) retunis (int)

requires t имеет операции

equal, It: proctype (t, t) returns (bool)

такой, что tупорядочивается черезIt, и массив а упорядочен по воз­растанию черезIt.

effectsЕсли х принадлежит а, то возвращаетсяiтакое, чтоa[i] = x; в противном случае возвращаетсяhigh(а) + 1

Рис. 3.7.Спецификации параметризованных процедур.

Параметризованная абстракция в действительности представ­ляет собой класс взаимосвязанных абстракций, определенных в одной спецификации. Например, параметризованная абстрак­цияsortпредставляет собой не одну параметризованную про­цедуру, а целый класс процедур, одна из которых принимает в качестве параметра массив целых чисел, другая —строковый массив и т. д. Мы будем поименовывать такие процедуры сочета­нием имени класса с именем типа, напримерsort[int] иsort[string]. Аналогично мы получимsearch[int] иsearch[real]. Подобные имена мы уже исполь­зовали во встроенных классах абстракций языкаCLU —напри­мер,array[int].

Класс содержит элемент для каждого типа, который удовлет­воряет ограничениям, заданным в предложенииrequires. Напри­мер,sort [int]находится в классеsort,asort [bool] —нет (по­скольку в языке CLUк булевым переменным неприменима опе­рацияIt). Спецификация процедуры естественным образом полу­чается из спецификации класса путем замены имени параметра его значением и удалением "из предложенияrequiresограничений на тип параметра(ов) (поскольку эти условия, задаваемые этими ограничениями, были удовлетворены). Следовательно, специфика­ция дляsearch [int]совпадает со спецификацией дляsearchна рис. 3.3.

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

sort = proc [t: type ] (a: array [t ]) returns (array [t ])

Обычно операции, перечисленные в предложении requires. спецификации, используются и в реализации. Например, для реа­лизации процедурыsortмы используем операциюIt. Для про­верки типа в таких операциях компилятор должен знать их имена, а также число и типы их аргументов и результатов. Мы даем такую информацию в предложенииwhere, которое помещается сразу же за заголовком. Например,

sort = proc [t: type] (a: array [t] returns (array [int])

where t has It: proctype (t, t) returns (bool)

Единственные операции параметра типа, которые могут быть использованы в параметризованном модуле, перечислены в пред­ложении where.

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

Текст параметризованной процедуры аналогичен непараметри­зованной процедуре. Например, приведенная на рис. 3.8реализа­ция процедурыsearchотличается от реализации на рис. 3.4тем, что элементы массива, принадлежащие ранее к целочисленному типу, имеют теперь тип t —параметр типа. Процедураsearchсравнивает элементы массива при помощи t$ltи t$equal.Эти обращения даются с использованием сокращенных форм.

Для использования параметризованной процедуры мы должны сначала указать значения для параметров, напримерsearch[int]. Следовательно,search [int](а) является разрешенным обраще­нием, если а естьarray [int],ноsearch(а) таковым не является, поскольку дляtне было указано никакого значения.

search == proc [t: type] (a: array [t], x: t) returns (int)

where t has It, equal: proctype (t, t) returns (bool)

%реализация с использованием метода линейного поиска

at = array [t ]

i: int := atjjjlow (a)

while i <= at$high (a) do

if a [i ] = x then return (i) end % использование T$equal

if a [i] <x % использование t$lt

then i := i + 1 else return (at$high (a) + 1) end

end % конец цикла while

return (i)

end search

Рис. 3.8.Параметризованная абстракцияsearch.

При задании параметра для типа компилятор проверяет, при­менимы ли к данному типу операции, указанные в предложенииwhere. Например, обращениеsearch[array [int]]не допускается, посколькуarray [int]не имеет операцииit. Такая проверка га­рантирует, что использованные в параметризованном модуле операции будут снабжены фактическими параметрами и что зна­чения и типы аргументов и результатов соответствуют ожидае­мым.

Параметризованная процедура должна содержать список опе­раций в предложенииwhere, даже если она использует эти опе­рации неявным образом, обращаясь к другой параметризованной процедуре, использующей данные операции. Предположим, на­пример, что мы создали параметризованные версии процедур для задачи сортировки слиянием, показанной на рис. 3.5,ОперациюItиспользует только процедураmerge. Однако процедурыmergeиsortдолжны содержатьItв предложенияхwhereс тем, чтобы компилятор мог удостовериться, что сделанное вmerge.sortобращениеmerge [t]является допустимым.

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