Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Lisp: Слезы радости, часть 2

Оригинал: "Lisp: Tears of Joy, Part 2 "
Автор: Vivek Shangari
Дата публикации: July 1, 2011
Перевод: Н.Ромоданов
Дата перевода: Август 2012 г.
Первую статью серии читайте здесь.

Язык Lisp был оценен, как самый мощный язык программирования в мире. Но только очень небольшой процент самых элитных программистов пользуются им из-за его загадочного синтаксиса и его академической репутации Это весьма печально, поскольку Lisp не так уж и трудно понять. Если вы хотите быть в числе избранных, то эти статьи для вас. Это вторая статья в серии, которая началась в июне 2011 года.

"Мне кажется, чрезвычайно важно, чтобы мы, занимаясь информатикой, получали удовольствие от общения с компьютером. С самого начала это было громадным удовольствием. Конечно, время от времени появлялись заказчики, и через какое-то время мы стали серьезно относиться к их жалобам. Нам стало казаться, что мы вправду отвечаем за успешную и правильную работу компьютеров. Я не думаю, что это так. Я считаю, что мы отвечаем за то, чтобы их обучать, указывать им новые направления и поддерживать гармонию в доме. Я надеюсь, что информатика никогда не перестанет приносить удовольствие. Я надеюсь, что мы не станем миссионерами. Не надо чувствовать себя торговцами Библией. Таких в мире уже достаточно. То, что вы знаете о программировании, могут выучить и другие. Не думайте, что к успешной работе с компьютерами только в ваших руках ключ. Что у вас, как я думаю и надеюсь, есть — это логика: возможность увидеть в машине больше, чем вы видели, когда Вас впервые к ней подвели, увидеть, что вы можете сделать из ее нечто бoльшее."

Это цитата Алана Перлиса (Alan J Perlis), первого лауреата премии Тьюринга, найдет отклик у тех, кто читал мою предыдущую статью о Lisp, которая, в конце концов, о том, как получать удовольствие от общения с компьютером и от самого языка программирования, а также расширять их возможности. Одна из причин, почему это возможно с Lisp, заключается в том, что он был разработан как расширяемый язык программирования. Вникайте в подробности.

При изучении Lisp ничего не заменит хорошую книгу. Начните с бесплатных ресурсов. Я рекомендую следующие книги, которые доступны в интернете:

Ниже приведены фрагменты текста с сайта Пола Грэма, на котором цитируются выдержки из его книг On Lisp и ANSI Common Lisp.

Программирование снизу-вверх

Lisp спроектирован как расширяемый язык; он позволяет вам самостоятельно определять новые операторы. Это возможно т.к. язык Lisp создан из тех же самых функций и макросов, как и ваши собственные программы. Так что расширить возможности Lisp не сложнее, чем написать на нем программу. На самом деле это настолько просто (и настолько удобно), что расширение языка является стандартной практикой. Точно также, как вы пишите свою программу сверху-вниз в сторону языка, вы строите язык снизу-вверх в направлении к своей программе. Вы работаете по технологии снизу-вверх, а также по технологии сверху-вниз.

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

Программирование в стиле снизу-вверх естественно приводит к созданию расширяемых программ. Если вы применяете принцип восходящего программирования вплоть до самого верхнего слоя вашей программы, то этот слой становится языком программирования для пользователя. Поскольку идея расширяемости укоренились в языке Lisp так глубоко, она делает его идеальным языком для написания расширяемых программ.

Работа в стиле снизу-вверх также является лучшим способом создать многократно используемый код. Сущность написания многократно используемого кода состоит в выделении общего из специфического; восходящее программирование изначально создает такое разделение. Вместо того, чтобы тратить все ваши усилия на написание единого монолитного приложения, вы тратите часть своих усилий на создание языка, а часть их — на написание на нем (пропорционально меньшего) приложения. То, что специфично для данного приложения, будет сосредоточена в верхнем слое. Нижние слои образуют язык для написания таких приложений, как ваше, а что может быть более многократно используемым, чем язык программирования?

Быстрое прототипирование

Lisp не только позволяет писать более сложные программы, но позволяет писать их быстрее. Программы на языке Lisp, как правило, более короткие - язык предоставляет вам более крупные концепции, поэтому вам не придется пользоваться ими в большем количестве. Как отметил Фредерик Брукс (Frederick Brooks), лучше известный как автор книги "Мифический человеко-месяц" (The Mythical Man-Month), время, которое требуется для написания программы, зависит, главным образом, от ее длины. Так что только этот факт сам по себе означает, что написание программы на языке Lisp занимает меньше времени. Эффект усиливается за счет динамичного характера языка Lisp: в Lisp цикл редактирования — компиляции — тестирования настолько короткий, что программирование происходит в режиме реального времени.

Более высокие абстракции и интерактивная среда могут изменить способ организации разработки программного обеспечения. Фраза "быстрое прототипирование" описывает вид программирования, который начался с Lisp - на Lisp вы часто можете написать прототип за меньшее время, чем потребовалось бы написать программу в соответствие со всей спецификацией. Более того, такой прототип может быть настолько абстрактным, что он будет более лучшей спецификацией чем та, что написана на естественном языке. И Lisp позволит вам плавно перейти от прототипа к созданию программы. Когда программы на Common Lisp пишутся с прицелом на скорость и компилируются на современных компиляторах, они работаю быстрее, чем написанные на любом другом языке высокого уровня.

Все это, очевидно, означает, что теперь вы сможете тратить на работу меньше времени, и, наконец, видеться с вашей семьей за обедом, что вы обещали им последние три года; ваш босс счастлив и счастлива ваша семья.

Ответы на вопросы

После того, моя первая статья в редакции от июня 2011 года была опубликована на сайте LINUX For You, я получил много вопросов о языке программирования Lisp. К счастью, Девид Ламкинс (David B Lamkins), автор книги "Успешный Lisp" (Successful Lisp), предоставил здесь исчерпывающие ответы на большинство из этих вопросов. Он ответил на следующие вопросы:

  1. Я посмотрел на Lisp раньше, и его не понимаю.
  2. Я не вижу программы из-за скобок.
  3. Lisp очень медленный по сравнению с моим любимым языком.
  4. Никто не пишет программ на Lisp.
  5. Lisp не позволяет мне использовать графический интерфейс.
  6. Я не могу вызвать из Lisp-а код, написанный другими.
  7. Когда моя программа работает, сборщик мусора, используемый в Lisp-е, вызывает непредсказуемые паузы.
  8. Lisp — громадный язык.
  9. Lisp предназначен только для исследований по искусственному интеллекту.
  10. В Lisp-е нет хороших инструментальных средств программирования.
  11. Lisp использует слишком много памяти.
  12. Lisp использует слишком много места на диске.
  13. Я не могу найти хороший компилятор для Lisp-а.

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

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

Начинаем знакомиться

Lisp, название которого является аббревиатурой от сочетания LISt Processing (обработка списков), был разработан для обеспечения возможности символьной обработки при решении таких проблем в программировании, как символьное дифференцирование и интегрирование алгебраических выражений. Несмотря на свое возникновение в виде математического формализма, Lisp является практическим языком программирования.

Основные элементы Lisp-а, к числу которых относятся основные структуры данных, называются s-выражениями. Есть также интерпретатор Lisp-а, который является сердцем любой системы Lisp и, в основном, является машиной, реализующей процессы, описанные на языке Lisp. Интерпретатор Lisp-а выполняет вычисления над s-выражениями посредством процесса, называемого вычислением.

С самого начала в разных реализациях Lisp-а интерпретация и/или компиляция выполнялись по разному. В современных коммерческих версиях Lisp-а обязательно есть компилятор. То, что в современных вариантах Lisp-а часто также есть интепретатор, всего лишь повышает удобство пользоваться некоторыми реализациями, благодаря чему возможно отложенное связывание и, в том числе благодаря интерактивной отладке, улучшенная гибкость.

Строка-приглашение к работе

Я полагаю, что на вашем компьютере уже установлен CLISP (пожалуйста, о том, как устанавливать и использовать CLISP, читайте в инструкциях в части 1). В зависимости от того, какая используется ОС, точная команда, с помощью которой запускается процесс Lisp-а, может отличаться.

В состав любой системы Lisp будет входить интерактивный интерфейс верхнего уровня, называемый toplevel. Вы набираете в этом интерфейсе выражения Lisp-а и система отображает их значения. Lisp обычно отображает строку, которая сообщает вам, что Lisp ждет от вас ввода чего-нибудь. Во многих реализациях Common Lisp в качестве такой строки-приглашения верхнего уровня используется символ > (символ "больше"); в некоторых реализациях могут использоваться совершенно другие строки-приглашения, а в некоторых — они вообще могут не использоваться.

s-выражения

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

> (+ 1 2)
3

В этом примере, вы в скобках просто набрали выражение; Lisp выдал строку-приглашение и ответ. Во многих реализациях Lisp пользователь для того, чтобы сигнализировать о том, что команда завершена, вводит символ перехода на новую строку. В других реализациях работа начнется сразу, как только будет обнаружена закрывающая скобка. Кроме того, в некоторых реализациях вместе с результатом будут выданы дополнительные пустые строки.

В выражении (+ 1 2)символ + называется оператором сложения, а цифры 1 и 2 называются аргументами. В других языках программирования это выражение может записываться как 1 + 2, а в Lisp-е оператор + помещается на первое место, за которым следуют аргументы, при этом все выражение заключено внутри пары скобок. Эта запись называется префиксной нотацией, поскольку оператор указывается на первом месте.

Префиксная нотация Lisp-а более удобна для программистов. Например, если вы хотите сложить вместе пять чисел, то в обычной нотации (и обычном языке программирования) вы должны использовать оператор + четыре раза:

1 + 2 + 3 + 4 + 5

... тогда как в Lisp-е, вы просто еще добавляете аргументы:

> (+ 1 2 3 4 5)
15

Команды, подобные этим, называются s-выражениями, где s указывает на символьное выражение. Это очень общий термин, применимый почти ко всему, что можно выразить на Lisp.

S-выражения состоят из списков и атомов. Списки ограничиваются скобками и могут содержать любое количество элементов, разделенных пробелами. Все остальное - атомы. Элементы списков сами могут быть s-выражениями (иными словами, атомами или вложенными списками). Подробнее о списках и атомах будет рассказано в следующей статье.

Комментарии, которые, с технической точки зрения, не являются s-выражениями, начанаются с точки с запятой и продолжаются до конца строки и, по существу, трактуются как пробелы.

> ;demo of multiplication operator
(* 3 7)
21

Поскольку операторы могут иметь различное количество аргументов, нам для того, чтобы показать, где выражение начинается и заканчивается, нужны круглые скобки. Выражения могут быть вложенными, то есть, аргументы в выражении сами могут быть сложными выражениями.

Предположим, вы хотите вычислить значение ((4*5)/(2+3)), тогда эквивалентное s-выражение в Lisp-е будет следующим:

> (/ (* 4 5) (+ 2 3))
4

Вычисление

Lisp вычисляет все. Он даже вычисляет собственные аргументы. В Lisp вычисляются даже сами числа, то есть, в любое время Lisp пытается вычислить 1, ответ всегда равен 1.

> 1
1
> 2
2

В Lisp + является функцией, а выражение, например,(+ 1 2) является вызовом функции. Когда Lisp вычисляет вызов функции, он делает это в два этапа:

  1. Сначала слева направо вычисляются аргументы. В случае (+ 1 2) для каждого аргумента вычисляется само его значение, так что значения аргументов будут равны 1 и 2, соответственно.
  2. Значения аргументов передаются в функцию с именем указанного оператора. В данном случае, это функция +, которая возвращает 3.

Если какие-нибудь из аргументов сами являются вызовами функций, то они вычисляются по тем же самым правилам. Так что, когда вычисляется (/ (* 4 5) (+ 2 3)), то происходит следующее:

  1. Lisp вычисляет (* 4 5): 4 вычисляется как 4, а 5 вычисляется как 5. Эти значения передаются функции *, которая возвращает 20.
  2. Lisp вычисляет (+ 2 3): 2 вычисляется как 2, а 3 вычисляется как 3. Эти значения передаются функции +, которая возвращает 5.
  3. Значения 20 и 5 направляются в функцию /, которая возвращает 4.

Не все операторы в Common Lisp являются функциями, но большая их часть является. И вызовы функции всегда вычисляются таким образом. Аргументы вычисляются слева направо, а их значения передаются в функцию, которая возвращает общее значение выражения. Это в Common Lisp называется правилом вычисления.

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

Обращайтесь за помощью!

Если вы наберете что-нибудь, что Lisp не сможет понять, то появится сообщение об ошибке, и вы перейдете в программу, которая называется отладчиком.

В обычном отладчике Lisp-а есть возможность приостановить вычисление. Когда вычисление приостановлено (состояние, обычно известное, как разрыв цикла), вы можете изучить содержимое стека времени исполнения, проверить значения локальных или глобальных переменных или изменить эти значения.

То, как работает отладчик, не определяется самим Common Lisp, как таковой. Это больше то, что осталось от создания различных реализаций Common Lisp. Например, нет единого стандарта Common Lisp, который бы указывал, что должно изображаться в строке-приглашении после возникновения ошибки. Нет стандартизации команд, которые должен понимать отладчик. В некоторых реализациях, пользователь обычно вообще не набирает никаких команд; для этой цели просто зарезервированы специальные клавиши.

В CLISP для того, чтобы выйти из прерванного цикла и вернуться на верхний уровень toplevel, просто наберите :q так, как это показано ниже:

1]> (/ 1 0)
 
*** - /: division by zero
The following restarts are available:
ABORT         :R1        Abort main loop
Break 1 [2]> :q
[3]>

Вы должны узнать, какой эквивалент команды :q реализован в вашем варианте Lisp. Поэкспериментируйте, ознакомьтесь с руководством по эксплуатации или обратитесь к местному эксперту.

Что дальше?

Все фанаты фильма X-Men соглашаются со мной, когда я говорю, что последнее дополнение к серии - X Men First Class — оказалось еще лучше. Что может быть лучше, чем узнать о происхождении героев и сюжетной линии, которую вы полюбили. Кажется это, на самом деле, тенденция в Голливуде, коснувшаяся таких фильмов, как Звездные Войны, Бетмен и т.д.

Я буду следовать этой тенденции и в третьей статье дам вам представление об эволюции Lisp. Скромное начало для языка, который вам уже стал нравиться (если вы все еще читаете эту статью, то, вероятно, это произошло, или это просто мое собсвенное самоуспокоение, которого вам недостаточно?!).

Я также подберу темп изложения, поскольку мы только прошлись по самой поверхности языка Lisp.

Продолжение следует...