Три подхода к программированию
АрхивЕсть такая старая шутка, что всех людей можно разделить по крайней мере на две категории: на тех, кто уверен, что всех людей можно разделить на две категории, и на тех, кто в этом не уверен. Что касается программирования, то с вопросом классификации там еще труднее. Да и вопрос о том, что же такое программирование: наука или искусство? - сродни вопросу о том, что было раньше: курица или яйцо? Себя я отношу к тем, кто считает программирование наукой и, следовательно, пытается ввести в этой науке классификацию.
Классифицировать языки программирования можно по многим параметрам - например по способам контроля типов данных. А можно классифицировать их по стилю, который они требуют от программиста при написании программ. Вообще различают три стиля программирования: императивный, функциональный и логический. Иногда функциональный стиль делят на аппликативный и чисто функциональный. Давайте рассмотрим каждый из стилей подробнее.
Самым распространенным классом языков программирования является класс императивных языков (они еще известны под названием операторных). К ним относятся и Паскаль, и Бейсик, и даже Си++, несмотря на всю его объектную ориентированность. Императивный подход наиболее естественен для человека, общающегося с компьютером. Действительно, если вспомнить определение алгоритма: конечная последовательность определенных в каждый момент времени действий, выполнение которых ведет к решению задачи за конечное число шагов, - то именно набор указаний - императив - наиболее приемлем для кодирования. Да и вообще, приятно ведь кем-нибудь покомандовать! Более того, если вспомнить таких классиков теоретического программирования, как Тьюринг и Пост, то становится понятно, что и они, создавая теорию универсальных вычислителей, пользовались именно императивным стилем написания программ. Фортран и более поздние языки программирования также несут в своих операторах приказной тон:
ДЛЯ i ОТ 1 ДО 10 ДЕЛАЙ.
Среди многих десятков языков программирования есть один "древний старичок". Он чуть моложе Фортрана, и его первый интерпретатор был написан именно на Фортране. Звать его "ЛИСП". Название происходит от английского термина List Processing - обработка списков. Его автором является профессор математики Маккарти. Первая реализация ЛИСП'а была сделана в самом начале шестидесятых годов.
Досталось (и достается сейчас) языку довольно много. Началось все с названия. Имя языка совпадает с английским словом "шепелявить". Представляю, что приходилось выслушивать ЛИСП-программистам по поводу их произношения. Потом языку досталось из-за безумного количества скобок, используемых для записи программ, из-за бедности типов данных (базовых всего два), из-за... список можно продолжить. Но первый компьютерный психиатр "Элиза" был написан именно на ЛИСП'е и только значительно позже переписан на других языках программирования. Первые экспертные системы и системы автоматического доказательства теорем также были исходно реализованы на ЛИСП'е. И это несмотря на бедность средств работы с периферией, контроль типов во время исполнения программы и т. п. Почему же так случилось? Да потому, что ЛИСП - один из немногих языков программирования, который поддерживает функциональный стиль.
Давайте рассмотрим действие некоторой программы P. Она получает на входе некоторый набор (множество) данных М и преобразует его во множество выходных данных M1. То есть программа отображает множество М во множество М1, причем конкретному набору входных данных соответствует конкретный выходной набор. Отображение однозначно! В математике такая зависимость называется функцией, а значит, мы имеем право рассматривать программу как функцию над множеством входных параметров. Кажущаяся сложность определений, полностью окупается тем изяществом, с которым можно писать программы на функциональных языках. Судите сами.
Пусть необходимо реверсировать произвольную последовательность. То есть из конструкции вида (A B C D E F Q) получить (Q F E D C B A). Последовательность может быть произвольной длины и произвольной структуры, то есть вместо любого из атомов А, В, и т. д. может стоять произвольная подпоследовательность. (Вообще, в ЛИСП'е такие структуры называются списками). Решение этой задачи занимает всего несколько строк. Вот оно:
(DEFUN REVERSE-1 (X)
; Определяем функцию реверсирования с единственным аргументом
(COND ((NULL X) NIL)
; Если аргумент пустой, то ничего не делать (вернуть пустой список)
(T (APPEND (REVERSE-1 (CDR X)) (LIST(CAR X))))))
; Иначе объединить реверсированный список, содержащий все элементы исходного за исключением самого первого (головы), со списком, содержащим голову исходного.
Согласитесь, что три строчки не так много для сформулированной задачи.
Еще функциональное программирование, в том числе и ЛИСП, активно применяется в системах символьных вычислений. Мощнейший аналитический решатель задач REDUCE полностью написан на диалекте языка, называемом R-LISP, а все версии AutoCAD, по 12-ю включительно, поддерживают встроенный язык Авто-ЛИСП, хоть злые языки и утверждают, что ЛИСП был выбран начинающей тогда компанией Autodesk не от хорошей жизни, а от нехватки денег для приобретения "серьезного" языка. А ЛИСП (вместе с исходниками) распространялся свободно. Но это сплетни. А если серьезно, то вряд ли Autodesk поддерживала бы и развивала свой язык, если бы функциональный подход никак себя не оправдывал в компьютерной графике.
Итак, нам осталось рассмотреть последний класс языков программирования. Этот класс является "побочным продуктом" разработки компьютеров пятого поколения. Идея была выдвинута в семидесятых годах в Японии, и именно там был реализован логический подход к программированию. Только там мог возникнуть язык, который позволяет компьютеру если не думать, то по крайней мере логично рассуждать. Этот язык получил имя "Пролог" (Programming Logic).
Любой человек по определению - лентяй. При первой возможности ничего не делать, он будет ничего не делать. Именно логическое программирование на Прологе позволило программисту свести к минимуму усилия по (как это ни смешно) проработке логики программы. Идея, заложенная в логический стиль, проста. Давайте сформулируем аксиомы, касающиеся некоторых объектов, и назовем эти аксиомы фактами. Установим отношения между объектами и назовем их правилами или теоремами. Дальше, построим запрос (опять в виде некоторой теоремы) и попросим компьютер доказать либо опровергнуть его. Реализация сформулированной идеи носит естественные ограничения исчисления предикатов, в рамках которого работает язык (о полуразрешимости исчисления предикатов можно прочесть в любом курсе по математической логике). Удобства, предоставляемые Прологом, становятся особенно заметными после некоторой практики программирования задач символьной обработки и искусственного интеллекта.
Однако Пролог нашел интересное применение не только в среде экспертных систем и систем распознавания образов. Для доказательства запросов (целей) правила и факты представляются в Пролог-машине в виде таблицы, то есть любая Пролог-система для каждой задачи строит небольшую реляционную базу данных. Благодаря этому свойству Пролога, стало возможным его использование в качестве языка запросов к обычным базам данных. Использование Пролога в таком новом качестве позволяет многократно повысить скорость обработки запроса, поскольку число промежуточных операций по переводу информации из одного представления в другое резко сокращается.
При работе с базами данных Пролог во многом удобнее императивного SQL. На нем можно относительно легко реализовать СУБД. Однако фирмы - разработчики программного обеспечения пишут софт на Си++, аргументируя свой выбор возможностью писать в объектах. Текстовый процессор на ЛИСП'е "выжмет" из своего автора гораздо меньше сил, чем такой же процессор, но написанный на другом языке. А отладка если и не доставит удовольствие, то точно уж не будет столь изнурительной. И в объектах писать можно (система CLOS - Common Lisp Object System довольно давно стала негласным стандартом языка), и с периферией работать просто. ЛИСП и Пролог сейчас - это мощные и гибкие системы, а пользуются ими единицы. В чем тут дело? Я не знаю, но каждый раз, садясь за SQL от фирмы GUPTA, говорю себе, что у меня просто многолетняя привычка приказывать компьютеру, что делать.