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

136 Глава 6

Зта операция дополняла бы операцию sma!l_to_big, обсу­ждавшуюся выше.

Для изменяемых совокупностей мы постоянно требовали, чтобы совокупность, по которой происходит итерация, не изме­нялась в теле цикла. Если мы опустим это требование, итератор должен работать по известным правилам даже в том случае, когда сделаны модификации. Например, предположим, что целое число п удалено из набора intset, когда работает операция elements. Должно ли число п выдаваться по операции elements?

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

Модификации, сделанные в теле цикла или выполненные ите­ратором, могут иногда быть полезными. Например, рассмотрим программу, которая выполняет описание задачи в некоторой очереди задач.

for t: task in task. queue$al!_ tasks (queue) do

% выполняется операция t. % если операция t генерирует новую задачу nt, % тогда ее надо поставить в очередь, выполнив % операцию taskqueue$enq (queue, nt) end

Абстракция итерации

Когда выполняемая задача генерирует другую задачу, мы просто помещаем ее в очередь, чтобы она позднее выполнялась. Итератор alLtasks в соответствующее время представит ее на выполнение. Однако такие примеры редки, обычно совокупность не изменяется ни в теле цикла, ни итератором.

6.5. Обзор главы

В этой главе рассматривается проблема полноты типов дан" ных, которые являются совокупностью объектов. Поскольку совокупность, вообще говоря, используется для выполнения некоторого действия над ее злементами, нам необходим некоторый способ доступа ко всем элементам. Этот способ должен быть эффек-

тивным в смысле времени и пространства, удобным для исполь­зования и не должен разрушать данную совокупность. Кроме того, он должен обеспечивать абстракцию через спецификацию.

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

Итераторы эффективны для исполнения. Выдача из итератора аналогична обращению к процедуре. К телу цикла for «обра­щаются» из итератора. Возобновление работы итератора анало­гично возврату из процедуры. Тело цикла «возвращает» управ­ление в итератор. Следовательно, затраты на использование ите­раторов состоят максимум из одного обращения к процедуре на выполнение тела цикла. Такие затраты могут быть меньше из-за оптимизаций компилятора.

Итераторы полезны сами по себе, как это имело место в приме­рах permutations и primes. Однако их основным применением яв­ляются операции над типами данных. В конце книги мы рассмо­трим другие примеры их использования.

Дополнительная литература

Atkinson Russel R., Barbara H. Liskov, Robert \V. Scheifler, 1978. Aspects of implementing CLU. Proceedings of the ACM 1978 Annual Conference, pp. 123— 129.

Упражнения

6.1. Задайте некоторую процедуру is.prirne, в кочорой определяечся, про­стое ли это целое число, и за^ем реализуйте ее, используя итератор allprirnes (рис. 6.10).

6.2. Реализуйте для упорядоченного списка olist итератор big.to_small, который был задан в разд. 6.4.

6.3. Для структуры poly (рис. 4.3), которая выдает все ненулевые термы, было бы полезно иметь итератор terms. Задайте спецификацию для этого итера­тора. Должен ли он быть некоторой операцией структуры poly?

6.4. Реализуйте итератор terms, заданный в упражнении 6.3, или в в"де операции структуры poly, или в другом виде (по вашему усмотрению), зачем используйте итератор terms для того, чтобы реализовать следующее:

diff = proc (р : poly) returns (poly)

effects Возвращается структура poly, которая является результатом дифференцирования набора р.

6.5. Задайте спецификацию абстракции stack, которая обеспечивает доступ к ее элементам в порядке «последним пришел — первым вышел». Стеки изменяемы. Отметим, что для того, чтобы стеки были полезны для каких-либо приложений (например, чтобы реализовать тип в упражнении 6.6.), должен быть некоторый способ доступа ко всем элементам стека. Мы могли бы задать некоторый итератор,

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