Не забывай  -  или проиграешь!

 

Не секрет, что в России наиболее популярными языками программирования являются Си, Си++ и Паскаль. И, конечно, Ассемблер. Это довольно сильно отличает нашу страну от остального мира, где программы для Windows пишутся обычно на VisualBasic.

 

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

 

Одним из таких языков является LISP  -  LISt Processing (обработка списков). Его придумал в 1956 году профессор Массачусетского технологического института Джон Маккарти для анализа и разбора английских фраз, чтобы обеспечить реализацию проекта по искусственному интеллекту "Принимающий советы". Сначала это были версии для первых компьютеров IBM и DEC. Более-менее законченный вариант LISP 1.5 появился в 1965 году.

 

Лисп, как следует из его названия, предназначен для обработки списков, состоящих из атомов  -  абстрактных элементов, представляющих собой формально не ограниченные по длине цепочки символов. Они могут трактоваться как строки, числа или представлять собой некие логические структуры с вложенными на неограниченную глубину подсписками в виде иерархических деревьев. (Например, данная фраза является типичным в Лисп-смысле списком, который должен быть заключен в скобки.) Для обработки списков используется функциональная модель, базирующаяся на теории Lambda-исчислений Черча. Фактически программа на Лиспе представляет собой набор Lambda-функций, при этом работа со списками осуществляется с помощью базового набора примитивов типа CAR/CDR (взять первый элемент списка, который сам может быть списком/получить список без первого элемента). Таких примитивов в минимальном наборе всего 13. С их помощью и, главное, благодаря рекурсивной системе обработки информации Лисп позволяет очень компактно описывать функции, для реализации которых на других языках программирования потребовались бы сотни и тысячи строчек кода. Такие задачи, как автоматическое доказательство теорем, понимание естественного языка и окружающего мира, логические исчисления, написание компиляторов,  -  все, что требует обработки абстрактной структурной информации, очень удачно описывается и программируется на Лиспе.

 

После первых впечатляющих успехов актуальной стала задача эффективной реализации языка. Сначала все Лисп-системы были интерпретируемыми, что позволяло достичь определенной гибкости, но сильно замедляло сам процесс работы программы. Автор Лиспа опубликовал в 1965 году свою книгу "LISP 1.5 Programmer’s Manual", в которой описал не просто язык, но и структуру так называемой виртуальной Лисп-машины, некоей абстрактной схемы функционирования Лисп-системы, и формального определения структуры компилятора и интерпретатора. Этот труд стал образцом классического описания языка программирования и его окружения, и на него ссылаются вплоть до сегодняшнего дня. Удивительная ясность и простота Лиспа в сочетании с его мощностью и оригинальной идеологией сделала его не просто языком программирования, а своего рода способом формального описания алгоритмов. Кроме того, такие идеи, заложенные в Лиспе, как "сборка мусора" или оптимизация памяти, освобождение ее от "висячих ссылок", актуальны и по сей день.

 

Где-то к этому времени относится первое совершенное в отношении Лиспа преступление, лишившее его основного преимущества перед другими языками  -  прозрачности структуры программы. Кто-то, я не знаю точно, может быть, это был сам Великий  -  Джон Маккарти, ввел в программу примитив PROG, позволяющий писать операторы последовательно, один за одним, как в Фортране или Алголе, и, что самое страшное, добавил оператор GO (goto), без которого PROG, очевидно, был лишен всякого смысла. С этого момента развитие Лиспа пошло под откос.

 

Лисп-машина была реализована в начале 70-х в ряде компьютеров таких фирм, как Xerox и Texas Instruments в виде, как бы сказали сейчас, "зашитой в ПЗУ программы", а тогда воплощенной в "железе" для повышения эффективности функционирования.

 

В конце 70-х годов, когда бурно расцвела теория искусственного интеллекта, происходит второе рождение Лиспа. Создается множество диалектов практически для всех платформ и операционных систем, и именно тогда появляются два диалекта, которые стали основоположниками сегодняшних стандартов. Это прежде всего Scheme Lisp, который унаследовал от своего родоначальника наиболее чистые черты оригинальной идеологии. Пройдя глубокую математическую переработку, эта версия, по-прежнему ограничиваясь небольшим числом базовых примитивов (полное описание языка занимает всего 50 страниц), позволила сосредоточиться на ключевых деталях при решении ряда математических задач, требующих некоего формального описательного аппарата. Например, оригинальной и многообещающей оказалась идея engines  -  параллельных процессов. Поэтому в большинстве научных групп используется именно эта версия Лиспа.

 

Второй диалект, Common Lisp (CL), наоборот, отличался очень большой библиотекой различных функций, чуть ли не превосходящих по количеству аналогичные библиотеки Фортрана (!). Его было значительно удобнее использовать для реализации конкретных проектов, требующих, помимо простого анализа списочных структур, еще и больших вычислительных объемов работы и организации хорошего графического интерфейса. Описание этого диалекта занимает уже около 1300 страниц, в него введено довольно много возможностей обычных процедурных языков типа Си, например строгая типизация, которая в оригинальном Лиспе отсутствовала вообще. CL сильно отличается от языка LISP 1.5 60-х годов, и хотя он и включает в себя все базовые возможности, в реальных проектах обычно используется более подходящая человеческой психологии и более близкая к привычным языкам структура программы  -  линейная, а не рекурсивная. Однако из-за отказа от оригинальной идеологии, когда требовалось очень четко формализовывать задачу в почти математических терминах, сразу возникли проблемы, характерные для обычных задач проектирования и реализации крупных проектов.

 

После активного распространения UNIX в 80-х годах получила широкую известность версия Portable Standard Lisp, реализованная на большинстве платформ, и, наконец, Common Lisp становится фактическим стандартом. А 8 декабря 1994 года в американском Институте национальных стандартов было зарегистрировано официальное описание этого языка ANSI X3.226:1994 (X3J13), которое действует и сегодня.

 

Всплеск интереса к объектно-ориентированному программированию не обошел и Лисп. В него было добавлено понятие объекта, метода, наследования, быстро появился объектный стандарт Common Lisp Object System (CLOS), но при этом его изобретатели не понимали или не хотели понимать, что такое искусственное расширение языка, не соответствующее его идеологии, лишь усложняет Лисп и лишает его как оригинальной ясности, так и эффективности.

 

Современные реализации Лиспа представляют собой большие программные комплексы, близкие к CASE-системам. Этот язык относится, скорее, к 4GL-классу, несмотря на то что был придуман около 40 лет назад. Манипулирование объектами на абстрактном уровне, хоть и требует подчас конкретного, не визуального, кодирования, тем не менее делает ненужным программирование рутинных операций, а наличие больших библиотек, обеспечивающих быструю реализацию множества примитивов, позволяет получить более эффективный и надежный код, чем при ручном программировании аналогичных задач на Си++! Например, совершенно абсурдным может показаться программирование задач автоматического интеллектуального перевода на Си. Интересно, а на чем пишут свои "переводчики" наши программисты? Имеется, кстати, большое число "компиляторов", переводящих текст задачи на Лиспе в С-код.

 

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

 

Конечно, и стоят такие системы недешево. Например, цена многоплатформной версии Allegro Lisp 4.2 составляет $4500, Golden Common Lisp для DOS, Windows, Windows NT и OS/2 стоит $2000, но имеется не меньшее количество и некоммерческих компиляторов, например 32-разрядная версия Allegro Common Lisp 3.0 for Windows, GNU CL для UNIX и т. д.

 

Можно ожидать появления версий и для Интернет. Простой интерпретатор Лиспа на Java уже распространяется бесплатно, а в будущем наверняка появятся и более мощные сетевые диалекты. В силу своей простоты и эффективности этот красивый, но подзабытый в России язык заслуживает не меньшего внимания, чем те же "раскрученные" Си и Си++.

 

Сергей Бобровский

 

В статье частично использованы материалы "LISP.FAQ

(c) 1992-1996 Mark Kantrowitch and Barry Margolin".

Версия для печати