Пожалуй, ни один другой язык программирования не вызывает столь неоднозначной реакции на себя у программистов. Если Бейсик большинство недолюбливает, а C++ уважает, то к Лиспу кодирующая братия относится настороженно. И во многом виной тому тот факт, что многие даже приблизительно не представляют себе, что же это за зверь такой.
Лисп? Хм... Где-то я это уже слышал...
Хотя многие говорят, что Лисп - это самый старый из активно используемых теперь языков программированию, верить этому стоит с натяжкой. Здесь следует вспомнить старую рекомендацию, что, выслушав рассказ рыбака об улове, следует все цифры для верности разделить на шестнадцать. Лисп, конечно, не мёртв, в отличие от многих своих сверстников и даже куда более молодых машинных языков, но он не самый старый из них. Самым старым из высокоуровневых языков является Фортран, а из всех языков программирования вообще, конечно же, Ассемблер.
Кое-где Лисп до сих пор изучают в ВУЗах. Не знаю, входит ли он в программу подготовки ИТ-специалистов в Беларуси, но, думаю, даже если и не входит, будущим программистам стоит хотя бы поверхностно, с помощью этой статьи, ознакомиться с этим легендарным языком программирования.
Для начала, думаю, немного об истории его создания, хотя ей, пожалуй, стоило бы посвятить и отдельную статью. Дело в том, что создатель Лиспа Джон Маккарти в далёких пятидесятых годах предыдущего столетия занимался вопросами создания искусственного интеллекта. Вопросы эти и с позиции современной науки далеко не просты, а тогда были и вовсе практически за гранью понимания даже хорошо знакомого с программированием человека. Работавший в ту пору в Массачусетском технологическом институте Маккарти нуждался в таком языке программирования, с помощью которого можно было бы легко оперировать со словами обычного английского языка и с их последовательностями. Именно так и был создан язык с довольно оригинальным, на теперешний взгляд, синтаксисом, и названный LISP (нечто вроде акронима от List Processor - процессор списков).
Язык, созданный Маккарти в качестве средства построения искусственного интеллекта, стал популярен и в других областях. И это не случайно. Как совершенно справедливо написано на посвящённом Лиспу русскоязычном портале lisp.ru, "в 1960 Джон Маккарти опубликовал выдающуюся статью, в которой он сделал для программирования примерно то же, что Евклид когда-то сделал для геометрии. Он показал, как, имея в наличии только простые операторы и представление для функций, создать целый язык программирования". Впрочем, дата (1960 год) в данном случае довольно-таки условна - во многих источниках указывается, что оригинальная спецификация и первая версия Лиспа появились на два года раньше, то есть в 1958 году. Впрочем, плюс-минус пару лет для языка с таким богатым прошлым, как у Лиспа, особой погоды не делают.
Особенности Лиспа
Как я уже говорил, по меркам современных технологий программирования и современных же языков, Лисп кажется, по меньшей мере, весьма оригинальным. Впрочем, сами понимаете, в этом нет совершенно ничего плохого. Просто ко всему необычному нужно сначала привыкнуть, чтобы оценить все его плюсы и минусы.
Главной особенностью Лиспа можно считать тот факт, что он работает со списками. С другой стороны, этот язык программирования - функциональный. Я рассказывал о функциональном программировании на страницах "Компьютерных вестей", если конкретно - в статье "Знакомьтесь: функциональное программирование" (№24, 2008 год). С ещё одной стороны, современный Лисп поддерживает также объектно-ориентированное и процедурное программирование. Как может столько парадигм, довольно-таки различных по своей сути, ужиться в одном и том же языке программирования? Оказывается, в этом нет ничего особенно сложного.
Список - это основная единица любой программы на Lisp'е. Списком является любая последовательность любых элементов (элементы заключаются для удобства чтения и для соблюдения иерархии в скобки). Сами элементы при этом делятся на два типа: опять-таки, списки и атомы - элементы простых типов, таких, например, как числа, строки и прочие кирпичи, из которых, в конечном итоге, строится любая программа.
Что касается природы списков в Лиспе, то, с точки зрения структуры данных, это однонаправленный список, то есть каждый из элементов списка в Лиспе указывает на следующий элемент. Эту особенность языка можно использовать в программировании, что, в принципе, Лисп-программисты с успехом и делают.
Если среди элементов списка есть функция, которую нужно вызвать и выполнить, то она должна быть первым элементом в списке, а следом должны следовать её аргументы. Именно поэтому совершенно привычная и естественная для любого другого языка программирования конструкция 2 * 2 в Лиспе принимает вид (* 2 2). Согласитесь, это выглядит довольно необычно и поначалу кажется совершенно неудобным, но, если отвлечься от арифметических операций и посмотреть на другие, "обычные", функции, то, в принципе, ничего смертельного в таком способе записи не обнаруживается.
Все операторы в Лиспе реализованы точно так же, как функции и как арифметические операторы. С их помощью в Лиспе можно управлять ходом программы, организовывать циклы и ветвления, а также делать многие другие очень и очень интересные вещи. Например, очень интересны так называемые лямбда-выражения, встречающиеся и во многих других языках программирования. В Лиспе они реализуются с использованием специального оператора lambda и фактически представляют собой неименованные функции. В других языках лямбда-выражения реализуются несколько иначе, но в Лиспе это, конечно же, всё те же вездесущие списки.
Впрочем, говоря всё время о Лиспе как о каком-то едином языке, я совершаю ошибку или, по крайней мере, поступаю не вполне корректно. Потому что в наши дни Лисп - это уже не один единственный язык программирования, а целое семейство языков с инструментами, предлагаемыми различными производителями и используемыми в разных областях большой страны, называемой информационными технологиями. Думаю, рассказать о различных диалектах Лисп, используемых сейчас в мире, в рамках данной статьи попросту необходимо.
Современный Лисп
Современные диалекты Лиспа и привнесли в него многие из популярных особенностей, например, то же объектно-ориентированное программирование, о котором Джон Маккарти на момент создания своего языка, конечно, даже и не слышал.
Самым популярным современным диалектом Лиспа является Common Lisp. Часто, когда пишут просто Lisp, имеют в виду именно Common Lisp, просто первое слово из его названия опускают для краткости.
Common Lisp - это стандартизованный язык, для которого существует немало компиляторов и интерпретаторов, многие из которых являются не просто бесплатными, а даже совершенно свободными программами. Главными отличиями Common Lisp от Лиспа "классического" является поддержка объектно-ориентированного программирования, без которой сложно представить любой современный язык программирования, а также развитая система макросов - то есть, языковых конструкций, которые можно применять для написания программы в привычном для программистов, использующих другие языки, стиле. Чтобы понять это отличие, посмотрите на листинги. В первом - программа для вычисления факториала на "традиционном" Лиспе, а во втором - она же, но уже на Common Lisp'е.
(defun factorial (n) (if (<= n 1) 1 (* n (factorial (- n 1))))) (defun factorial (n) (loop for i from 1 to n for fac = 1 then (* fac i) finally (return fac)))
Другим популярным диалектом Лиспа является Scheme, ставший уже, в общем-то, самостоятельным языком программирования. Многие Scheme-программисты даже считают, что программируют совсем не на Лиспе, впрочем, конечно, это дело уже десятое - главное, чтобы программировали хорошо. Scheme - это развитие Лиспа в сторону функционального программирования. Главная идея этого языка - минимизация количества встроенных конструкций, с расширением возможностей языка путём создания надстроек из этих стандартных элементов. Впрочем, хотя стандарт Scheme не содержит в себе "излишеств" вроде ООП, большая часть реализаций всё же их предлагает - в виде надстроек, само собой разумеется.
Для того чтобы представить себе отличия между Common Lisp и Scheme, приведу пример реализации вычисления факториала и для этого языка. Как видите, отличий от "классического" Лиспа в случае Scheme намного меньше, чем в случае Common Lisp:
(define (factorial n) (if (= n 0) 1 (* n (factorial (- n 1)))))
В общем-то, помимо Common Lisp и Scheme, существует много других реализаций Lisp, используемых в современных ИТ-процессах. Самым удачным примером внедрения Lisp в качестве языка написания сценариев для серьёзной и большой программы можно считать язык AutoLisp, используемый в AutoCAD'е. Ещё один пример аналогичного, по своей сути, применения этого языка - это, опять-таки, встроенный язык сценариев, но уже в свободном аудиоредакторе Audacity, о котором когда-то на страницах "Компьютерных вестей" рассказывал маэстро Кристофер, а также в не менее свободном графическом редакторе Gimp. В Gimp'е, кстати, используется Scheme. Ну а если я не вспомню о Lisp'е в Emacs, то обидятся линуксоиды во главе с Михаилом Астапчиком (а возможно, и с самим Ричардом Столлмэном).
Резюмируем, пожалуй...
Газета не резиновая - она бумажная. Даже если вы читаете эту статью в электронном виде, на неё всё равно действуют те же ограничения по объёму, что и на статью в печатном варианте "Компьютерных вестей". Это я к чему? Это я к тому, что уже пора закругляться. Лисп - тема, безусловно, крайне интересная, однако хорошего, как говорится, понемножку, и пора уже подвести итоги тому, что было сказано выше.
Ну, во-первых, как вы сами можете убедиться, Лисп - это далеко не мёртвый язык программирования, несмотря на то, что возраст у него весьма и весьма почтенный даже для языка программирования. Сложно, конечно, сказать, кто сейчас "живее", если можно так выразиться, - Лисп или Фортран. Но в том, что Лисп живее того же Кобола, сомнений, думаю, не возникнет ни у кого.
Во-вторых, благодаря Common Lisp'у тот язык, о котором мы с вами так подробно и обстоятельно здесь говорили, не так уж и сильно отличается от "обычных" языков программирования - тех же C++, Java или PHP. Впрочем, Common Lisp, несмотря на свою популярность, это всё-таки уже не тот Лисп, который придумывал Джон Маккарти. Но пользоваться им всё-таки проще и приятнее, чем тем же Scheme. В-третьих, Лисп не так уж и неудобен - просто к нему нужно привыкнуть.
Если вас заинтересовал этот язык программирования, то вам прямая дорога на портал lisp.ru. Там вы найдёте массу информации по этому языку программирования.
Вадим СТАНКЕВИЧ
Горячие темы