
2.2. Иерархические данные и свойство замыкания
125
Все эти примеры дают лишь слабое представление о б огромной области задач, выра-
зимых в виде операций над последовательностями
15
.
Последовательности, здесь реализованные в виде списков, служат стандартным ин-
терфейсом, который позволяет комбинировать обрабатывающие модули. Кроме того, если
мы представляем все структуры единым образом как последовательности, то нам удается
локализовать зависимость структур данных в своих программах в небольшом наборе опе-
раций с последовательностями. Изменяя эти последние, мы можем экспериментировать с
различными способами представления последовательностей, оставляя неприкосновенной
общую структуру своих программ. Этой возможностью мы воспользуемся в разделе 3.5,
когда обобщим парадигму обработки последовательностей и введем бесконечные после-
довательности.
Упражнение 2.33.
Заполните пропущенные выражения, так, чтобы получились определения некоторых базовых опе-
раций по работе со списками в виде накопления:
(define (map p sequence)
(accumulate (lambda (x y) h??i) nil sequence))
(define (append seq1 seq2)
(accumulate cons h??i h??i))
(define (length sequence)
(accumulate h??i 0 sequence))
Упражнение 2.34.
Вычисление многочлена с переменной x при данном значении x можно сформулировать в виде
накопления. Мы вычисляем многочлен
a
n
x
n
+ a
n−1
x
n−1
+ . . . + a
1
x + a
0
по известному алгоритму, называемому схема Горнера (Horner’s rule), которое переписывает
формулу в виде
(. . . (a
n
x + a
n−1
)x + . . . + a
1
)x + a
0
)
Другими словами, мы начинаем с a
n
, умножаем его на x, и так далее, пока не достигнем a
0
16
.
Заполните пропуски в следующей заготовке так, чтобы получить процедуру, которая вычисляет
15
Ричард Уотерс (Waters 1979) разработал программу, которая анализирует традиционные программы на
Фортране, представляя их в терми нах отображений, фильтров и накоплений. Он обнаружил, что 90 процентов
кода в Пакете Научных Подпрограмм на Фортране хорошо укладывается в эту парадигму. Одна из причин
успеха Лиспа как языка программирования заключается в том, что списки дают стандартное средство пред-
ставления упорядочен ных множеств, с которыми можно работать при помощи процедур высших порядков.
Язык программирования APL своей мощности и красоте во многом обязан подобному же выбору. В APL
все данные выражаются как массивы, и существует универсальный и удобный набор общих операторов для
всевозможных действий над массивами.
16
Согласно Кнуту (Knuth 1981), это правило было сформулировано У. Г. Горнером в начале девятнадцатого
века, но на самом деле его использовал Ньютон более чем на сто лет раньше. По схеме Горнера многочлен
вычисляется с помощью меньшего количества сложен ий и умножений, чем при прямолинейном способе: вы-
числить сначала a
n
x
n
, затем добавить a
n−1
x
n−1
и так далее. На самом деле можно доказать, что любой
алгоритм для вычисления произвольных многочленов будет использовать по крайней мере столько сложений
и умножений, сколько схема Горнера, и, таким образом, схема Горнера является оптимальным алгоритмом для
вычисления многочленов. Это было доказано (для числа сложений) А. М. Островским в статье 1954 года,