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

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

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

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

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

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

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[целочисленная] и sort[строковая]. Аналогично мы получим search[целочислен­ная] и search[действительная]. Подобные имена мы уже исполь­зовали во встроенных классах абстракций языка CLU —напри­мер, array[целочисленный].

Класс содержит элемент для каждого типа, который удовлет­воряет ограничениям, заданным в предложении requires.Напри­мер, sort [int]находится в классе sort, a sort [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тем,

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 + I else return (at$high (a) + 1) end end %конец цикла while return (i) end search

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

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

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

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

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

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