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

Однако есть один язык, который странным образом вызывает всеобщее уважение: Lisp. Крестоносцы клавиатур, готовые атаковать любого, кто посмеет заявить, что какой-либо язык лучше других, сходятся в том, что Лисп находится на другом уровне. Он выходит за пределы утилитарных критериев, по которым судят другие языки, поскольку средний программист никогда не использовал Лисп для создания чего-либо практического, и, вероятно, никогда не будет этого делать, однако же, уважение к Лиспу настолько глубокое, что ему часто приписывают мифические свойства. Всеми любимые комиксы xkcd изображали таким образом Лисп как минимум дважды: в одном комиксе персонаж достигает Лисп-просветления, которое помогает ему познать фундаментальную структуру Вселенной. В другом старый программист в халате передаёт стопку круглых скобок своему падавану, объясняя, что это – «элегантное оружие для более цивилизованных времён», намекая на присущие Лиспу оккультные возможности Силы.

Ещё один прекрасный пример – пародия Боба Канефского на песню «Бог живёт на Терре». Его пародия написана в середине 90-х и называется «Вечное пламя». Она описывает, как, по-видимому, Бог создал мир при помощи Лиспа. Далее приводим отрывок, а полную версию можно найти на сайте GNU Humor Collection:
Ведь Бог писал на Лиспе
Когда заполнил листья зелёным.
Фрактальные цветки и рекурсивные корни:
Самый красивый хак из виденных мною.
А когда я изучаю снежинки,
И не нахожу двух одинаковых,
Я знаю, что Бог любит язык
Со своим собственным четырёхбуквенным названием.

Говорю только за себя, но мне кажется, что культурный мем «Лисп – это тайное волшебство», это самое странное и интересное явление. Лисп был задуман в башне из слоновой кости в качестве инструмента для исследований искусственного интеллекта, поэтому он всегда будет немного незнакомым и загадочным для простых программистов. Однако сейчас программисты подначивают друг друга «попробуй Лисп перед тем, как умереть», как будто это какое-то психоделическое средство, расширяющее сознание. Они делают это несмотря на то, что Лисп – второй по возрасту из самых старых языков программирования, которые ещё используют, уступая лишь Фортрану, и то, всего на год. Представьте, что вам поручила бы рекламу какого-то нового языка программирования компания или команда, которая его разработала. Разве не было бы классно суметь убедить всех, что у вашего нового языка есть божественные силы? Но как этого можно было бы достичь? Как язык программирования прославился в роли источника тайного знания?

Как Лисп дошёл до жизни такой?


Обложка журнала Byte, август 1979

Теория А: аксиоматический язык


Джон Маккарти, создатель Лиспа, изначально не стремился к тому, чтобы Лисп был элегантной сутью вычислительных принципов. Но, после одной-двух удачных идей и нескольких улучшений, Лисп превратился именно в это. Пол Грэм – о нём мы расскажем позже – писал, что, создав Лисп, Маккарти «сделал для программирования то же, что Евклид для геометрии». Возможно, люди ищут в Лиспе глубокий смысл, потому что Маккарти создал его из настолько фундаментальных частей, что тяжело сказать, изобрёл он его или открыл.

Маккарти начал размышлять о создании языка во время Дартмутского летнего исследовательского проекта по искусственному интеллекту 1956 года. Этот семинар стал непрерывной многонедельной академической конференцией, самой первой в области ИИ. Кстати, именно Маккарти, тогда будучи адъюнкт-профессором по математике в Дартмуре, придумал термин «искусственный интеллект», предлагая провести эту встречу. В конференции участвовало порядка десяти человек. Среди них были Аллен Ньюэл и Герберт Саймон, два исследователя, связанных с RAND Corporation и Университетом Карнеги-Меллона, только что закончившие разработку языка IPL.

Ньюэл и Саймон пытались создать систему, способную выдавать доказательства в логике высказываний. Они поняли, что это будет тяжело сделать, оставаясь на уровне собственных инструкций компьютера, поэтому решили создать язык – или, как они его называли, «псевдо-код» – который поможет им естественнее выразить работу их «машины теоретической логики». Их язык, IPL, «язык обработки информации», был больше похож на высокоуровневый диалект ассемблера, чем на язык программирования в современном смысле. Ньюэл и Саймон, возможно, имея в виду Фортран, отметили, что «другие псевдо-коды», находившиеся тогда в разработке, были «заняты» представлением уравнений в стандартной математической записи. Вместо этого их язык концентрировался на представлении высказываний в виде списков символьных выражений. Программы на IPL использовали последовательности макросов на ассемблере для обработки и вычисления выражений в рамках одного или нескольких из этих списков.

Маккарти считал, что будет полезно иметь алгебраические выражения в языке, похожем на Фортран. Поэтому IPL ему не нравился. Но он подумал, что символические списки – неплохой способ моделировать задачи из области ИИ, в особенности те, что включают в себя дедукцию. Это был зародыш желания Маккарти создать язык алгебраической обработки списков, язык, который напоминал бы Фортран, но мог бы и обрабатывать символические списки, как IPL.

Конечно, сегодня Лисп не напоминает Фортран. За последовавшие несколько лет идеи Маккарти по поводу идеального языка обработки списков развились. Его идеи начали меняться в 1957 году, когда он начал писать процедуры для программы на Фортране, играющей в шахматы. Длительное воздействие Фортрана убедило Маккарти, что в его дизайне было несколько неудачных мест, главное из которых – неуклюжий оператор IF. Маккарти изобрёл альтернативу, условное выражение «true», возвращающее подвыражение A, если заданная проверка прошла успешно, и подвыражение B в другом случае, и выполняющее только то подвыражение, которое было возвращено. Летом 1958 года, когда Маккарти работал над программой, способной на дифференцирование, он понял, что его условное выражение «true» сделало написание рекурсивных функций более простым и естественным. Задача с дифференцированием также подвигла Маккарти на написание функции maplist, принимающей в качестве аргумента другую функцию, и применяющей её ко всем элементам списка. Она была полезной для дифференцирования сумм произвольного количества членов.

Такие вещи на Фортране было не выразить, поэтому осенью 1958 Маккарти задал нескольким студентам задачу по реализации Лиспа. Поскольку теперь Маккарти был адъюнкт-профессором в MIT, все студенты учились в MIT. Переведя идеи в рабочий код, Маккарти со студентами внесли изменения, ещё больше упростившие язык. Самое крупное из них заключалось в синтаксисе Лиспа. Маккарти сначала хотел, чтобы в языке использовались т.н. «М-выражения», слой "синтаксического сахара", делавшего синтаксис Лиспа похожим на Фортран. Хотя М-выражения можно перевести в S-выражения – простой список, заключённый в скобки, которыми славен Лисп – S-выражения реально были низкоуровневым представлением, предназначавшимся для компьютера. Единственной проблемой было то, что Маккарти обозначал М-выражения при помощи квадратных скобок, а на перфораторе IBM 026, использовавшемся в MIT, квадратных скобок не было. Поэтому команда Лиспа ограничилась S-выражениями, и использовала их для представления не только списков данных, но и применения функций. Маккарти со студентами сделали ещё несколько упрощений, включая переход на префиксную запись и модель памяти, в которой у языка был только один тип real.

В 1960-м Маккарти опубликовал знаменитую работу по Лиспу «Рекурсивные функции символических выражений и их машинное вычисление» [Recursive Functions of Symbolic Expressions and Their Computation by Machine]. К тому времени язык был сокращён до такой степени, что Маккарти понял, что создал «элегантную математическую систему», а не просто ещё один язык программирования. Позже он писал, что многие упрощения в Лиспе превратили его в «способ описания вычисляемых функций, гораздо более точный, нежели машины Тьюринга или общие рекурсивные определения, используемые в теории рекурсивных функций». В своей работе он представил Лисп, как рабочий язык программирования, и как формализм для изучения поведения рекурсивных функций.

Маккарти объяснял Лисп читателям, выстраивая его из небольшого набора правил. Позже Пол Грэм прошёл по следам Маккарти, используя более простой в чтении язык, в своём эссе "Корни Лиспа". Грэм может объяснить Лисп при помощи лишь семи примитивных операторов, двух различных записей для функций и шести функций высокого уровня, определяемых через примитивные операторы. Способность определить Лисп при помощи такой небольшой последовательности простых правил, безусловно, добавляет ему загадочности. Грэм назвал работу Маккарти попыткой «аксиоматизировать вычисления». Я думаю, что это отличный способ размышлять о привлекательности Лиспа. В других языках явно присутствуют искусственные конструкции, описываемые такими зарезервированными словами, как while, typedef, или public static void, кажется, что описание Лиспа ограничено самой логикой вычислений. Это качество и изначальная связь Лиспа с такой эзотерической областью, как «теория рекурсивных функций», должны объяснять сегодняшний престиж языка.

Теория Б: машина будущего


Через два десятилетия после создания, Лисп превратился, согласно знаменитому "словарю компьютерщиков", в «родной язык» исследований в области ИИ. На ранних этапах Лисп распространялся быстро, вероятно, из-за того, что его систематический синтаксис делал задачу его реализации на новых машинах относительно прямолинейной. Позже исследователи продолжали его использовать из-за того, как хорошо он справлялся с символическими выражениями, что было важно в эпоху, когда большая часть ИИ была символической. Лисп использовали в таких плодовитых ИИ-проектах, как программа понимания естественного языка SHRDLU, система компьютерной алгебры Macsyma, и логической системы ACL2.

К середине 1970-х исследователям ИИ начало не хватать компьютерной мощности. К примеру, у PDP-10 – всеми любимой машины для работы с ИИ – было 18-битное адресное пространство, которого всё чаще не хватало для ИИ-программ на Лиспе. Многие ИИ-программы к тому же должны были быть интерактивными, а создание крупной интерактивной программы, хорошо работающей на системе с разделением времени, было трудной задачей. Решение, которое первым предложил Питер Дойч из MIT, состояло в разработке специального компьютера для Лиспа. Такие машины должны были дать каждому пользователю выделенный процессор, оптимизированный под Лисп. На них также должна была работать среда разработки, написанная на Лиспе для хардкорных Лисп-программистов. Лисп-машины, придуманные в неудобный момент в конце эры мини-компьютеров, но до начала расцвета микрокомпьютерной революции, были высокопроизводительными персональными компьютерами для элиты программистов.

Некоторое время казалось, что Лисп-машины будут волной будущего. Появилось несколько компаний, начавших состязаться за коммерциализацию этой технологии. Наиболее успешной из них стала Symbolics, созданная ветеранами MIT AI Lab. В 1980-х Symbolics выпустила линейку компьютеров из серии 3600, популярных в области ИИ и в индустриях, где требовались вычисления высокой мощности. В линейке 3600 были компьютеры с большими экранами, растровая графика, интерфейс, использовавший мышь, мощные программы для графики и анимации. Это были впечатляющие машины, позволявшие писать впечатляющие программы. К примеру, Боб Кали, работавший в области исследования робототехники, написал мне через твиттер, что ему удалось реализовать и визуализировать алгоритм поиска пути на Symbolics 3650 в 1985. Он рассказал, что растровая графика и ООП (доступное на Лисп-машинах благодаря расширению Flavors) были новинками в 1980-х. Symbolics находилась на переднем крае.



Но в результате компьютеры Symbolics были безумно дорогими. Symbolics 3600 стоил $110 000 в 1983. Большинство людей могло только дивиться мощности Лисп-машин и магии операторов, писавших на Лисп, издалека. Но они дивились. Журнал Byte несколько раз описывал Лисп и Лисп-машины в период с 1979 по конец 1980-х. В августовском номере от 1979 года, посвящённом Лиспу, главные редактор восторгался новыми машинами, разрабатываемыми в MIT, «с горой памяти» и «передовой операционной системой». Он считал их такими многообещающими, что предыдущие два года, в которые появились Apple II, Commodore PET и TRS-80, казались скучными. Пять лет спустя, в 1985, автор в журнале Byte описывал процесс написания программ на Лиспе для «сложных и чрезвычайно мощных Symbolics 3670», и призывал читателей учить Лисп, заявляя, что он был как «языком, необходимым для большинства исследователей ИИ», так и кандидатом на будущий язык общего назначения.

Я спросил Пола Макджонса, много сделавшего для сохранения Лиспа в Музее компьютерной истории в Маунтин-Вью, о том, когда люди впервые начали говорить о Лиспе, как о даре существ из высшего измерения. Он сказал, что этому, безусловно, способствовали свойства самого языка, но ещё и близкая связь Лиспа и мощных приложений в области ИИ в 1960-х и 1970-х. Когда Лисп-машины стало возможным приобрести в 1980-х, с мощностью Лиспа познакомилось ещё несколько человек, находившихся вне таких мест, как MIT или Стэнфорд, и легенда продолжила расти. Сегодня Лисп-машины и Symbolics мало кто помнит, но они помогали поддерживать ауру загадочности Лиспа вплоть до 1980-х.

Теория В: обучение программированию


В 1985 профессоры из MIT, Гарольд Абельсон и Джеральд Сасман, а также жена Сасмана, Джулии, опубликовали учебник «Структура и интерпретация компьютерных программ» [Structure and Interpretation of Computer Programs]. В учебнике читателей обучали программированию на языке Scheme, диалекте Лиспа. Его использовали в MIT для введения в программирование два десятилетия. Мне кажется, что это учебник, SICP, добавил мистицизма Лиспу. SICP взял Лисп и показал, как его можно использовать для иллюстрации глубоких, почти философских концепций искусства программирования. Эти концепции были достаточно общими для того, чтобы использовать любой ЯП, но авторы SICP выбрали Лисп. В итоге репутация Лиспа была дополнена дурной славой этой странной и гениальной книги, интриговавшей многие поколения программистов (и ставшей очень странным мемом). Лисп всегда был «элегантным формализмом Маккарти»; теперь он стал ещё и языком, «обучающим вас скрытым секретам программирования»).

Стоит немного рассказать о том, насколько странная это книга – поскольку мне кажется, что её странность и странность Лисп сегодня слились в одно. Странность начинается с обложки. На ней изображён волшебник или алхимик, приближающийся к столу, и готовый начать какое-то колдовство. В одной руке у него кронциркуль или циркуль, в другой – глобус с надписями «eval» и «apply». Женщина напротив него показывает на стол; на фоне висит в воздухе греческая буква лямбда, излучающая свет.



Что тут вообще происходит? Почему у стола нога животного? Почему женщина показывает на стол? В чём значимость чернильницы? Должны ли мы понять, что волшебник раскрыл тайные знания вселенной, и что они состоят из цикла eval/apply и лямбда-исчисления? Видимо, так и есть. Только это изображение должно было многое добавить к сегодняшнему восприятию Лиспа.

Но и текст самой книги часто оказывается таким же странным. SICP не похожа на большинство других книг по информатике. Авторы в предисловии поясняют, что книга не просто о программировании на Лисп – она повествует о «трёх фокусах, или явлениях: человеческом разуме, наборе компьютерных программ и компьютере». Позже они описывают, что убеждены в том, что программирование нужно рассматривать не как дисциплину информатики, а как новую запись «процедурной эпистемиологии». Программы – это новый способ структурирования мыслей, которые лишь иногда вводят в компьютер. В первой главе даётся краткий экскурс по Лиспу, но большая часть книги повествует о более абстрактных концепциях. В ней обсуждаются различные парадигмы программирования, природа времени и идентичности в ОО-системах, а в одном месте – то, какие проблемы с синхронизацией могут возникнуть из-за фундаментальных ограничений передачи сообщений, играющих роль скорости света в теории относительности. Это довольно заумные вещи.

И не сказать, что книга плохая. Она чудесная. В ней обсуждаются важные концепции программирования на уровне более высоком, чем во всех других прочитанных мною книгах, концепции, о которых я давно задумывался, но не мог описать. Удивительно, что учебник по введению в программирование так быстро может перейти к описанию фундаментальных недостатков ООП и преимуществах функциональных языков, минимизирующих изменяемое состояние. Удивительно, как это превращается в обсуждение того, как потоковая парадигма, наверно, что-то вроде сегодняшней RxJS, может дать вам лучшее обоих подходов. SICP выделяет самую суть разработки высокоуровневых программ способом, напоминающим исходную работу Маккарти по Лиспу. Первое, что вам хочется сделать, прочтя эту книгу – заставить прочесть её ваших друзей-программистов; если они её найдут, увидят обложку, и не станут читать, то всё, что у них отложится – это то, что некая загадочная штука по имени eval/apply даёт волшебникам особую власть над столами с ногами животных. Меня бы ещё впечатлила их обувь.

Но, возможно, наиболее важный вклад SICP состоял в подъёме Лиспа с уровня забавной диковинки до педагогической необходимости. Задолго до SICP люди советовали друг другу изучить Лисп, чтобы повысить свой уровень как программиста. Номер журнала Byte от 1979 года тому свидетельство. Тот же редактор, восхищавшийся новыми Лисп-машинами в MIT, объяснил, что стоит учить этот язык, поскольку он «представляет другую точку зрения на задачи». Однако в SICP Лисп был представлен не просто как контраст к другим языкам. Его использовали в качестве вводного языка, намекая, что это лучший язык для изучения базовых понятий программирования. Когда сегодняшние программисты советуют друг другу попробовать Лисп до того, как они умрут, они, вероятно, делают это из-за SICP. Ведь Brainfuck тоже, вероятно, предлагает «другую точку зрения на задачи». Но люди вместо этого изучают Лисп, зная, что уже лет двадцать точка зрения Лиспа была настолько полезной, что студентов в MIT учили Лиспу до всех остальных языков.

Возвращение Лиспа


В год выхода SICP Бьёрн Страуструп опубликовал первое издание книги "Язык программирования C++", принёсшей ООП в массы. Несколько лет спустя рынок Лисп-машин рухнул, и началась зима ИИ. За последовавшие десять с чем-то лет C++ и потом Java стали языками будущего, а Лисп прозябал.

Естественно, невозможно указать, когда точно люди стали снова восхищаться Лиспом. Возможно, это произошло после того, как Пол Грэм, сооснователь Y-Combinator и создатель Hacker News, опубликовал несколько влиятельных эссе, где описывал Лисп, как лучший язык для стартапов. В эссе "Опережая средних" Грэхем утверждал, что макросы Лиспа сделали язык сильнее других языков. Он заявил, что использование Лиспа в своём стартапе Viaweb помогло ему разработать определённые вещи быстрее, чем это смогли сделать конкуренты. Некоторых программистов это убедило. Но большинство не переключилось на Лисп.

Вместо этого всё больше особенностей Лиспа стало попадать во всеми любимые языки. В Python появилась генерация списков. В C# — Linq. В Ruby… ну, Ruby – это и есть Лисп. Как отмечал Грэм ещё в 2001, «язык по умолчанию, встроенный во многие появившиеся позже популярные языки, постепенно развивался в сторону Лиспа». И хотя другие языки постепенно приближаются к Лиспу, сам Лисп как-то поддерживает свою особую репутацию загадочного языка, который мало кто понимает, но все должны изучить. В 1980, в год 20-летия Лиспа, Маккарти писал, что Лисп выжил так долго, поскольку занял «примерный локальный оптимум своего рода в пространстве ЯП». Но это недооценивает реальное влияние Лиспа. Он выживает уже пятьдесят лет потому, что программисты десятилетие за десятилетием нехотя признавали, что это лучший инструмент для своей задачи. Он выжил, даже несмотря на то, что большинство программистов его не используют. Благодаря его происхождению и использованию в исследованиях ИИ, и, возможно, также наследию SICP, Лисп продолжает восхищать людей. И пока мы не сможем представить Бога, сотворившего мир при помощи какого-то более нового языка, Лисп никуда не денется.

Комментарии (50)


  1. lain8dono
    30.10.2018 13:50
    +1

    Заголовок спойлера
    1. Neikist
      30.10.2018 13:59

      Серийные эксперименты? Вообще я еще где то его видел в аниме кажется.


      1. lain8dono
        30.10.2018 14:09
        +1

        В эндинге Subete ga F ni Naru: The Perfect Insider?


        1. Neikist
          30.10.2018 14:16

          Первое, увы, не смотрел, во втором такого тоже не помню. Мне кажется я видел это где то в относительно свежих вещах.


    1. Varim
      30.10.2018 15:36
      +5

      Для которого Бога?
      Спорят викинг и раввин,
      Спор заведомо бесплоден:
      — Бог — один. И он не Один.
      — Один — Бог. И не один.
      Раввин и викинг в жарком споре
      сошлись на том, что сила в Торе!


  1. vesper-bot
    30.10.2018 14:24

    Я ещё застал время, когда Лисп был без всех этих let и setq. Когда побочные эффекты были единственным вариантом сделать что-то вне собственного значения возврата (и то могу путать с Паскалем), когда на интуитивном уровне появляось понятие «хвостовая рекурсия», когда рекурсивный подход к решению задач был вообще единственным, и можно было понять рекурсию, пока понимаешь рекурсию… когда единственное место для хранения результатов вычислений — это стек без локальных переменных… много чего было, я тогда проперся конкретно. Мы тогда писали то ли курсовик, то ли лабу — перемножить многочлены от Х, если на входе они в символьном формате вроде «2x^2+3x-6», и из моей группы только у меня хватило мозгов преобразовать формат в лисповские списки (2 2)(3 1)(6 0), потом вычислить, потом преобразовать обратно. Но решили все, хотя бы как-то. Бедный mulisp.com :)


    1. IIvana
      30.10.2018 18:17
      +1

      let же может быть тривиально реализован как макрос — например


      (let (a (+ 1 2 3)
            b (* 4 5 6))
        (foo (+ a b)))

      раскроется как


      ((lambda (a b) (foo (+ a b))) (+ 1 2 3) (* 4 5 6))

      и для этого не нужно ничего в ядре языка, макросы позволяют навернуть на базовых возможностях все что угодно. let* так же тривиально макросом реализовать, только там будет разворачиваться не в одну мультиарную лямбду, а в несколько вложенных унарных — для гарантии порядка вычисления аргументов, если он не гарантируется в колл-конвеншене вызова (как в Scheme, например).


      1. Druu
        30.10.2018 19:29

        let же может быть тривиально реализован как макрос — например

        let действительно легко реализуется, но core-форма обычно letrec, и тут уже есть проблемки.


      1. PerlPower
        31.10.2018 01:00

        В лиспе все можно реализовать в виде макроса, в этом-то и беда.


        1. x86128
          31.10.2018 19:03

          Это точно, можно завернуть так, что потом свой код через длительное время придется разбирать заново.


          1. Druu
            31.10.2018 19:20

            Это можно на любом ЯП завернуть :)


      1. vesper-bot
        31.10.2018 11:45

        А вот не было макросов изначально в лиспе! Во всяком случае, в том виде, в котором его нам на третьем курсе преподавали. Восемь функций: lambda, atom, eq, car, cdr, cons, quote, cond — всё. Как только кто-то запилил let/set в лисп, на нем стало возможно писать программы в императивном стиле, с переменными и присваиванием. До того — фиг, только функциональный стиль был доступен. Извращались как могли. Единственным по факту послаблением был defun — обертка над лямбдой. (Правда, честно, так и не осилил пользоваться именно лямбдой… и есть подозрение, что можно написать что-то вроде (defun let (a b) (defun (quote a) nil (quote b))) и будет работать)


        1. IIvana
          31.10.2018 12:09

          Я понимаю, что есть миллион диалектов сабжа, но не верю, что среди них есть такие запущенные )


          1. Если нет макросов — напиши свой макропроцессор. Гомоиконность, как-никак. Пишешь кот, квотишь его, скармливаешь функции преобразования, получаешь другой кот, копипастишь результат куда надо.
          2. Про императивный стиль — и сейчас есть широко распространенные языки, в которых нет мутабельности от слова совсем. И ничего, живут как-то люди.
          3. Defun — это (внезапно) тоже макрос ) То есть

          (defun (f a b) (+ a b))

          раскрывается в


          (def f (lambda (a b) (+ a b)))

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


          1. vesper-bot
            31.10.2018 12:21

            Ну вот, пришел спец и макнул носом в лужу. :) По поводу eval — надо копать старые файлы, кажется, наш вариант ПО у меня где-то сохранился ещё, но если defun — макрос, то там, скорее всего, и setq был, и eval, и остальное, но ничего из этого не было в преподанном, и проверялось на отсутствие, сколько мне известно.

            Да, я думал именно наколхозить механику let/set через лямбды. Формально решение должно существовать, если макрос является строгой Лисп-функцией, и может отсутствовать, если прикручен извне.

            Про императивность — меня учили не разбрасываться памятью, и в 1996м сборка мусора была в зачаточном состоянии, ещё как парадигма только ЕМНИП, как следствие, иммутабельными могли быть только константы, иначе программа быстро исчерпывала память. А так — если прописывать, что при вызове функции под результат каждый раз выделяется память, которую средствами языка потом нельзя поменять, why not.


            1. IIvana
              31.10.2018 13:20

              Решил побаловаться — написал лет через функцию. Только квотировать при вызове надо, как выше говорил


              (defn let (l)
                    (defn go (l ns es)
                          cond (null? (cdr l)) (cons (cons 'lambda ns l) es)
                          (go (cdr l) (cons (caar l) ns) (cons (cadr (car l)) es)))
                    ((lambda (x) (print "macroexpand:" \n x \n) (eval x))
                     (go l nil nil)))
              
              (let '((a (+ 1 2 3))
                     (b (* 4 5 6))
                     (c (* 7 8 9))
                     (+ a a b b c c)))
              
               => macroexpand:
              ((lambda (c b a) (+ a a b b c c)) (* 7 8 9) (* 4 5 6) (+ 1 2 3))
              1260


        1. fierce-katie
          01.11.2018 11:40

          Предположу, что вам его преподавали в рамках какого-нибудь курса типа «Функциональное программирование», а Лисп использовали в качестве языка для демонстрации возможностей парадигмы, причём даже не какой-нибудь существующий диалект, а «сферический Лисп в вакууме», в котором ничего императивного использовать нельзя, а про макросы рассказывать просто не нужно, пока дело не дойдёт до написания реальных программ (видимо, курсового практикума). Но интересно узнать, был ли живой в какой-то момент времени диалект, состоящий только из восьми упомянутых примитивов.


          1. vesper-bot
            01.11.2018 11:51

            В яблочко.

            Думаю, в самом начале был такой, но недолго.


            1. fierce-katie
              01.11.2018 14:50

              Попробую ещё более в яблочко: ВМК, АЯ? :)


  1. x86128
    30.10.2018 15:25
    +1

    Занимательный факт: игровая логика The Last of Us написана на lisp, о чем говорится в видео Unsynced: The Last of Us Melee System

    Так же следует обратить внимание на язык Racket (это развитие Scheme/lisp). По сути это полигон развития языкостроения


    1. Druu
      30.10.2018 17:02

      Так же следует обратить внимание на язык Racket (это развитие Scheme/lisp). По сути это полигон развития языкостроения

      Стоит отметить, что некий небезызвестный typescript построен в значительной части именно на базе научной работы команды Racket.


      И яп для упомянутого Last Of Us тоже именно на Racket писались (с-но, в Last Of Us, как и в Uncharted, использовался не один язык, а много специализированных диалектов).


      1. Neikist
        30.10.2018 17:09

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


        1. x86128
          30.10.2018 19:17
          +1

          Дядька из ролика вещает, что использование лиспа, помимо программистов, позволило привлечь игровых дизайнеров к написанию скриптов и тем выпустить игру в короткий срок.

          То есть, в смежных с программированием областях, нужда в неких DSL есть и использование лиспа позволяет достаточно просто такую задачу решить.

          Поклонники Racket особенно плодовиты, там даже шутка у них есть, что в неделю до 8-ми языков изобретают.


    1. newpy
      31.10.2018 11:06

      Так же следует обратить внимание на Clojure. Который как современный диалект Лиспа, широко используется (CircleCI, Wallmart, Atlassian, etc.) в том числе в крупных продакшн проектах. Например на Clojure написана транзакционная БД Datomic, представленная в AWS.

      Например согласно этому опросу/исследованию JVM экосистемы от JavaMagazine, (более 10к респондентов разработчиков) Clojure занимает второе место после Java среди языков использующих JVM платформу.

      Не может не радовать что в наши дни современные диалекты как Racket и Clojure имеют такое широкое применение.

      Собственно счастлив тем, что использую Clojure ежедневно в работе как Clojure разработчик.

      Автору спасибо за статью. Было интересно читать.


      1. Kirhgoff
        31.10.2018 13:53

        Да про Clojure все знают, это вы как из другой вселенной вещаете :) Обалденный язык, но трудно людей к нему склонить, к сожалению. Сам очень его люблю, у меня коллега в момент слабости тим лида запилил на нем сторонний проект по импорту данных из разны систем. Все классно, работать с ним удовольствие, но одна проблема, как в спринт попадает задачка на добавление туда функционала, если я или другой мой clojure-enabled товарищ заняты на других эпиках, новый человек там теряется и время исполнения задачи умножается на 10, потому что страшно ему, потому что нужно запариваться (pair) со знающими clojure людьми и в итоге есть недовольство. Так мы вирус clojure не внесли в наш Ruby коллектив. Им все хочется на go программировать, если уж экзотику можно. Очень грустно от этого, я моменты программирования на clojure лелею


        1. newpy
          31.10.2018 14:14

          В текущие проекты сложно такое «пропихнуть», проблема понятна и на слуху, остается только сочувствовать. Но как отдельный сервис иногда может быть альтернативой тому же Go в зависимости от задачи, особенно если это касается работы с данными. Просто Go это мейнстрим, и понятен большинству, не надо сворачивать голову о ФП. Clojure в сравнении с ним крайне маргинальная вещь. С другой стороны в этом можно найти и плюсы.


        1. x86128
          31.10.2018 19:00

          Не знаю, попадалась ли вам эта статейка — Why Ruby is an acceptable LISP

          Так что вы, являясь членом Ruby коллектива, фактически и так пишете на lisp, потому вам и кложа приятна :)


          1. Druu
            31.10.2018 19:21

            Руби негомоиконный, что, с-но, ставит крест на полноценном метапрограммировании.
            Ну и нормальной модели compile-time'а в рубях нет. Хотя, справедливости, ради она и в лиспах только в scheme-derived диалектах есть.


          1. Kirhgoff
            31.10.2018 23:45

            Статью не видел, почитаю, но в моем случае приятность кложи не связана с Ruby.
            Я сначала писал 16 лет на Java, потом сьехал на Scala, потом попробовал Clojure а потом переехал в Австралию и два года пишу на Ruby :)


    1. beeruser
      01.11.2018 04:49

      У Naughty Dog был свой диалект LISP — GOAL.
      Собcтвенно игра Jax & Daxter написана на нём чуть ли не целиком.
      en.wikipedia.org/wiki/Game_Oriented_Assembly_Lisp


      1. Druu
        01.11.2018 09:47

        У них их много разных было. GOAL, получается, конкретно под ps2.


  1. speakingfish
    30.10.2018 16:18
    +2

    «Compass» здесь — циркуль а не компас.
    Соответственно вместо «кронциркуль или компас» должно быть «циркуль или кронциркуль»


    1. vvzvlad
      30.10.2018 18:01
      +1

      Причем, это понятно, даже если просто посмотреть на картинку


  1. Slowz
    30.10.2018 19:54
    +1

    Мне кажется что современная популярность Lisp'а отчасти обязана его современным потомкам, например Clojure или Common Lisp. Мне посчастливилось работать с Clojure.


  1. qw1
    30.10.2018 20:44

    В играх тоже бывает. Вот только что заскринил

    Скрытый текст


    1. dopusteam
      30.10.2018 21:21

      Подскажите, что за игра?



      1. xztau
        31.10.2018 08:21

        emacs:)


    1. Industrialman96
      01.11.2018 11:40

      А что за игра?


      1. qw1
        01.11.2018 14:35

        Выше же написано.


  1. DelphiCowboy
    31.10.2018 09:19

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

    В год выхода SICP Бьёрн Страуструп опубликовал первое издание книги «Язык программирования C++», принёсшей ООП в массы. Несколько лет спустя рынок Лисп-машин рухнул

    Было бы очень интересно прочитать, что такое Лисп-Машины, и чем они столь радикально отличались от обычных компьютеров.


    1. x86128
      31.10.2018 18:47

      Можете прочитать на википедии, взяв оттуда список названий машин и загуглив документацию например на bitsavers. Стоит сказать, что события разворачивались в 70-х и тогда еще небыло понятия «обычный компьютер». Были только большие ЭВМ и очень большие.

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

      Но потом, в 80-х, появились микро-компьютеры и RISC процессоры которые стоили дешевле на порядки и работали при этом достаточно быстро покрывая нужды большинства программистов.


  1. KES777
    31.10.2018 13:17

    Было бы интересно видеть в статье пометку: а сколько же это "гора памяти" в те времена.


    Заметку сделать вот в этом месте:


    В августовском номере от 1979 года, посвящённом Лиспу, главные редактор восторгался новыми машинами, разрабатываемыми в MIT, «с горой памяти» ( XXXКбайт, — прим. ред.)


    1. DelphiCowboy
      01.11.2018 07:27

      Погуглил, и получил ссылку на… Хабру:

      habr.com/post/190082
      В 1988 эта же компания представила миру линейку Ivory, первым представителем которого был XL400. Эти же компьютеры были уже 40-битными и позволяли адресовать 16ГБ памяти

      А ведь обычным программам тогда более чем хватало 640kb…


  1. Fen1kz
    31.10.2018 15:05

    Лисп классный, но скобки перед функцией меня убили. Так и писал:
    add ( 2 *мат* backspace backspace ctrl+left ( ctrl+right 2 3 )
    :(


  1. nmrulin
    31.10.2018 15:08

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


    1. DelphiCowboy
      01.11.2018 11:48

      Судя по всему, интерес, похоже, угас потому, что ФП, в 1988 году, хотело 16GB памяти (пруф habr.com/post/190082 ), в то время как всем остальным хватало 640kb.


      1. Druu
        01.11.2018 12:04
        +1

        Он из-за AI Winter угас. А 16gb — это лишь максимально адресуемая память. На данный момент для 64 битных систем она, с-но, порядка 16 эксабайт, но это не значит, что столько актуально требуется :)


  1. Whiteha
    31.10.2018 17:27
    +2

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


    1. x86128
      31.10.2018 18:36

      Сейчас, в 2018, в питон и js уже давно перекочевали фишки лиспа такие как: функция как первоклассный объект, итераторы, неопределенное (бесконечное) число аргументов функции, лямбды, сборка мусора, нетипизированные переменные, REPL. Есть возможность сделать eval к строке с кодом на питон или js, но вот выполнить какие-то глубоки преобразования кода, не просто, для этого нужны пакеты работы с AST. Больше встает вопрос а так ли часто это необходимо?

      Поэтому сейчас довольно трудно сравнить. Всё течет, всё меняется.


  1. Timka21213
    31.10.2018 17:59

    RLisp в Reduce 3.3 www.reduce-algebra.com язык моего диплома и кандидатской, вспоминаю с благодарностью: это было откровением свыше после написания собственных списочных процедур для операций над полиномами в символьном виде на языке Pascal! Уже не вспомню, как система попала ко мне на дискеты, но вместе с книгой Дэвенпорт «Компьютерная Алгебра» перевернула отношение к вычислениям вообще и символьным — в частности.