- •4.9.1. Изменяемость
- •4.9.2. Классы операций
- •98 Глава 4
- •4.9.3. Полнота
- •100 Глава 4
- •4.9.5. Операции egual, similar и copy
- •102 Глава 4
- •104 Глава 4
- •5. Исключительные ситуации
- •108 Глава 5
- •110 Глава 5
- •6.2.1. Сигнализация об исключительных ситуациях
- •5.2.2. Обработка исключительных ситуаций
- •112 Глава 5
- •5.2.3. Предложение resignal
- •6.2.4. Необрабатываемые исключительные ситуации
- •114 Глава 5
- •6.2.3. Предложение resignal
- •5.2.4. Необрабатываемые исключительные ситуации
- •116 Глава 5
- •118 Глава 5
- •118 Глава 5
- •120 Глава 5
- •122 Глава 5
- •124 Глава 5
- •128 Глава 6
- •130 Глава 6
- •6.2.1. Реализация итераторов
- •6.2.2. Использование итераторов
- •132 Глава 6
- •134 Глава 6
- •136 Глава 6
- •138 Глава 6
- •140 Глава 7
- •142 Глава 7
- •7.2. Абстракция данных
- •144 Глава 7
- •146 Глава 7
- •148 Глава 7
- •150 Глава 7
- •7.4. Генераторы
- •162 Глава 7
- •154 Глава 7
- •156 Глава 7
- •162 Глава 8
- •164 Глава 8
- •166 Глава 8
- •168 Глава 8
- •170 Глава 9
- •172 Глава 9
- •174 Глава 9
- •176 Глава 9
- •9.1.3. Пример
- •178 Глава 9
- •180 Глава 9
- •182 Глава 9
- •184 Глава 9
- •186 Глава 9
- •188 Глава 9
- •190 Глава 9
- •192 Глава. 9
- •194 Глава 9
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.), должен быть некоторый способ доступа ко всем элементам стека. Мы могли бы задать некоторый итератор,
