А вы знаете, где сейчас используется Лисп?
Лисп — второй по старшинству из ныне живых высокоуровневых языков программирования (после Fortran) и первый функциональный язык. Он был разработан в 1958 году и сильно изменился с тех пор, породив множество диалектов и оказав значительное влияние на развитие других языков. На данный момент наиболее известные диалекты: Common Lisp, Scheme, Racket и Clojure.

Слева: Лисп-машина в музее MIT.
Справа: Лисп-машина Symbolics 3640, фото Michael L. Umbricht и Carl R. Friend (Retro-Computing Society of RI)
Лисп стал “первооткрывателем” многих идей, нашедших применение в современных языках программирования: древовидные структуры, динамическая типизация, функции высшего порядка и многое другое. В этом посте мы не будем углубляться во вклад Лиспа в теорию, а сосредоточимся на практической пользе.
Изначально Лисп предназначался для работ в области искусственного интеллекта, в частности как представление математической нотации для символьных вычислений. Но насколько широко диалекты Лиспа используются сейчас и в каких областях применяются?
Мы в Typeable любим и применяем функциональное программирование, а влияние Лиспа на функциональные языки всё ещё сильно, поэтому нам стало интересно разобраться в этом вопросе.
Кто и что пишет на Лиспе?
Во время учёбы мне часто приходилось иметь дело с диалектами Лиспа. Проведя поиск информации при подготовке этой статьи, я была приятно удивлена, когда находила упоминание кода на том или ином диалекте Лиспа в приложениях, которыми пользуюсь сама. Думаю, и вы найдёте знакомые названия в этом списке.
- GNU Emacs — текстовый редактор, разработанный Ричардом Столлманом в 1984 году, первая программа проекта GNU, участник вечной битвы за звание лучшего текстового редактора. Написан по большей части на своём собственном диалекте Лиспа, Emacs Lisp. На нём же пользователи пишут конфиги и расширения для Emacs. Хотя этот диалект и может использоваться как скриптовый язык общего назначения, он всё же заточен под разработку текстового редактора: например, в Emacs Lisp есть мощная библиотека для работы с текстовыми файлами.
- Grammarly — онлайн-сервис для проверки текстов на английском языке. Сервис использует искусственный интеллект для анализа текста и формирования советов по его улучшению. Проверяется не только грамматика и орфография, но и лаконичность, словарный запас и тон текста. Разработка началась в 2009 году, сейчас у сервиса 30 миллионов активных пользователей ежедневно, он регулярно попадает в различные рейтинги. Я сама использую Grammarly как расширение для браузера, и неожиданно для меня оказалось, что весь их бэкенд, вся работа с обработкой текстов, написана на Common Lisp. Разработчики поделились в своём техническом блоге, почему они выбрали CL и каково это — Лисп в современном продакшене: https://www.grammarly.com/blog/engineering/running-lisp-in-production/
- В Boeing 747 и 777 используется Allegro NFS Server (сервер, использующий протокол сетевого доступа к файловым системам, NFS), написанный на Common Lisp. Продолжая тему авиации: Boeing и Airbus используют Piano — пакет программ на Common Lisp для разработки и анализа конструкции воздушного судна. Узнать больше о низкоуровневой разработке на Common Lisp можно из этого доклада: https://youtu.be/S7nEZ3TuFpA


Заключение
Я попыталась включить в список примеры из разных прикладных областей, инструменты для разработчиков, готовые приложения для нетехнических пользователей и системы, входящие в состав того, чем регулярно пользуется довольно большое число людей, даже не задумываясь об этом.
Конечно, это список не полный, здесь выделены наиболее интересные на мой субъективный взгляд применения Лиспа в современном ПО. Более полные списки библиотек, готовых приложений и компаний, использующих диалекты Лиспа, можно посмотреть в следующих ресурсах:
- Clojure:
- https://clojure.org/community/success_stories
- https://github.com/razum2um/awesome-clojure
- https://github.com/azzamsa/awesome-cl-software
- https://common-lisp.net/lisp-companies
- https://github.com/caocao485/awesome-racket-and-scheme
- https://github.com/avelino/awesome-racket
Рассказывайте в комментариях, какие программы на Лиспах используете и делитесь своими pet-проектами!
Вам также может понравиться:
- Как мы выбираем языки программирования в Typeable
- Сильные стороны функционального программирования
- Зачем мы транспилируем Haskell в JavaScript
- 7 полезных инструментов на Haskell
Первый древнейший: в чём уникальность языка программирования LISP
В этой статье мы поговорим об одном из самых старых языков программирования ― Lisp. Несмотря на свой внушающий уважение возраст, он всё ещё находится в строю и заставляет переосмысливать всю теорию программирования. Так что же это за язык и чем он примечателен?
Лисп, или LISP (от англ. LISt Processing language — «язык обработки списков», современное написание: Lisp) — семейство языков программирования, программы и данные в которых представляются в виде списков.
Существует альтернативная расшифровка названия LISP: Lots of Irritating Superfluous Parentheses («Много раздражающих лишних скобок») — намёк на особенности синтаксиса языка.
Шутливое «Десятое правило Гринспена» гласит: «Любая достаточно сложная программа на Си или Фортране содержит заново написанную, неспецифицированную, глючную и медленную реализацию половины языка Common Lisp».

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

Создан был этот язык в конце 1950-х годов математиком Джоном Маккарти. Принято считать, что именно он положил начало понятию «искусственного интеллекта».
Во время работы над одним из своих исследовательских проектов ему пришлось разработать совершенно новый язык программирования, содержащий ряд концепций, до этого не применявшихся.
1. Условные конструкции
If/then/else и построения из них впервые появились именно в языке Lisp и только затем были позаимствованы другими языками.
2. Функции
В этом языке функции находятся на том же уровне, что и строки или числа.
3. Рекурсия
Несмотря на свою математическую природу и то, что она была известна гораздо раньше появления языка Lisp, впервые она была реализована именно в нём.
4. Переосмысление переменных
Все переменные в рамках языка Lisp представляют собой указатели.
5. Сборка мусора
Механизм эффективного автоматического контроля памяти, который стирает из неё ненужные объекты, впервые появился именно в Lisp-е.
6. Вся программа построена на основе выражений
Стандартная Lisp-программа представляет собой деревья выражений, которые могут возвращать конкретные значения.
Если язык полностью состоит из выражений, это позволяет составлять их любимым способом:
(if foo (= x 1) (= x 2))(= x (if foo 1 2))7. Символьный тип (A symbol type)
Символы отличаются от строк, что позволяет проверить на равенство, сравнив указатели.
8. Нотация для кода (A notation for code)
Подразумевает использование деревьев из символов.
9. Весь язык всегда доступен (The whole language always available)
Нет явного различия между временем чтения, компиляции и выполнения. Можно компилировать или запускать код во время чтения, читать или запускать кода, пока идёт процесс компиляции, или читать, или компилировать код во время выполнения.
Чем ещё примечателен этот язык? Дело в том, что каждый язык обладает развитой библиотекой инструментов для реализации многих концепций. Любой практикующий программист может воспользоваться либо уже имеющимися в наличии классами, переменными, константами и функциями, либо написать свои собственные реализации.
Lisp же, помимо этого, предоставляет возможности расширения синтаксиса, для чего в нём реализована система макросов. Например, Пол Грэм называет макросы «программами, которые пишут программы». Есть мнение, что Lisp более гибкий, чем обычные языки программирования, так как позволяет неожиданным и творческим образом сочетать элементы, что недоступно никакому другому языку.
Например, рассмотрим минимальную исполняемую программу, которая компилируется и выполняется, даже если при этом ничего существенного не происходит. Начнём с C/C++. В этих языках «точкой входа» — местом, где программа начинает выполняться — является функция main (что значит «основная»):
main()<>Круглые скобки после имени функции указывают на то, что мы определяем функцию, а не переменную (подробнее об этом позже), фигурные скобки содержат тело функции, инструкции, которые будут выполнены, когда функция будет вызвана. Пока оставим тело функции пустым. На самом деле написанный выше код упрощён. Он будет компилироваться и выполняться, но так определять можно только единственную функцию — main. Дело в том, что всякая функция имеет тип (это он совпадает с типом вычисляемого результата). Если функция ничего не возвращает, её тип void («ничто»), и он обязательно указывается перед именем функции. Если же тип функции не указан, то подразумевается тип int (сокращение от integer, что значит «целый», т. е. целое число), и тогда функция обязана возвращать целое значение инструкцией return. Функция main имеет целый тип, так что полная версия будет такой:
int main()
Напишем то же самое на Java. Как и в C/C++, точкой входа является функция main, но в Java не существует функций вне классов. Таким образом, нам нужно определить класс, членом которого является функция main (функция, принадлежащая классу, называется методом):
public class Minimal < public static void main(String[] args) <>>В первой строке мы определили класс по имени Minimal, во второй строке мы определили пустой метод main. В отличие от C/C++, в Java все ключевые слова обязательны при определении классов (public class) и методов (public static void). Кроме того, в Java метод main всегда получает массив строк (об этом позже).
Теперь напишем то же самое на Lisp:
Это не опечатка. Вся программа состоит из единственной буквы T, которая в Lisp означает истинное значение (сокращение от truth — «истина»). Что же произошло? Во-первых, в Lisp всякое выражение возвращает некоторый результат. Даже если выражение не является вызовом функции и ничего не вычисляет. В частности, любое значение вычисляется само в себя. Во-вторых, точкой входа является то, что пользователь запускает, будь то функция или значение. Мы «запустили» истину, и она, ничего не вычислив, возвратила саму себя.
Жемчужины Lisp:
- не обязывает программиста определять элементы программы (функции, классы и др.) без необходимости;
- любая сущность Lisp может быть запущена. При этом она возвращает осмысленный результат. В частности это означает, что Lisp не делает разницы между выражениями (expression) и инструкциями (statement), его синтаксис не нуждается в специальном символе завершения инструкции, типа ; в C/C++/Java или разделения между инструкциями в Pascal.
Говоря об этом языке, нельзя не вспомнить и о макросах. Макрос в Lisp — это своего рода функция, которая получает в качестве аргументов формы или объекты и, как правило, генерирует код, который затем будет скомпилирован и выполнен. Это происходит до выполнения программы во время фазы, которая называется развёрткой макросов (macroexpansion). Проще говоря, с помощью макросов можно сделать так, чтобы код Lisp действовал как любой другой язык программирования… Воистину поразительно!
Именно поэтому он получил большую популярность среди хакеров в своё время. Многие отмечают ещё и то, что преимущества этого языка далеко не всегда очевидны тем, кто пытается его использовать, однако более умудрённые программисты говорят, что основной его пользой является опыт переосмысления информатики и программирования в целом. Новый опыт получает любой программист, столкнувшийся с Lisp.
Так как Lisp основан на списках, оператор может представлять собой список элементов, каждый из которых может быть представлен тоже списком либо конечным неделимым элементом, получившим название «атом». В качестве такого атома может выступать, например, какое-либо значение в виде числа или символа.
Lisp является языком системного программирования для так называемых лисп-машин, производившихся в 1980-е годы, например, фирмой Symbolics.
Lisp-машина — универсальная вычислительная машина, архитектура которой оптимизирована для эффективного выполнения программ на языке Lisp.
Эквивалентна абстрактной машине Тьюринга (и обычному персональному компьютеру) по критерию полиноминальной сводимости.
Несмотря на то, что лисп-машины никогда не были широко распространены, многие популярные сейчас идеи и программные технологии были впервые разработаны с помощью лисп-машин. Так, на машинах, которые использовались в исследовательском центре Xerox PARC, были реализованы:
- сборка мусора;
- лазерная печать;
- многооконный графический интерфейс пользователя;
- растровая графика высокого разрешения;
- рендеринг;
- множество сетевых инноваций.
Lisp-машины предоставляли широкие возможности по проведению экспериментальных разработок в области компьютерных наук. На базе разработок таких машин было создано новое поколение инженерных рабочих станций.
Любой язык программирования является живой субстанцией, которая постоянно развивается и совершенствуется. Не был исключением и язык Lisp. Так, ряд лабораторий, исследовавших вопросы искусственного интеллекта, начали предлагать свои интерпретации языка. В результате это привело к появлению ряда диалектов языка Lisp. В период с 1960-х по 1980-е годы образовались такие диалекты, как MacLisp, Interlisp, PSL, Franz Lisp, Scheme, Zetalisp, NIL и T.
Стандартизация языка
К первой половине 1980-х годов в лисп-сообществе сложилась ситуация, которую некоторые авторы сравнивали с Вавилонской башней: параллельно существовали и развивались более десятка крупных диалектов Лиспа, общее же число несовместимых между собой реализаций было существенно больше. Похожая ситуация наблюдалась в это время в большинстве распространённых языков программирования, в случае же с Лиспом ситуация усугублялась тем, что язык изначально был разработан как произвольно расширяемый, что спровоцировало развитие его возможностей в разных диалектах в существенно разных направлениях.
На начальном этапе, когда Lisp использовался почти исключительно в лабораториях и институтах, многообразие диалектов не сильно мешало и даже было отчасти полезным, поскольку способствовало быстрому развитию языка. Но к 1980-м годам, когда появилась потребность в промышленных разработках на Лиспе, обилие реализаций стало тормозом, так как приводило к массовому дублированию разработок и рассредоточению сил на поддержку множества лисп-систем.
Попытки стандартизации Lisp предпринимались почти с момента его появления (первое предложение по стандартизации датируется 1960 годом), но из-за разобщённости и значительных различий в потребностях заинтересованных групп разработчиков ни одно из предложений не было принято. Во второй половине 1970-х годов Министерство обороны США провело огромную работу по анализу ситуации в программных разработках военного назначения, после чего организовало конкурс на разработку нового языка высокого уровня для встроенных систем, которым стал язык Ада. Однако Ада изначально не предназначалась для искусственного интеллекта и символьной обработки, вследствие чего для таких разработок военное ведомство США оказалось вынуждено допустить к использованию более подходящий язык. Поэтому Министерство обороны США оказало организационную и финансовую поддержку формированию промышленного стандарта языка, который и приняло в качестве дополнительного средства разработки ПО для военных применений.
Первоначальный вариант стандарта начали готовить в Университете Карнеги — Меллона на основе внутреннего проекта Spice Lisp, также первоначально нацеленного на разработку лисп-системы для рабочей станции. Проектируемый стандарт с самого начала получил наименование Common Lisp («Общий Lisp»), подчёркивающее цель разработки — получить единый базовый язык, на основании которого можно было бы создавать программно-совместимые системы. В разработке и редактировании стандарта приняли участие около 80 специалистов из университетов, лабораторий и фирм США. Процесс разработки впервые происходил дистанционно, с помощью компьютерной сети ARPANET, через которую было передано свыше 3000 сообщений. Процесс разработки стандарта завершился в 1984 году. Его результат был зафиксирован в первом издании руководства Common Lisp: the Language Гая Стила.
Для чего применяется
Сферы применения языка Lisp многообразны: наука и промышленность, образование и медицина, от декодирования генома человека до системы проектирования авиалайнеров. Первые области применения языка Лисп были связаны с символьной обработкой данных и процессами принятия решений. Наиболее популярный сегодня диалект Common Lisp является универсальным языком программирования. Он широко используется в самых разных проектах: интернет-серверы и службы, серверы приложений и клиенты, взаимодействующие с реляционными и объектными базами данных, научные расчёты и игровые программы.
Существуют специализированные диалекты Lisp, предназначенные для конкретных применений, например, Game Oriented Assembly Lisp (GOAL). Он создан для написания высокодинамичных трёхмерных игр, на нём целиком написана серия игр Jak and Daxter.
Одно из направлений применения Lisp — его использование в качестве скриптового языка, автоматизирующего работу в ряде прикладных программ, в том числе:
- AutoLISP — скриптовый язык САПР AutoCAD;
- Emacs Lisp — встроенный язык текстового редактора Emacs, использованный как в реализации самого редактора, так и в разработке дополнений к нему, что даёт неограниченные возможности расширения функциональности;
- Interleaf Lisp — скриптовый язык в издательском программном обеспечении Interleaf/Quicksilver;
- Nyquist — скриптовый язык в аудиоредакторе Audacity;
- Rep (близок к Emacs Lisp) — язык настроек и расширений в оконном менеджере Sawfish;
- SKILL — скриптовый язык САПР Virtuoso Platform компании Cadence Design Systems;
- TinyScheme — один из скриптовых языков в свободном графическом процессоре Gimp версии 2.4 или более;
- ICAD — система «знаний на основе знаний», которая позволяет пользователям кодировать знания дизайна и опыт инженерного проектирования.
Что дальше?
В случае Лиспа сложно провести чёткую грань между диалектом и языком-потомком, так как различные диалекты Лиспа, созданные за более чем полвека его существования, могут существенно различаться и быть несовместимыми. С другой стороны, Лисп просто в силу возраста оказал то или иное влияние на огромное число языков, причём не только функциональных. Если считать прямыми потомками Лиспа только языки, сохранившие общую структуру программы, но синтаксически несовместимые с Лиспом, то можно выделить следующие:
- Scheme — разработанный в 1976 вариант Lisp, который и сегодня используется в обучении программированию и в исследовательских целях, а также применяется в качестве встраиваемого языка.
- Racket — потомок Scheme, разрабатываемый с 1994 года и находящийся в использовании по сей день. Мощная расширяемая lisp-система, включающая в себя все современные средства поддержки программирования и большой массив библиотек.
- Clojure — созданный в 2007 году на основе Lisp язык функционального программирования, интегрированный с платформой Java (программы транслируются в байт-код и работают под управлением JVM). Унаследовав основные черты Lisp, язык имеет целый ряд синтаксических отличий и нововведений. Интеграция с Java-платформой даёт возможность непосредственно применять весь массив накопленных библиотек для данной платформы. Также Clojure имеет встроенную поддержку параллельного программирования, причём является одним из немногих языков, поддерживающих механизм транзакционной памяти.
- Лого — язык и интерактивная среда, разработанные в 1967 году Сеймуром Пейпертом и Идит Харель для обучения детей дошкольного и младшего школьного возраста основным концепциям программирования. Язык имеет лисп-подобный списочный синтаксис, в котором устранена необходимость использования большинства скобок. Поддерживается также и императивная форма программы, напоминающая Бейсик. Повторение, кроме рекурсии, может быть реализовано с помощью конструкции цикла с фиксированным числом итераций. Характерная особенность среды интерпретатора Лого — поддержка визуального агента («черепашки»), изображаемого в виде пиктограммы на графическом поле (в окне).
Завершая рассказ, можно сказать, что Lisp до сих пор остаётся одним из основных использующихся языков. Применяется он и как средство обычного промышленного программирования, от встроенных скриптов до веб-приложений массового использования, хотя популярным его назвать нельзя: в рейтингах популярности языков он стабильно занимает примерно 29-30 места.
- lisp
- программирование
- исследования в ит
- исследования и прогнозы в it
- Блог компании Сбер
- Программирование
Lisp
Устройте конкурс между агентствами и узнайте реальные цены и сроки выполнения вашего проекта. Создание заказа занимает 5 минут.
Об инструменте
Что такое Lisp
Lisp – семейство языков программирования. Синтаксис диалектов Lisp состоит из линейных списков символов. По этой причине Lisp стал популярен в науке – в языке удобно реализованы символьные вычисления. Lisp стал первым языком, который поддерживает метапрограммирование, благодаря чему на нем появились первые разработки искусственного интеллекта.
Используется для разработки веб-приложений, искусственного интеллекта и в некоторых других промышленных областях. Имеет ряд диалектов (в частности — скриптовых), которые служат для решения определенных задач — от науки и медицины до геймдева. Также существует ряд языков, которые являются прямыми потоками Lisp — Scheme, Racket, Clojure, Logo.
Создан математиком Джоном Маккарти, который первым ввел понятие искусственного интеллекта. Разработка Lisp подразумевала введение ряда новых концепций, которые ранее никем не применялись.
У языка появилось большое количество диалектов из-за его применения в различных лабораториях и интитутах – в то время не было интернета и разные научные группы модернизировали язык под себя. Первая версия языка появилась в 1958 году, но такие диалекты, как Common Lisp, Scheme и Clojure применяют до сих пор.
Основные возможности Lisp
- Списки данных, которые могут быть вложены в друг друга, передаваться как аргументы функций и возвращаться в качестве результатов. Также списки в Lisp могут быть модифицированы и манипулироваться с помощью специальных функций и операторов.
- Продвинутый функционал для создания рекурсий, что делает язык пригодным для решения задач, требующих многоуровневой обработки данных.
- Гибкую система макросов, которая позволяет преобразовывать код перед выполнением и создавать разработчику собственные синтаксические конструкции.
Особенности Lisp
Язык поддерживает сильную динамическую типизацию. Современная версия языка является мультипарадигмальной, но синтаксис языка рассчитан на функциональное программмирование. Lisp – интерпретируемый язык, благодаря чему его программы могут быть запущены напрямую, без предварительной компиляции.
Преимущества Lisp
- Использование списков в качестве данных и данных структур.
- Поддержка метапрограммирования, с которой можно динамически модифицировать язык.
- Автоматический контроль памяти, который снимает с программисту задачу по управлению памятью в программе.
- Большое количество готового кода в сфере разработки искусственного интеллекта.
Уникальные технологии Common Lisp (с примерами использования)
В языке Common Lisp есть как минимум 3 инфраструктурных технологии, во многом формирующие подходы к его применению, которые в других языках либо отсутствуют вовсе, либо реализованы в очень ограниченном варианте. Для компенсации их отсутствия пользователи других языков часто вынуждены использовать Шаблоны проектирования, а порой и вообще не имеют возможности применять некоторые более эффективные подходы к решению типичных задач.
Что это за технологии и какие возможности дает их использование?
Макросистема
- Это основная отличительная особенность Common Lisp, выделяющая его среди других языков. Ее реализация возможна благодаря использованию для записи Lisp-програм s-нотации (представления программы непосредственно в виде ее абстрактного синтаксического дерева). Позволяет программировать компилятор языка.
- Позволяет полностью соблюдать один из основополагающих принципов хорошего стиля программирования DRY (не-повторяй-себя).
- В отличие от обычных функций, аргументы, передаваемые макросам, не вычисляются, поэтому с их помощью можно создавать любые управляющие конструкции языка.
Определение управляющих конструкций языка, которые могут использоваться на равне со стандартными (на самом деле практически все стандартные управляющие конструкции также являются макросами. Основу языка — «аксиомы», которые невозможно определить через другие конструкции — составляют специальные операторы). В качестве примера можно привести анафорические управляющие конструкции (см. библиотеку Anaphora), которые, используя принцип «convention over configuration», скрывают реализацию некоторых типичных шаблонов.
Самый простой пример — макро AIF (или IF-IT), которое тестирует первый аргумент на истинность и одновременно привязывает его значение к переменной IT, которую, соответственно, можно использовать в THEN-clause:(defmacro aif (var then &optional else) `(let ((it ,var)) (if it ,then ,else)))Учитывая то, что в CL ложность представляется константой NIL, которая также соответствует пустому списку, такая конструкция, например, часто применяется в коде, где сначала какие-то данные аккумулируются в список, а потом, если список не пуст, над ними производятся какие-то действия. Другой вариант, это проверить, заданно ли какое-то значение и потом использовать его:
(defun determine-fit-xture-type (table-str) "Determine a type of Fit fixture, specified with TABLE-STR" (handler-case (aif (find (string-trim *spacers* (strip-tags (get-tag "td" (get-tag "tr" table-str 0) 1))) *fit-xture-rules* :test #'string-equal :key #'car) (cdr it) 'row-fit-xture) (tag-not-found () 'column-fit-xture)))(js:defpsmacro set-attr (id attr val) `(.attr ($ (+ "#" ,id)) ,attr ,val))Мета-объектный протокол и CLOS
- Основа объектной системы языка. Позволяет манипулировать представлением классов.
- Методы не принадлежат классам, а специализируются на них, что дает возможность элегантной реализации множественной диспетчиризации. Также возможна специализация не по классу, а по ключу.
- Уникальной является технология комбинации методов, позволяющая использовать стандартные способы комбинации: перед, после, вокруг, —, а также определенные пользователем.
Примерами использования мета-объектного протокола также являются инфраструктурные системы языка, реализованные в виде библиотек:
- object-persisance: Elephant, AllegroCache
- работа с БД: CLSQL
- интерфейс пользователя: Cells
Библиотека CLSQL создана для унификации работы с различными SQL базами данных. Кстати, на ее примере можно увидеть проявление мультипарадигменности Common Lisp: у библиотеки есть как объектно-ориентированный интерфейс (ORM), реализованный на основе CLOS, так и функциональный (на основе функций и макросов чтения).
С помощью мета-объектного протокола стандартный класс языка расширяется специальным параметром — ссылкой на таблицу БД, к которой он привязан, а описания его полей (в терминологии Lisp: слотов) — дополнительными опциональными параметрами, такими как: ограничение уникальности, ключа, функция-преобразователь при записи и извлечении значения из БД и т. д.
Система обработки ошибок / сигнальный протокол
Система обработки ошибок есть в любом современном языке, однако в CL она все еще остается в определенном смысле уникальной (разве что в C# сейчас вводится нечто подобное). Преимущество этой системы заключается опять же в ее большей абстрактности: хотя основная ее задача — обработка ошибок, точнее исключительных ситуаций, — она построена на более общей концепции передачи управления потоком выполнения программы по стеку. Как и системы в других языках. Но в других языках есть единственный предопределенный вариант передачи управления: после возникновения исключительной ситуации стек отматывается вплоть до уровня, где находится ее обработчик (или до верхнего уровня). В CL же стек не отматывается сразу, а сперва ищется соответствующий обработчик (причем это может делаться как в динамическом, так и в лексическом окружении), а затем обработчик выполняется на том уровне, где это определенно программистом. Таким образом, исключительные ситуации не несут безусловно катастрофических последствий для текущего состояния выполнения программы, т. е. с их помощью можно реализовать различные виды нелокальной передачи управления (а это приводит к сопроцедурам и т. п.) Хорошие примеры использования сигнального протокола приведены в книге Practical Common Lisp (см. ниже).
- Kent Pitman, Condition Handling in the Lisp Language Family
- Peter Siebel, Practical Common Lisp, Ch.19 «Beyond Exception Handling: Conditions and Restarts»
Вспомогательные технологии
Кроме того в CL есть ряд технологий менее значительных, которые нельзя назвать в полной мере уникальными, но которые существенно упрощают его применение и делают программы более ясными, а также дают дополнительные возможности для расширения языка:
Протокол множественных возвращаемых значений
Дает возможность возвращать из функции несколько значений и по желанию принимать все их (и привязывать к каким-то переменным) или только часть. По-умолчанию для кода, не использующего эту функциональность, передается только значение.
Казалось бы, это простая возможность, однако, на поверку, она требует обширной поддержки на языковом уровне (учитывая необходимость поддержки возврата из блоков и т. п.).
Протокол обобщенных переменных
Это аналог свойств в некоторых ОО-языках. Концептуально, оперирует понятием места (place) — по сути дела ячейки памяти, однако не физической (без манипуляции указателями) — это может быть просто объект или же элемент какой-то структуры (будь-то опять же объект, список, массив и т. д.) Таким образом, имеются намного большие возможности, чем при использовании обычных свойств, поскольку для любой функции, которая читает значения какого-либо места, можно указать функцию которая его значение задает.
Макросы чтения
Это инструмент модификации синтаксиса языка за пределы s-выражений, который дает программисту возможность, используя компилятор Lisp, создать свой собственный синтаксис. Его работа основана на фундаментальном принципе Lisp-систем: разделении времени чтения, времени компиляции и времени выполнения — REPL (Read-Eval-Print Loop). Обычные макросы вычисляются (раскрываются, expand) во время компиляции, и полученный код компилируется вместе с написанным вручную. А вот макросы чтения выполняются еще на этапе обработки программы парсером при обнаружении специальных символов (dispatch characters). Механизм макросов чтения является возможностью получить прямой доступ к Reader’у и влиять на то, как он формирует абстрактное синтаксическое дерево из «сырого» программного кода. Таким образом, можно на поверхности Lisp использовать любой синтаксис, вплоть до, например, Впрочем, Lisp-программисты предпочитают все-таки префиксный унифицированный синтаксис со скобками, а Reader-макросы используют для специфических задач.
Пример такого использования — буквальный синтаксис для чтения hash-таблиц, который почему-то отсутствует в спецификации языка. Это, кстати, еще один пример того, каким образом CL дает возможность изменить себя и использовать новые базовые синтаксические конструкции наравне с определенными в стандарте. Основывается на буквальном синтаксисе для ассоциативных списков (ALIST):
; a reader syntax for hash tables like alists: #h([:test (test 'eql)] (key . val)*) (set-dispatch-macro-character #\# #\h (lambda (stream subchar arg) (declare (ignore subchar) (ignore arg)) (let* ((sexp (read stream t nil t)) (test (when (eql (car sexp) :test) (cadr sexp))) (kv-pairs (if test (cddr sexp) sexp)) (table (gensym))) `(let ((,table (make-hash-table :test (or ,test 'eql)))) (mapcar #'(lambda (cons) (setf (gethash (car cons) ,table) (cdr cons))) ',kv-pairs) ,table)))))Послесловие
В заключение хотелось бы коснуться понятия высокоуровневого языка программирования. Оно, конечно, является философским, поэтому выскажу свое мнение на этот счет: по-настоящему высокоуровневый язык должен давать программисту возможность выражать свои мысли, концепции и модели в программном коде напрямую, а не через другие концепции, если только те не являются более общими. Это значит, например, что высокоуровневый язык должен позволять напрямую оперировать такой сущностью, как функция, а не требовать для этого задействовать другие сущности такого же уровня абстракции, скажем, классы. Подход к созданию высокоуровневого языка можно увидеть на примере Common Lisp, в котором для каждой задачи выбирается подходящая концепция, будь то объект, сигнал или место. А что дает нам использование по-настоящему высокоуровневых языков? Большую расширяемость, краткость и адаптируемость программы к изменениям, и, в конце концов, настоящую свободу при программировании!
Все про українське ІТ в телеграмі — підписуйтеся на канал DOU
Подобається Сподобалось 0
До обраного В обраному 0
48 коментарів
А еще: 1. Lamkins D.B. Successful Lisp.How to understand and use Common Lisp.20012. Harold Abelson, Gerald Sussman, Julie Sussman, Harold Abelson, Julie Sussman — Structure and Interpretation of Computer Programs (там, правда, Sheme идет, кажется) все хорошо гуглится и ибуглится (eboogle.ru)
Vsevolod Dyomkin программист 20.09.2010 18:37
2 rmrnch: Спасибо за книги — хорошая библиография. С книгами по CLOS’у Bobrowa и ко. не приходилось сталкиваться раньше.
Список книг по Ліспу з моєї бібліотечки: 1. Franz Inc. ANSI Common Lisp — 2002, довідник.2. Sonya Keene. Object-oriented programming in Common Lisp: A Programmer’s guide to CLOS — 1989, 290p.3. Э. Хювёнен, И. Сеппянен. Мир Лиспа. Т1: Введение в язык Лисп и функциональное программирование, 458с.4. Т2 тих же авторів5. Peter Seibel. Practical Common Lisp — 2005, 528p.6. An Introduction to Programming in Emacs Lisp. Second Edition by Robert J. Chassell — 2002, 314p.7. CLOS in Context: The Shape of the Design Space. Daniel G. Bobrow, Richard P. Gabriel, Jon L White — 2004, 34p.8. CLOS: Integrating Object-Oriented and Functional Programming. Ті ж автори, 2004, 20с.9. Common Lisp Object System Specification. Authors: Daniel G. Bobrow, Linda G. DeMichiel, Richard P. Gabriel, Sonya E. Keene, Gregor Kiczales, and David A. Moon — 1988, збірник документів.10. Basic Lisp Techniques. David J. Cooper, 2003 — 100с.11. Tutorial on Good Lisp Programming Style. Peter Norvig, Kent Pitman — 116p.12. On Lisp. 426с.13. COMMON LISP: An Interactive Approach. STUART C. SHAPIRO — 1991, 426с.14. Common Lisp Language Specification — 1096p. ІМНО, найбільш корисна на практиці — як щось не ясно в мові, то однозначно сюди:) + всілякі Idiot’s Guides, коммон лісп кукбук та дещо з того, на що вказує сайт SBCL Internals. Не скажу, що прочитав ті 14 книжок повністю, я більше з точки зору практики підходив — читав, що потрібно для проекту. Збирав я ці книжки в неті вже давненько, тому посилань дати не зможу, але всі вони гугляться.Про компанію — називати не буду, тим більше Лісп в ній не головний напрямок, але вона в Україні.Щоб згадати в пості С++:), зроблю невелику рекламу одній книзі — «Шаблони С++. Довідник розробника», автори Вандевурд, Джосаттіс. Зараз читаю, і просто приємно, коли вміють люди так доступно розписати складні теми. І весело буває — «шаблонний параметр шаблонного аргумента шаблона» — здається, цілком згодиться як скоромовка:)
Vsevolod Dyomkin программист 20.09.2010 18:37
2 rmrnch: Все-таки хотелось бы узнать про компанию, в которой можно посмотреть на большое количество Common Lisp кода (или вы не в Украине?), а также узнать какие именно 10 книг вы прочитали по Lisp’у. Просто я, например, в 21 год о нем вообще не слышал еще, если не считать разве что беглого упоминания в книге Гради Буча — так что, честно говоря, поражает уровень вашей осведомленности уже сейчас (не сочтите за недоверие).
В мене ще жодного разу не було такого відчуття, що Лісп має якусь унікальну і особливу, принципову перевагу над С++.
Можливість поступово допрограмовувати працюючу систему (здається «exploratory programming»): тобто, можливість вносити зміни у вже працюючу систему без необхідності перезапускати її під час розробки, а також можливість випробування нового коду одразу в REPL. Та і можливості розширення мови, мені здається, на порядок ширші за C++.GNU Emacs + SLIME створюють досить таки приємне середовище для «інтерактивного програмування», що, гадаю, принципово неможливо для C++ та подібних, чітко компільованих мов програмування.В той же час, можливість компіляції Common Lisp програм в машинні коди є, на мій погляд, цікавою перевагою у порівнянні з іншими динамічними (скриптовими) мовами програмування (тобто, для яких ще не створено реалізації з відповідними можливостями).
Я не стверджую, що С++ є абсолютно універсальним. Вище вже писав — кожній задачі свій інструмент. Я не впевнений також, що маю право розмірковувати тут про те, чим С++ краще Ліспа, оскільки мої знанння С++ досить посередні, і мабуть на форумі є люди, здатні розкрити цю тему переваг С++ більш глибоко. Проте я спробую, і якщо десь помиляюсь, то вкажіть мені на це. Справа в тому, що багато чого з функціонального програмування та конкретно Ліспа є і в С++ та його бібліотеках. Шаблони і метапрограмування широко використовуються, і я наразі не можу точно сказати, що є такого в Ліспі, чого немає в сучасних бібліотеках для С++ (а частина цих можливостей — новий стандарт С++). Моя впевненість в тому, що С++ не відстає, грунтується на існуванні таких бібліотек, як Boost.Any, Boost.Bind, Boost.Enable If, Boost.Exception, Boost.Foreach, Boost.Function, Boost.Fusion, Boost.Lambda, Boost.MPL, Boost.Optional, Boost.Parameter, Boost.Statechart, Boost.Tuple. В документації до них інколи спеціально пишуть, що дана бібліотека забезпечує реалізацію такої-то концепції функціонального програмування в С++, і мені ці реалізації подобаються деколи більше, ніж оригінали (просто люблю С++:)). В мене ще жодного разу не було такого відчуття, що Лісп має якусь унікальну і особливу, принципову перевагу над С++. А коду на Ліспі я бачив багато, і написаного непоганими фахівцями. Так, іноді він красивий і ефективний, але не кращий «в середньому». А от Вам простий приклад недоліку Ліспа: уявіть собі, що Вам необхідно реалізувати власну систему управління пам»яттю для великого проекту. В Ліспі про збір сміття взагалі не думають, там все бере на себе середовище. А в С++ я можу перевизначити оператор new і мати власну систему збору сміття, яка, наприклад, може попереджати мене про те, що ще 100МВ, і пам»ять закінчиться, а тому користувачу варто зберегти проект. В Ліспі нестача пам»яті — це крах, SBCL каже no more memory і його більше нічого не обходить. Сам бачив:) Тому я думаю, що С++ синтезує в собі багато ідей з різних областей програмування, і непогано балансує між низькорівневістю і абстракцією. Хоча ще раз кажу, це всього лише моя особиста думка, помножена на залишки юнацького максималізму (мені 21). Можливо з віком і новим досвідом я зміню думку, але поки що я вважаю, що С++ і йому подібні мови не просто так популярні, а через ті самі об»єктивно існуючі переваги, про які ми тут так довго і багато балакали:) P.S. Про Пітера Норвіга — коли паттерн реалізується середовищем чи є його частиною, то це зручно, але особисто мені подобається самому закодати і розуміти, як все працює, а не покладатись на закриту реалізацію. Крім того, тій презентації вже 10 років, за той час дещо змінилось і переваги динамічних мов не видались мені вирішальними після прочитання. Словом, все це дуже суб»єктивно, і можливо, мені ще просто рано брати участь в таких фундаментальних дискусіях.
Vsevolod Dyomkin программист 20.09.2010 18:37
Коли говорити про методи розробки для складних систем, то С++ та Java мають таку перевагу, як масовість використання. І відповідна кількість документації для всіх етапів розробки — від загального OOD/OOA до конкретної реалізації того чи іншого паттерна і оптимізації коду. Лісп потребує деякої наполегливості в освоєнні -, а немало книг по ньому переважно не підіймаються вище того, як зробити хитру рекурсію або оптимальний алгоритм чого-небудь, а також як написати макрос, який буде генерити нам макрос, який в свою чергу буде. Про загальну архітектуру пишуть менше, якщо взагалі пишуть. Якщо така книга чи ресурс Вам відомі, поділіться посиланням, буду вдячний:)
1. В практической части PCL (которую, я уверен, вы читали) достаточно много времени уделяется правильному подходу к созданию сложных систем (хотя и в неявной форме). Еще на интересующую вас тему есть книга Patterns of Software: Tales from the Software Community Ричарда Гэбриэла (основателя того самого Lucid). Ее я не читал, но читал некоторые из его эссе. Во всяком случае в западных кругах он считается авторитетом в области Software Design.Не забывайте также, что очень многие исследования в этой области начинались с Lisp представителями Lisp-сообщества и потом распространились далее. Взять, к примеру, того же Gregor Kiczales’а, который написал AMOP, а также предложил аспектно-ориентированное программирование.2. Кроме того, в целом, ничего не мешает вам применять знания о Software Engineering & Design, программируя на разных языках — они ведь, по идее, должны быть языково-независимыми, так ведь? Просто в некоторых языках пресловутые паттерны приходится программировать в явной форме, а в некоторых они реализованы в самой языковой среде.3. Ну и, наконец, к вопросу о самих паттернах/OOD/OOD.etc. и их фундаментальности. Я уверен, что вам также знакома и презентация Питера Норвига, в которой он показывает, что добрая половина из них являются просто костылями, придуманными для обхода искусственных ограничений статических языков. По моему мнению, лучшие учебники по Software Design — не те, которые учат, как запрограммировать ту или иную конструкцию в каком-то конкретном языке, а те, которые демонстрируют фундаментальные (языконезависимые) подходы к разработке и развитию сложных систем от малого к большому (а это такие книги как: SICP, PAIP или On Lisp).
Про залежність від Лісп-хоста — я маю на увазі перенесення системи з одної реалізації Ліспа на іншу. Мені доводилось портувати код з Lucid в SBCL, тут і повилазили всі ці низькорівневі біндінги і виходи за межі стандарту.
Я понял. Ну, это тема для отдельной дискуссии. Опять же, как по мне, это смотря как повернуть.
Я розумію, що в кожної мови своя ніша, і напевно несправедливо вимагати від Ліспа бути придатним для всіх. З іншого боку, коли люди пишуть компілятор в байт код і віртуальну машину для цього коду на Ліспі (а таке є в мене на проекті), то я маю право запитати: ну чим С++ гірше для конкретно цієї задачі? Це саме той випадок, коли маєш молоток і починаєш вважати все цвяхами.
В целом, вы тоже, наверное, будете смеяться, но вы — уже человек, который говорит мне про возможность использования Lisp только в узко ограниченном кругу задач, причём практически одними и теми же словами. На счет драйверов я с вами, конечно, соглашусь (если это не драйвера под Lisp-машину:)), но все остальное. Я, например, как раз использую Lisp под веб (поскольку веб — это только интерфейс), читал о том, как его используют и для embedded (например, для программирования FPGA или генерации asm-кода для каких-то специализированных устройств). Я не знаю специфики той задачи, пример которой вы приводите — это тоже тема для более глубокой дискуссии (можем обсудить по почте), —, но если вы спрашиваете, чем С++ хуже, то тогда ответьте хотя бы, чем он лучше?:) Просто, интересно понять на чем основанна увереноость, что С++ — это молоток для любых гвоздей (притом, что Лисп — нет)?
Коли говорити про методи розробки для складних систем, то С++ та Java мають таку перевагу, як масовість використання. І відповідна кількість документації для всіх етапів розробки — від загального OOD/OOA до конкретної реалізації того чи іншого паттерна і оптимізації коду. Лісп потребує деякої наполегливості в освоєнні -, а немало книг по ньому переважно не підіймаються вище того, як зробити хитру рекурсію або оптимальний алгоритм чого-небудь, а також як написати макрос, який буде генерити нам макрос, який в свою чергу буде. Про загальну архітектуру пишуть менше, якщо взагалі пишуть. Хорошими програмістами стають, коли є в кого повчитися, грамотний код почитати. Не кажу, що перечитав багато по Ліспу (книг 10 набереться), але щось не зустрічалось мені такої книги, як дизайн і архітектура великих систем на Ліспі (або про їх реалізацію без «звичного» ООП, як його розуміють для того ж С++). Де б писали про грамотне розділення системи на ядро, зовнішні інтерфейси, управління пам»яттю, управління мультизадачністю, синхронізацію та інше. Тобто про те, що потрібно на практиці. З прикладами коду. Якщо така книга чи ресурс Вам відомі, поділіться посиланням, буду вдячний:) Я розумію, що в кожної мови своя ніша, і напевно несправедливо вимагати від Ліспа бути придатним для всіх. З іншого боку, коли люди пишуть компілятор в байт код і віртуальну машину для цього коду на Ліспі (а таке є в мене на проекті), то я маю право запитати: ну чим С++ гірше для конкретно цієї задачі? Це саме той випадок, коли маєш молоток і починаєш вважати все цвяхами. Внести в цю машину найменшу зміну вкрай важко — треба пильнувати, щоб все не розвалилось. Тести тут мало помагають, бо теоретично на вхід машини може прийти безконечна кількість тих чи інших результатів від компілятора. Крім того, машина використовує глобальні контексти і багатопотоковість обчислень. Написати для неї осмислені тести не легше, ніж її саму:) Про залежність від Лісп-хоста — я маю на увазі перенесення системи з одної реалізації Ліспа на іншу. Мені доводилось портувати код з Lucid в SBCL, тут і повилазили всі ці низькорівневі біндінги і виходи за межі стандарту. Щоб заімплементити колбек з С в Лісп, довелось лізти в сорси SBCL і з»ясовувати, як же воно все влаштовано. Ви будете сміятись, але мене виручило знання асма — там ці колбеки якраз використовують деяку кросплатформенну надбудову над ним, яка потім вже транслюється в машинний код. Називається це діло VOP — Virtual Operation, наскільки я пам»ятаю. Взагалі SBCL Internals не порадував, можна б було трохи більше розписати, щоб стороннім легше було в код в»їхати. Щось я багато написав, пора завершувати. В підсумку, мабуть, залишимось при старому правилі — кожній задачі свій інструмент. І Лісп хороша річ, і С++ достойна штука. І взагалі, головне — як уявляєш собі задачу та її модель, а на чому імплементити — діло десяте. Хіба є спеціальні вимоги — web, ембеддед, драйвери — тоді вибір інструментів дещо звужується:)
Vsevolod Dyomkin программист 20.09.2010 18:37
2 rmrnch: Мне кажется, вы сами объяснили, в чем проблема c вашей Common Lisp системой:
Система написана в “кращих” традиціях функціонального програмування — всі 50 МВ сорсів належать до одного пакету, чітка архітектура відсутня, про паттерни навіть не згадую. Сам код макаронний, все залежить від всього, і зміни в одному місці можуть аукнутись там, де цього ніхто не чекав. Тестами це все не покрито, бо в часи написання системи TDD ще був не в моді, та й взагалі складається враження, що писали систему без чіткого розуміння того, які недоліки має Лісп.
Проблема не в использовании Лиспа, а в не владении разработчиками грамотным подходом к разработке. (Вы думаете, что при таком же подходе к разработке на С++ получилось бы что-то более поддерживаемое?) Да и, вообще говоря, парадигма функционального программирования (да и метапрограммирования) ортогональны к технологиям организации разработки, а тем более никак не подразумевает она того, чтобы “всі 50 МВ сорсів належать до одного пакету, чітка архітектура відсутня” и т.п.:)
Додайте сюди залежність від хост-Ліспа (а при роботі з викликами в С з Ліспа та особливо з колбеками з С в Лісп ця залежність встає на повен зріст)
Мне кажется, это скорее проблема зависимости С/С++ от хоста. Я так понимаю, вы говорите про независимость от хоста, которая есть у Java — тогда можно использовать ABCL компилятор (например). (Но причем тут сравнение с С++?)
Складність і кучерявість Ліспа в купі з відсутністю нормальної типізації та загальною атмосферою вседозволеності, яка пронизує специфікацію Ліспа, вилазять йому в цьому випадку боком.
Вместо Лиспа здесь можно вставить любой динамический язык (Python, Ruby, Javascript. ). А в ответ услышать примерно такого же уровня утверждение про статические языки.:)
SBCL. Останній, до речі, далеко не фонтан, мені доводилось розбиратись в його коді і навіть трохи правити. Пам»ять SBCL їсть нехило — при компіляції складних макросів може спокійно взяти собі 1500 МВ оперативи, не всяка 3Д забавка стільки бере. Все тому, що там використовується багатократна оптимізація коду на проміжних етапах компіляції. Кожен прохід на великому макросі — +100М-150М меморі, я міряв спеціально засобами самого компілятора. Збирач сміття деколи любить вивалитись з еррором, і цей баг ще й зараз в розсилці по SBCL мелькає. Тому я схильний вважати цей компілятор нестабільним.
Обратите внимание, что память он ест на этапе компиляции и за счет этого экономит память и процессорное время на этапе исполнения. По-моему, это разумный trade-off при оптимизации. А что касается проблемы с GC — я и сам с ней встречался (вот более подробное исследование: http://blo.udoidio.info/2008/1. ), и работа по исправлению ведется. Думаю, это проблема никак не связана со спецификой Common Lisp’а — такие ошибки могут быть у всех: мне, например, рассказывали про баг в.Net GC, из-за которого он может подвисать на несколько минут, и этот баг тоже пока не исправлен (не говоря о том, что никто не пропагандирует SBCL как идеальный или из ряда вон выходящий компилятор).P.S. Если это не промышленный секрет, хотелось бы узнать название организации, где занимаются разработкой и поддержкой Common Lisp систем (к которой вы имеет отношение).
Маючи певний досвід розробки на Ліспі, хотів би зазначити, що для великих проектів він не такий зручний, як той же С++ чи Java. Тонкощі програмування і код, який модифікує сам себе на ходу, відступають перед незручностями відладки і розуміння. За реальним прикладом ходити далеко не треба — в мене на проекті є система моделювання і управління виробництвом, написана майже повністю на CommonLisp. Приблизний розмір сорсів складає 50МВ — для такої мови, як Лісп, де у двадцяти рядках можна мати стільки семантики, скільки на деяких мовах не влізе і в 100−150, розмір гігантський. Система написана в «кращих» традиціях функціонального програмування — всі 50 МВ сорсів належать до одного пакету, чітка архітектура відсутня, про паттерни навіть не згадую. В коді багато великих макросів, для багатьох з них результат виконання macroexpand не влазить на кілька сторінок А4 маленьким шрифтом, є навіть один мегамакрос, який розкривається в 100К веселого коду. Сам код макаронний, все залежить від всього, і зміни в одному місці можуть аукнутись там, де цього ніхто не чекав. Тестами це все не покрито, бо в часи написання системи TDD ще був не в моді, та й взагалі складається враження, що писали систему без чіткого розуміння того, які недоліки має Лісп. Технологічно система крута — має власний компілятор, віртуальну машину, менеджер пам«яті, перехідники в натівні ліби дозволяють їй мати нормальний юай, і все це написано на Ліспі. Але сама якість коду при цьому вийшла кепською якраз через надто активне захоплення макросами і самомодифікацією. Додайте сюди залежність від хост-Ліспа (а при роботі з викликами в С з Ліспа та особливо з колбеками з С в Лісп ця залежність встає на повен зріст), і неспроможність Ліспа бути основою справді великих програмних систем стає очевидною. Складність і кучерявість Ліспа в купі з відсутністю нормальної типізації та загальною атмосферою вседозволеності, яка пронизує специфікацію Ліспа, вилазять йому в цьому випадку боком. Одна справа — вирішити на Ліспі якусь проблему «академічного» характеру, порадіти красі коду і почепити в рамочку на стіну, а інше — написати багаторівневу переносну аплікацію, яку легко супроводжувати і розширяти. Тому я вважаю, що той же С++ в умілих руках дасть кращий результат на виході, крім того, в ньому теж є багато чого з світу Ліспа — Boost розвивається не менш активно за SBCL. Останній, до речі, далеко не фонтан, мені доводилось розбиратись в його коді і навіть трохи правити. Пам»ять SBCL їсть нехило — при компіляції складних макросів може спокійно взяти собі 1500 МВ оперативи, не всяка 3Д забавка стільки бере. Все тому, що там використовується багатократна оптимізація коду на проміжних етапах компіляції, і проходи оптимізатора далі сьомого рідко дають ефект, а кількість проходів там захардкоджена числом 10. Кожен прохід на великому макросі — +100М-150М меморі, я міряв спеціально засобами самого компілятора. Збирач сміття деколи любить вивалитись з еррором, і цей баг ще й зараз в розсилці по SBCL мелькає. Тому я схильний вважати цей компілятор нестабільним. Можливо це суб»єктивно, але мені здається, що особливих причин писати на Ліспі зраз немає — я можу так казати хоча б тому, що досить багато на ньому писав і пишу на роботі, але з двох мов — С++ та Лісп — я б вибрав першу. Можливо їх порівняння взагалі некоректне, бо це різні парадигми програмування, але все врешті-решт зводиться до практичних проблем та їх моделювання — і я не можу пригадати жодної такої проблеми (NP-повні не в рахунок:)), яка б не вирішувалась так чи інакше в рамках С++. Добре писати на С++, розбираючись при цьому в нюансах, набагато складніше, ніж на Ліспі по списках бігати і самомодифікацією займатися. А ось проектування і дизайн однаково складні для обох мов. Все вищесказане є лише моя точка зору, і можливо я дещо применшую тут можливості та користь від Ліспа, але я відштовхуюсь при цьому від практики, а також власних вражень від нього. Цікаво було б почути думку людей, які застосовували на великих проектах Лісп — чи все їх в ньому влаштовує?