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

4.2.1. Реализация на языке clu

Хотя, конечно, возможно реализовать типы на языках, ко­торые специально не приспособлены для этой цели, более удобно, если тип может быть реализован как отдельный программный модуль. Язык CLU предоставляет такую программную единицу. Эта единица называется кластер. (CLU, отметим, — это первые три буквы слова cluster.) Кластер включает в себя следующее.

1. Заголовок, в котором придаются имена реализуемому типу и операциям. Этот заголовок похож на заголовок в специфика­ции.

2. Определение представления, выбранного в данной реали­зации.

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

Общий вид кластера представлен на рис. 4.4. dnarne = cluster is % список имен операций re? = и здесь дается описание представления

% здесь помещаются реализации операций % если необходимо, здесь могут быть представлены % вспомогательные программы

end dnarne Рис. 4.4. Общий вид кластера.

Для представления наборов целых чисел с помощью массивов, например, мы указываем

гер = array tint ]

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

Внутри кластера должны быть доступны как абстрактный тип, так и тип представления. Более того, должна иметься воз­можность перехода от одного типа к другому. Например, опера­ция insert получает в качестве аргумента набор целых чисел, но для реализации insert необходимо использовать массив, который представляет этот набор.

Возможность перехода от абстрактного типа к типу представ­ления и обратно в языке CLU обеспечивают ^две специальные операции: up и down. Операция up использует в качестве аргу­мента объект представления и в качестве результата выдает абстрактный объект, а операция down осуществляет обратное действие. Для того чтобы обеспечить преобразование абстрактного типа в тип представления и обратно, каждый кластер имеет свою собственную версию операций up и down. Эти операции автоматически определяются компилятором CLU. Например, в кластере процедуры intset компилятор порождает операции up и down со следующими заголовками:

up = proc (a: array tint 1) returns (intset) down == proc (s: intset) returns (array [int])

Операции up и down могут использоваться только в кластерах и всегда осуществляют переход от абстрактного типа к типу пред­ставления и обратно только для кластера, в котором они появи­лись. Поэтому операции up и down не могут отрицательно по­влиять на контроль типов языка CLU.

Хотя операции up и down могут появиться, где угодно, среди операций кластера, они в основном используются в одном из двух случаев. В первом случае, когда операция использует в ка­честве аргумента абстрактный объект, для преобразования этого объекта в тип представления используется операция down. Во вто­ром случае, когда операция возвращает заново созданный аб­страктный объект, сразу же перед возвратом для преобразования объекта представления в абстрактный тип используется операция up. Для удобства работы язык CLU предоставляет специально зарезервированное слово cvt. Слово cvt может использоваться как тип аргумента или результата в заголовках операций кластеров. Использование его как типа аргумента указывает, что фактиче­ский аргумент — абстрактного типа, неформальный — типа пред­ставления и что поэтому к фактическому аргументу сразу же после вызова должна быть неявно применена операция down и результирующий объект представления должен быть присвоен формальному аргументу. Когда cvt используется как тип резуль­тата, это означает, что результирующий объект — абстрактного типа, но возвращаемый объект—типа представления и что по­этому прямо перед возвратом к возвращаемому объекту неявно должна быть применена операция up. Слово cvt не добавляет ни­какой функциональности, которая не была бы обеспечена опера­циями up и down. Оно обеспечивает только удобство, которое возникает из возможности довольно просто описывать общие слу­чаи.

Теперь мы можем обратиться к представленной на рис. 4.5 реализации процедуры intset.

intset == cluster is create, insert, delete, member, size, choose rep = array [int]

create = proc ( ) returns (cvt) return (rep$new ( )) end create

insert = proc (s: intset, x: int)

if — member (s, x) then rep$addh (down (s), x) end end insert

delete = proc (s: cvt, x: int) j: int :== getind (s, x) if j <= rep$high (s) then s [j] := rep$top (s) % top возвращает s [high (s)]

rep$remh (s) end end delete

member = proc (s: cvt, x: int) returns (bool) return (getind (s, x) <= rep$high (s)) end member

size ^ proc (s: cvt) returns (int^ return (rep$size (s)) end size

72 Глава 4

choose = proc (s: cvt) returns (int)

return (rep$bottom (s)) % bottom возвращает s [low (s) ] end choose

getind = proc (s: rep, x: int) returns (int) i: int : = rep$low (s) while i (== rep$high (s) do if x = s \i} then return (i) end i:=i+ I end return (i) end getind

end intset Рис. 4.5. Реализация типа данных intset.

Прежде всего обратим внимание на реализацию операции create. Заголовок здесь следующий:

create = proc ( ) returns (cvt)

Следовательно, возвращается абстрактный объект, т. е. набор целых чисел. По оператору return должен быть возвращен массив, но к этому объекту перед возвращением применяется операция up. Обратимся теперь к реализации операции insert. В этом слу-лае cvt не используется. Заголовок здесь следующий:

insert = proc (s: intset, х: int)

Следовательно, заданный пользователем абстрактный объект intset не подвергается операции down.

Операция insert не возвращает никакого результата; вместо этого она модифицирует свой аргумент intset. В данной реализа­ции каждый элемент набора встречается в представляющем этот набор массиве только один раз; следовательно, операция insert не может просто добавить целое число х в массив. Она должна прежде проверить, не содержится ли уже х в массиве. Для этой цели используется операция member. Аргументом этой операции является набор целых чисел, поэтому в заголовке insert не ис­пользуется cvt. Заметим, что в обращении к операции member префикс «intset$» отсутствует; этот префикс не требуется, если операция вызывается внутри своего собственного кластера.

Если оказывается, что х не является членом s, к s явно при­меняется операция down и при помощи операции addh х добав­ляется в массив. Если х уже принадлежит s, массив не модифи­цируется. Заголовок операции delete следующий:

delete = proc (s: cvt, х: int)

В этом случае к переданному в качестве аргумента абстракт­ному объекту intset немедленно применяется операция down и внутри операции delete s будет иметь тип array [int].

Операция delete должна прежде всего выяснить, принадле­жит ли х s. Для этого используется внутренняя процедура ge­tind. Если х есть в массиве, процедура getind возвращает индекс, соответствующий расположению х, в противном случае возвра­щается число, большее верхней границы массива. Так как про­цедура getind не указана в заголовке кластера, она является вну­тренней для этого кластера, т. е. может быть вызвана только из этого кластера.

Если х принадлежит s, операция delete просто записывает верхний элемент массива в позицию х и затем уничтожает верх­ний элемент, используя операцию remh. При этом операция remh возвращает удаляемый элемент как результат, однако в нашем случае этот ненужный результат просто уничтожается.

Операция choose позволяет возвратить произвольный эле­мент s. Следовательно, при реализации этой операции мы можем действовать, как нам удобно. Один удобный выбор — это первый элемент массива, другой, тоже удобный, — последний элемент. Конечно, это приводит к тому, что операция choose возвращает обратившемуся к ней различные объекты, но, так как в специ­фикации choose говорится, что выбор произвольный, не следует рассчитывать на возврат каких-то определенных объектов. От­метим, что в согласии со спецификацией операция choose не из­меняет переданного ей в качестве аргумента набора intset.

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