primes = sieve [ 2.. ]
where
sieve (p:x) = p : sieve [ n | n <- x, n `mod` p /= 0 ]
> take 20 primes
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71]
10.4 О модульном программировании
Мы убеждены, что модульный подход является ключом к успешному программи-
рованию.
Модульное программирование – это такой способ программирования, при котором
вся программа разбивается на группу компонентов, называемых модулями, причем каж-
дый из них имеет свой контролируемый размер, четкое назначение и детально прорабо-
танный интерфейс с внешним миром. Единственная альтернатива модульности – моно-
литная программа, что, конечно, неудобно. Таким образом, наиболее интересный вопрос
при изучении модульности – определения критерия разбиения на модули. В основе мо-
дульного программирования лежат три основных принципа [7, с. 232]
.
Принцип утаивания информации Парнаса. Всякий компонент утаивает единственное
проектное решение, т.е. модуль служит для утаивания информации. Подход к разра-
ботке программ заключается в том, что сначала формируются список проектных ре-
шений, которые особенно трудно принять или которые, скорее всего, будут меняться.
Затем определяются отдельные модули, каждый из которых реализует одно из указан-
ных решений.
Аксиома модульности Коуэна. Модуль – независимая программная единица, служащая
для выполнения некоторой определенной функции программы и для связи с остальной
частью программы.
Сборочное программирование Цейтина. Модули – это программные кирпичи, из кото-
рых строятся программа. Существует три основные предпосылки к модульному про-
граммированию:
стремление к выделению независимой единицы программного знания. В идеальном
случае всякая идея (алгоритм) должна быть оформлена в виде модуля;
•
•
•
ответ на вызов сложности программирования;
возможность параллельного исполнения модулей.
Языки, от которых требуется эффективность, должны хорошо поддерживать мо-
дульность. Но новых правил видимости и механизма для раздельной компиляции недоста-
точно – модульность подразумевает больше, чем просто использование модулей. Наши
возможности разбиения задачи на подзадачи прямо зависят от наших возможностей со-
единения («склеивания») решений подзадач вместе. Чтобы способствовать модулярному
программированию языки должны содержать хороший «клей». Языки функционального
программирования обеспечивают два новых вида клея – функции высокого порядка и
ленивые вычисления. Используя эти возможности для склеивания, каждый может моду-
ляризовать программу новыми и перспективными путями. Небольшие и очень общие мо-
дули могут неоднократно широко использоваться, путем очень простого последователь-
ного программирования. Это объясняет, почему функциональные программы так малы по
размерам и легки в написании по сравнению с привычными императивными программа-
ми. Если какая-то часть программы выглядит беспорядочной или сложной, программисту
следует попытаться модуляризовать ее и обобщить части программы. Он может ожидать,
что функции высокого порядка и ленивые вычисления помогут это сделать. Более под-
робно об этих вопросах см. [13].
80