Как стать автором
Обновить

Комментарии 207

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

Скобки в Лисп ничем особым не отличаются от скобок в Си каком-нибудь или JavaScript. Почему-то никто не возражает против кучи закрывющих }) в каком-нибудь node-коде или кучи закрывающих тэгов в каком-нибудь xml. Наверное, потому что их пишут в разных строках?

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

В сях/js глубоко не закапываются и принято закрывающие скобки выносить на отдельную строку.
Глубина зависит от реализуемого алгоритма в процедуре. Глубоко «уйти вниз» довольно тяжело, потому что некуда уходить по структуре алгоритма. Можно же просто посмотреть реальный код на lisp и убедиться, что закрывающихся скобок там не так уж и много. Вот какой-то парсер: github.com/franzinc/xmlutils/blob/acl82/phtml.cl — здесь не более 6 закрывающихся скобок подряд.

Да, поленился погрепать, просто поскролил, ошибся. Там ещё в одном месте 7 есть. Но, ведь, всё равно, нет никакой бесконечной глубины вниз. Эти 10 скобок в какой-то особо эпичной по меркам Lisp процедуре. В Си бы это место закрвалось так: );}}}}. Ну, да, на 4 символа меньше. Но я бы одну скобку засчитал в пользу Lisp, потому что она закрывает блок labels с взаимно рекурсивными процедурами в локальной области видимости. Си и Go так не умеют. JS как бы умеет, но у него проблемы с областями видимости.


Впрочем, это всё не особо релевантно. Обычно в Lisp закрывающие скобки руками не пишут и внимания на них не обращают, в отличии от...

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

Приделать разметку пробелами, как в Python?

почему бы и да? я что-то никогда не видел многоскобочные однострочники в исходниках на лиспе, кроме как в сгенерированных s-выражениях, везде использовали то или иное форматирование кода

  1. Так редактировать код намного проще: если нужно взять выражение, то курсор устанавливается на открывающуюся скобку и копируется всё до соответсвующей закрывающейся. От редактора не требуется каких-то особых синтаксических возможностей. Плюс там есть ещё парочка фишек структурного редактирования, которые работают с s-выражениями. Вот, есть демо: http://danmidwood.com/content/2014/11/21/animated-paredit.html


  2. Так структура кода отчётливо видна. Не надо гадать, как всё сгруппировано, какие приоритеты операций и правила переноса выражений между строками. Это освобождает ресурс внимания, можно сосредотачиваться на другом.


  3. Это повышает культуру написания кода, на самом деле. Куча скобочек никому не нравится, поэтому люди стремятся писать простой по своей структуре код, пользуются абстрагированием, выносят общие выражения в процедуры. Сама структура кода становится более ясной и читаемой. Скобочки заставляют лучше продумывать код. И это хорошо.


Нет, на самом деле нет! Lisp — это не отдельная реализация, а ANSI-стандарт (теперь уже Common Lisp). Как и многие другие стандарты (например, ANSI-стандарт для языка программирования Си), он не содержит всего, что вам может понадобиться при написании приложений, например сокетов, синтаксических анализаторов XML, библиотек SQL и т. д.

Ну, вообще-то например Java или .Net содержат большую часть таких библиотек. А еще, если вам в мире Java вдруг потребуется парсер XML, вы с весьма высокой вероятностью найдете подходящий, и сможете его использовать без проблем в своем коде. Причем найдете вы его скорее всего прямо в maven central репозитории, так что подключение к проекту будет состоять из указания координат библиотеки в скрипте сборки.

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

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

Так что я вот такие фразы не понимаю. Есть куча других популярных языков, где все именно таким образом и обстоит. Бесплатно и сразу. И еще зачастую непростой выбор между несколькими хорошими решениями для одной задачи. Если лисп сообщество так не считает — разве кому-то от этого хуже, кроме самого сообщества?
У Lisp с этим сейчас тоже все хорошо — есть Quicklisp (https://www.quicklisp.org) — library manager for Common Lisp.
Ну тогда я просто не понимаю формулировки этого абзаца. Если репозиторий есть, и он общедоступен — нет никакой разницы, в ядре библиотека или в нем. Вот если его нет — это недостаток экосистемы языка. Иногда, как для C, такой недостаток по крайней мере объясним, но недостатком остается всегда.
Эссе было написано, по-видимому, ранее чем появился Quicklisp
Ну, я не вижу там каких-то признаков даты написания. Если автор правда так думал — я считаю, он в этом месте ошибался. Хорошая экосистема с богатым набором библиотек — это залог того, что пришедшие в проект на этом языке джуны не будут строить велосипеды, а возьмут готовый проверенный компонент, и будут решать задачу бизнеса, а не парсинга XML. А без прихода в проекты джунов никакой язык никогда не станет достаточно популярным.
Один из пойнтов автора как раз в том, что Лиспу не нужны программисты «ориентированные на экономию когнитивных ресурсов». «Гондору не нужен король, у нас республика» :) (с)
Ну да, ну да. Нужно не клепать код, решающий задачи бизнеса, а тратить когнитивные ресурсы на всякую интересную ерунду? Можно ведь и с такой стороны на это посмотреть :)

Честно говоря, меня смущает такой подход. Складывается впечатление, что это своего рода самоубеждение: мол проектов/библиотек/программистов меньше, чем у других языков, но нам это и не надо! В конце концов, раз такие статьи пишутся, значит авторов не всё устраивает. Но реклама получается специфическая.


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

Ну, а на самом деле, зачем? Пусть программистов и библиотек меньше. Главные же вопросы: можно на Lisp решить задачу или нельзя, насколько это можно сделать быстро, и насколько эффективным будет код. Опыт показывает, что решить можно, усилий это много не потребует (ну, потому что язык с базовой библиотекой действительно мощный), код будет достаточно быстрым. А мировое доминирование и огромная популярность — это что-то совсем перпендикулярное. Сообщесто Lisp достаточно развитое, чтобы даже писать свои браузеры, операционные системы и компиляторы. Что ещё нужно для пригодности инструмента?

Нужно не много но в хорошем качестве, например


  • Иметь возможность расширять команду, с этим у лиспа большие проблемы
  • Современная документация с примерами решения задач (начинал с PCL и обалдел от возможности сделать одно и то же 10 способами)
  • Набор хорошо поддерживаемых библиотек (в Lisp с этим есть определенные проблемы, как пример веб сервер с хорошей производительностью и набором фич — ssl\websockets\oauth и т.д. желательно без дополнительных приседаний)
    и т.д.
image

«Тебе не нужна большая команда, если ты — бог Lisp-а и можешь все написать сам» )
А мировое доминирование и огромная популярность — это что-то совсем перпендикулярное.

Ну если цель писать код самому, то ладно. В других случаях, не могу согласиться. Да, популярный язык/инструмент не обязательно хороший, но отсутствие популярности однозначно несёт с собой минусы.

Статья ссылается на Debian Woody, который вышел в 2002-ом и был актуален до 2006-го.

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

А я как раз не сомневаюсь. Если посмотреть на ряд популярных сегодня языков, то мы увидим, что почти каждый из них сопровождается солидным репозиторием компонентов, будь то maven central, npm, или там pip. Иногда исходники, иногда скомпилировано. Но всегда просто и стандартно. И чем выше популярность языка — тем как правило больше размеры этого репозитория.

Один из самых солидных репозиториев компонентов на любой вкус у хаскеля, и чё-то как-то на массовость не особо влияет.


На лиспе трудно (невозможно) писать не вникая, а индустрии надо именно это: вон го как хорошо пошел, именно из-за дубовости.

НЛО прилетело и опубликовало эту надпись здесь

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


Сравнивать надо с, например, julia. (Го не годится, потому что если бы не гугл, про него никто никогда бы всерьез не заговорил, js не годится, потому что монополия, и альтернатив нет, и так далее). Экосистема очень так себе, хаскелю во внучки годится, — но найти разработчика, по опыту судя, чуть ли не проще, чем на хаскеле.

Чисто опыт: в Haskell многое заброшено на половине. Автор удовлетворил своё влечение к монадам, и потерял интерес. Поэтому, вроде как, заявлено много всего, но для production подходит мало пакетов. Допиливать же их — отдельное удовольствие, потому что, конечно же, авторы выбирают особо изощрённые typelevel конструкции, которые ещё полгода изучать надо, чтобы понять, что к чему. Слишком тяжело. Поэтому оно всё в таком полусделанном состоянии. Есть набор центральных таких компонент, которые использованы в самом GHC и окружающих его утилитах, но и только. Если в GHC это не используется, то не повезло.


На Lisp-е легко фигачить, не приходя в сознание. Я вот писал или пишу на Си, Java, Go, Python, Haskell, Си++, JavaScript, Bash, Basic, Pascal, Delphi. Из этого всего Lisp — самый простой и мощный язык по моим ощущениям.

НЛО прилетело и опубликовало эту надпись здесь

С curl были проблемы, с DetFlow и ещё какой-то библиотекой для управления процессами (не помню названия).


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


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


На это говорят обычно, что вот мол лень тебе учиться, не хочешь освоить крутую штуку. Но вот лично мне надо изучать всякие распределённые системы, алгоритмы оптимизирующей компиляции и байесовские методы в машинном обучении. У меня просто на премудрости Haskell не остаётся сил. И что мне делать?


И я просто беру Lisp, который по ощущениям в 1000 раз проще, но позволяет писать в функциональной парадигме, которая весьма удобна для математики.


Тут мне скажут: надо просто нанять спеца в Haskell. Но у меня нет таких денег. Как на зло, спецы в Haskell стоят дорого, а я не банк.


Вот как-то так получается.

НЛО прилетело и опубликовало эту надпись здесь
(Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b вот, например, сигнатура, подобных которым довольно много встречается. И что делает такая функция? Нет, мы знаем, конечно, что это foldM, но такого рода функций понаписать можно бесконечное количество (можно через Йонеду посчитать). Плюс в зависимости от конкретных m и t поведение будет различное.

При этом, программисты на Haskell верят, что по типу можно понять семантику, и комментарии пишут редко (вот в Lisp такой установки нет, и комментариев там полно в коде). А печальнее всего то, что в итоге выясняется: такого рода абстрактная функция применяется только один раз, и только к одним конкретным экземплярам Monad и Foldable, и только тогда становится понятной идея автора. Для выяснения этого факта приходится несколько часов вызывать ошибки компиляции при помощи дырок, чтобы разобраться в коде. Несколько часов — это слишком долго для того, чтобы прочитать код и понять, что же он делает.

В Lisp с этим намного проще: можно в REPL на живой системе запустить функцию и посмотреть, от чего она работает и от чего падает. В Haskell, как бы, почти то же самое можно сделать, но если функцию кормить правильными типами, она будет выдавать нечто, и понять из этого нечто, чего же там на самом деле задумано, особенно, если монада какая экзотическая и самопальная (и не редко и не монада даже, а просто штука с >>=), ну, очень тяжело. Преждевременное абстрагирование — это не очень хорошо.

Может, дело в опыте, но я себя заставил решить кучу задач на Haskell в CodinGame и CodeWars, читал и разбирал чужие решения, не помогло.
При этом, программисты на Haskell верят, что по типу можно понять семантику, и комментарии пишут редко (вот в Lisp такой установки нет, и комментариев там полно в коде)

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


В Lisp с этим намного проще: можно в REPL на живой системе запустить функцию и посмотреть, от чего она работает и от чего падает.

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

И что? Будто в Haskell нет функций (мы не можем называть это функциями, давайте называть правильно: процедуры) процедур, которые влияют на глобальное состояние системы. Без этого программирование было бы невозможным и бессмысленным. Проблема в том, что у такой процедуры будет какая-нибудь абстрактная сигнатура, у которой будет абстрактная Monad m в ограничениях. И поди ж ты раскопай, что это на самом деле всегда что-нибудь про IO.

И почему все так боятся побочных эффектов? Да, нужны методы их контроля, и в Lisp они есть: можно исполнять функцию в её собственном окружении и наблюдать за изменениями в этом окружении. Но без побочных эффектов, ведь, не обойтись, особенно в системном программировании или в математическом моделировании с большими данными. Вы вот видели код на Haskell, который это делает? Там сплошное IO да IO погоняет, прямые доступы в память и все прочие прелести такого программировать (можно на benchmarks game посмотреть). А нормальных инструментов отладки, в отличии от экосистемы Lisp, в экосистеме Haskell нету, потому что всё это упрятано под IO, а IO для языка абстрактна и формально чиста. Но реальность не чистая, к счастью (не хотелось бы жить в абсолютно детерминированном мире одной функции).
НЛО прилетело и опубликовало эту надпись здесь
хоть одно IO?

$ git clone https://github.com/AccelerateHS
/accelerate
...
$ cd accelerate/
$ grep unsafePerformIO * -R | wc -l
48
$ grep indexByteArray * -R | wc -l
37

Accelerate — это красивый интерфейс для низкоуровневого интерпретатора accelerate-кода.
Максимум — условный unsafeIndex, который без рантайм-проверки границ. А почему? А потому, что система типов слишком слабая (а не слишком сильная), завтипов нет, и доказательство того, что доступ корректный, не то что произвести нельзя, а выразить нельзя.

В завтипах массивы с произвольным доступом по двоичным индексами не выражаются. Чем сильнее система типов, тем меньше свободы в структуре термов. Индуктивные конструкции — это, ведь, только деревья. Смоделировать массивы и двоичные значения можно, через Pos и Vector. Но это будут только модели. Как их компилировать в эффективный код, не понятно. HoTT до такого уровня переноса доказательств не развилась (да и разовьётся ли вообще? В кубических теориях существенные ограничения, а других для вычислимого автоматического переноса доказательств особо и нет).
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Оно будет одинаковым на уровне выше (точно так же, как поведение + одинаковое для всех чисел, хотя 1 + 2 и 3 + 4 немного различаются).

Это же не typelevel (затащить можно, конечно), а уровень термов и runtime. Но, допустим.

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

Но если мне скажут: вот тебе абелева группа, как я смогу понять, что это и о чём это? Это может быть что угодно, от многочленов до векторных пространств различной размерности и поведение вне групповой операции будет разное. Ну, да, я буду знать, что элементы можно свободно переставлять при операции, и где-то есть противоположные элементы, и для каких-то математических алгоритмов только это и важно. Но проблема в том, что только этих математических алгоритмов не достаточно. Данные из моей абстрактной группы должны быть связаны с реальностью, и результат вычислений может радикально отличаться по семантике (группа Z_5 или группа параллельных переносов рассказывают совсем разные истории). Без вписывания в некоторый глобальный контекст решаемой задачи абстрактный код не понять.

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

В Си++ та же самая проблема, на самом деле. Только не с sort, а с шаблонами. Она отчасти смягчается тем, что в Си++ культура другая: там не пытаются все идеи упаковать в минимальные интерфейсы, наоборот всё многословно и интерфейсы богатые. И, вроде как, по структуре этих интерфейсов можно примерно прикинуть, о чём идёт речь и как оно работает.

Олсо, ждём зависимые типы в хаскеле, чтобы можно было доказать, что ваша монада — монада.

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

Зависимые типы, как средство доказательства корректности, — не технология, учитывая те объёмы кода, которые требуются в production для решения задач, а просто любопытная математическая концепция. А на примере какой-то доказанной FS для Linux видно, что подход «докажем для ключевых кусков корректность, а для остального не важно», не работает. Ну, доказали они корректность FS в своей системе аксиом, а потом оказалось, что эта система не отражает реальную работу Linux, и чего делать?

А, ведь, есть ещё проблемы с параллельностью, где без сессионных типов и проверки моделей не обойтись. И что будем делать? Если у тебя нет суперкомпьютера и недель свободного времени, то ты и не можешь писать параллельные программы? Ну… Хорошая, конечно, концепция для защиты больших корпораций от особо активных disrupt-граждан…
НЛО прилетело и опубликовало эту надпись здесь
> Тестами тоже можно обложиться, а баги потом всё равно лезут, и лезут довольно много

Может тогда просто смириться с тем фактом, что баги будут всегда?
Ну если в то время было примерно тоже количество ошибок на примерно тотже объем функциональности, то может и правда стоит?
По крайней мере я часто слышу, что начиная с ...-ых годов ничего нового не изобрели (кроме завтипов, которые конкретно сейчас мы и обсуждаем)
НЛО прилетело и опубликовало эту надпись здесь
А документацию пишете до или после кода?
Тем более, что альтернатив-то нет. Тестами тоже можно обложиться, а баги потом всё равно лезут, и лезут довольно много. Верифицированному коду (особенно если он достаточно изолированный — например, блокчейн, а не модель ФС, работающая с моделью линухового ядра, где действительно можно сделать очень много ошибок хотя бы в построении этой самой модели ядра) доверия всегда больше, чем протестированному коду.


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

У NASA тоже есть парочка таких историй, например, о миссии Deep Space 1, в которой возникла ошибка как раз в верифицированном участке кода. Пришлось удалённо патчить систему.

Проблема в том, что код — это физический объект, а не математический. И соответствие чисто математической модели мира самому миру — это вопрос веры. Модель — всего лишь гипотеза, и говорить, что мы доверяем гипотезе без проверки в реальном мире только на том основании, что гипотеза написана на каком-то особом языке, не совсем научно.

Я, пожалуй, действительно, напишу обо всём этом отдельную статью.

P.S. Ну, а альтернатива есть. Так структурировать систему, чтобы можно было отдельно проверять поведение компонент максимально большим числом всевозможных способов. Есть же не только теория типов, есть и другие методы.
НЛО прилетело и опубликовало эту надпись здесь

SPARK Ada. Код проверяли и автоматически, и люди, он сработал по спецификации. Проблема была в самой спецификации, которая говорила: если возникнет переполнение целочисленных значений, отключай оборудование. Переполнение случилось из-за других параметров траектории, автопилот в соответствии со спецификацией и отключил. Все настолько верили в корректность кода, что не потрудились провести копеечное тестирование соответствующего модуля.


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

На лиспе трудно (невозможно) писать не вникая

Почему? Нет, я согласен, что в лиспе богатый набор языковых возможностей и есть где разгуляться. Но разве на нём нельзя писать как на условном питоне? Да, придётся освоиться с непривычным синтаксисом, но я бы не назвал это "вникать".


Я понимаю, когда вот такое говорят про С/С++: там невнимательность действительно приведёт к паданием, утечкам памяти и прочему UB.


Один из самых солидных репозиториев компонентов на любой вкус у хаскеля, и чё-то как-то на массовость не особо влияет.

Вероятно, это необходимый, но не достаточный критерий. Впрочем, я не сомневаюсь, что не будь у хаскеля библиотек, то популярность его была бы ещё меньше.
Ну и, кстати, по моему личному мнению "осилить" (на базовом уровне) лисп проще чем хаскель.

С репозиторием компонетнов в Haskell как раз все не очень хорошо. Разработчики так не особо заботятся о совместимости и получается что нужные тебе пакеты зависят от несовместимых версий третьего пакета. Кроме того слышал, что многие пакеты не тестируются и не работают в экзотических системах, типа windows, но искать где это проверить это лень, только с чужих слов знаю.
НЛО прилетело и опубликовало эту надпись здесь

Пользователям Lisp: какие реализации вы используете, какие рекомендуете? В частности, знакомы ли с Racket, и если да — что думаете о нём?

Нормальный язык. Проблема только в том, что Racket — это самостоятельный диалект Lisp, и код будет сложно переносить. А так, если не учитывать вопросы совместимости, довольно удобная и развитая система.
Я использую SBCL и очень доволен

Неплохой еще CCL (Closure Common Lisp), особенно под Mac OS X. Под x86 работает в среднем раза в 2 медленнее SBCL, но тоже вполне шустро. В SBCL есть одна неудобная вещь: нельзя на ходу увеличить heap и стеки, а я много экспериментирую с массивами по несколько гигабайт я тяжелой рекурсией, в результате чего регулярно проваливаешься в дебаггер или вообще вылетаешь. CCL выделяет себе память по мере надобности. Впрочем, гигантский растущий код может так и саму машину повесить. Пожалуй, это единственный плюс. В остальном SBCL лучше всего.

Пробовал ради интереса LispWorks и Allegro Lisp, но не заметил существенных особых достоинств. ECL производит крошечный бинарник и может использоваться как встроенный Лисп в программе на C, однако там глюков в изобилии, компилирует он на два порядка медленней SBCL, буквально в 50-100 раз, и там невозможно по-человечески отраживать код. Хотел, например, сравнить его скорость, а там (time) вообще без каких-то ухищрений не работает.

ABCL - глючный тормоз, требующий Джаву. Когда-то пользовался CMUCL, но это и был тот же SBCL. GCL- просто глюкалово. Впрочем, там и оговорено, что это не ANSI.

А вот Вы знаете, что в SBCL есть даже встроенный ассемблер? Там вообще очень много полезного, но плохо документированного (если вообще), помимо самой оболочки ANSI CL. Например, threads удобно оформлены в пакете sb-thread. Хотя при использовании получается уже не стандартный CL, но именно SBCL, к тому же не всегда портабельный.

https://pvk.ca/Blog/2014/03/15/sbcl-the-ultimate-assembly-code-breadboard/

Честно говоря, я ожидал и надеялся, что у вас будет некая статья по существу языка — например сравнение Лиспа с другими языками (скажем C/C++/Java/C#/...), раскрытие его киллер-фич, что-то такое крышесносящее и просветляющее, после прочтения чего только и хочется сказать «ВАУ!!!». Читаю в предвкушении такое длинное введение, и вдруг… статья заканчивается:(
Вообще лично у меня есть какой-то психологический барьер перед «чисто функциональными» языками типа Lisp и Haskell. Хотя функциональная парадигма, все эти лямбды и замыкания в гибридных языках общего назначения мне очень нравятся, но вот сами «чисто функциональные» языки по прежнему воспринимаю как нечто абстрактное с неким налетом таинственности, непостижимости и элитарности:) А целенаправленно изучать лень, да и нет каких-то реальных задач для этого.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
А есть ли какое-то вводное руководство по применению Пролога для написания трансляторов?
НЛО прилетело и опубликовало эту надпись здесь
О, и даже перевод есть! Спасибо!
Пролог слегка устарел (в частности там очень непродумана работа с констрейтами). На сколько я понимаю самое развитое решение в области логического программирования — библиотека core.logic в Clojure. В стиле ретро интересно посмотреть на язык LIFE, он более удачен, чем исходный Prolog, хоть и не столь известен.
Никогда раньше не слышал о LIFE и его сложно нагуглить. В чем особенности?
Практически весь материал здесь.
LIFE интересен термами с именованными атрибутами и возможностью унификации и поддержкой негативных констрейнтов в обычном прологовском синтаксисе (современные версии Prolog их тоже поддерживают, но синтаксис усложнен для совместимости).
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь

Есть генераторы парсеров, с помощью которых и так можно генерировать парсеры под любую платформу. К тому же грамматика любого более менее распространенного языка не совсем БНФ — там присутствуют семантические предикаты, а их уже сложнее описывать в рамках логического языка.

Можно пример не-БНФ-ности например в парсере Python? (Достаточно распространённый язык?)

В освновном это касается лексера. В Python не реализовать без предикатов работу с отступами и интерполяцию строк.

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Ух ты, какая вкусная ссылка!
Лисп и Хаскель вряд ли могут стоять рядом в таком контексте. Лисп (комон) такой же функциональный, как и современный JS, и позволяет писать вполне себе императивный код.
НЛО прилетело и опубликовало эту надпись здесь
Требуемая вами статья уже есть: lisper.ru/articles/common-lisp-technologies

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

Но на самом деле, когда вы говорите о «чисто функциональности» Лиспа, я понимаю, что вы еще не написали на лиспе даже Hello World — и немного завидую — у вас впереди может быть очень много увлекательного. Просто как-нибудь вечером откройте lisper.ru/pcl и если после первого раздела станет интересно — у вас в запасе появится совершенно новый способ думать о программировании
НЛО прилетело и опубликовало эту надпись здесь
Посмотрите главу 7 и 8 — там про макросы.

Потом главу 16 и 17 — иной взгляд на ООП

Но наиболее интресная — 19, после нее обычные исключения, гхм, сосут )
НЛО прилетело и опубликовало эту надпись здесь

Я бы не назвал лисп чисто функциональным. От хаскеля он вообще максимально далёк.

Иногда у меня возникает мысль, что у нас какая-то путаница с терминологией. Можно ли назвать хаскель не функциональным (что это вообще такое), а, к примеру, type-oriented языком?

Каждая новая парадигма пытается остроиться от прошлого этим методом:
— Структурное программирование — это хорошо, а все остальное — неструктурированные программы, в общем, мусор и хаос.
— Грамотное (literate programming) программирование — это хорошо, все остальное — неграмотное (отличная шутка, спасибо мистер Кнут :)
— Функциональное — то же самое, остальное — не функционально, звучит как «не работает»
НЛО прилетело и опубликовало эту надпись здесь
Лисп — не чисто функциональный язык. Функциональные гуру считают его нечистым.
НЛО прилетело и опубликовало эту надпись здесь
У вас просто не установлен плагин для редактора. С paredit (есть для Atom и Sublime), психологический барьер станет намного ниже.
НЛО прилетело и опубликовало эту надпись здесь

Может просто книжки хорошей не попадалось? Посмотрите "Структура и интерпретация компьютерных программ", буквально пары-тройки первых глав должно хватить.

Поддерживаю, но последнюю редакцию переписали на питоне.
Причины для этого хорошо описаны, и среди них нет ни одной хорошей.

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

То же название, те же авторы, легко спутать :) Так что я уточняю для людей, которые только открывают для себя «Книгу мага».

Разве? Авторы другие.

Виноват, не полностью прочитал историю перехода от классического курса Абельсона 6.001, где основная книга SICP, к курсу 6.0001 с основной книгой Guttag, «Introduction to Computation and Programming Using Python».
НЛО прилетело и опубликовало эту надпись здесь
Я неплохо знаком и с фортом и с лиспом, и мне думается, что вы ищите причину «не делать стартовое усилие». Простите, если ошибаюсь. Со своей стороны могу предложить начальную помощь — всегда хорошо, когда на старте есть у кого спросить. Я думаю, что человек, который понимает пролог и не понимает лисп — это нонсенс.
НЛО прилетело и опубликовало эту надпись здесь

А в чём проблема? Не понятно. Lisp — это процедурный язык. Можно писать в стиле Вирта. Да и функция вставки элемента в дерево, которая из прежнего дерева формирует новое, не выглядит особо сложной. Она отличаться будет от версии в стиле Вирта только тем, что вместо изменения узлов дерева будут формироваться новые узлы, содержащие указатели на поддеревья, из которых один будет указывать на изменённое поддерево с новым значением. В Prolog значения так же строятся, ведь.

На лиспе не писал, а Форт да, требует кучу примитивов предварительно загрузить в мозг, что сильно усложняет порог входа.
Фактически Форт и Пролог — для меня больше головоломки, чем языки на которых можно что-то писать.
Зато потом…

Я вообще не очень понимаю, как взрослый (вроде бы), вменяемый программист может уклоняться от изучения чего-либо нового — будь то язык, парадигма или технология. Это сюр какой-то…
Так что потом? Я на Форте писал вполне сложные программы лет в 15.
На Прологе — в университете.
В данный момент ни то ни то мне не надо.
Как упражнения для развития мозга — да, нормально. Как язык для разработки уже средних проектов — не подходит, ибо сложно потом в команду найти хоть помощника джедая, не говоря про второго джедая.

Форт процессоры? Ну за 15 лет ничего особо в этой области не произошло.

Взрослый программист имеет выбор, что изучать. Есть куча всего, что полезно для реальной работы.
В 7-ми миллиардном мире Forth-джедай не может найти себе падавана или второго джедая? Что-то слабо верится… Есть целые форумы, где фортеры ищут работу на форте. Впрочем, нужно спросить: «какой бюджет и какой проект?». А то я регулярно вижу, как на форте пишут GUI (где сложно продемонстрировать его преимущества), а на лиспе — очередную ERP (та же ситуация).

> Форт процессоры? Ну за 15 лет ничего особо в этой области не произошло.
Ну да, ну да… www.greenarraychips.com/home/products/index.html

> Есть куча всего, что полезно для реальной работы.
— Это например? В 2010-ом мне то же самое говорили про кучу вещей, например PHP и Smarty — и где теперь это все? А Common Lisp, Forth, Smalltalk, Prolog — живут и до сих пор вдохновляют программистов, новые проекты и решения в составе старых проектов. Потому что «хорошую идею нельзя убить» (с)
Найти, конечно, можно кого угодно. Но всегда надо сравнивать, к примеру, с усилиями на поиск инженера знающего тот же Питон на таком же уровне.

Ну сравните количество выпущенных форт-машин с другими микроконтролерами. А так то на современной базе можно и АДА-машину вместе со встроенным компилятором сделать. Не удивлюсь, если такая есть.
smarty ну уж точно не мертвее проектов на Форте.
Если уж так подумать, то стоит еще сравнить с усилиями на удержания фортера и питоняшки. Что-то мне подсказывает, что даже с точки зрения бизнеса «совокупная стоимость владения» будет неоднозначна.

Мне не нужно количество выпущенных микроконтроллеров. Мне нужно выбрать камень под задачу. Фортовый камень заруливает всех — посмотрите характеристики под те задачи, под которые он сделан

Это как в плюсах фигурная резьба по массивам, мешанина операторов или там математика указателей. Иногда надо, но в реальной жизни всё это оборачивается во всякие for-each, смартпойнтеры и т.п. И не выплывает. Так же и в Лиспе — очень часто вы не вызываете руками сами себя, а даёте эту работу fold'ам, map'ам и прочему стандартному синт. сахару, программа выглядит вполне понятным списком задач рантайму.


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

НЛО прилетело и опубликовало эту надпись здесь
Лисп вам понравится. Эквивалентные программы на других языках получаются в 5-20 раз многословнее
НЛО прилетело и опубликовало эту надпись здесь
Лисп очень мощный в задачах «написать прототип, переделать, написать следующий, превратить его во встроенный язык предметной области для целевой задачи и решить задачу на нем».

Могу предполжить, что если бы я был вами, то я бы написал надстройку над лиспом с элементами Ады, если есть многопоточность и Пролога — и это все еще оставался бы лисп. Ну а если надо вызвать числодробилку, и нужна большая производительность чем дает компилятор SBCL, то можно вызвать сишный код через FFI.

Это реально швейцарский нож, со способностью трансформации под задачу. Больше не надо выбирать язык под проект, в процессе работы над проектом язык станет таким, как нужно.
НЛО прилетело и опубликовало эту надпись здесь

Мне приходится заниматься примерно тем же. Lisp со всем этим справляется. Мне нравится, потому что теперь мне достаточно Lisp и Си для разнообразных задач, не нужно забивать голову другими языками, можно забивать её математикой и алгоритмами. Для Lisp есть, кстати, prolog-библиотеки.

Люди же часто возвращают объекты, чтобы возвращать объекты, и никого это не смущает. Функции похожи на простые объекты в некотором смысле: структура с окружением (значениями переменных) и указатель на код, который можно вызывать с дополнительными аргументами (считайте метод call). Весьма удобно, потому что часто объектов с одним методом хватает для реализации алгоритмов, а дополнительный код с описанием классов и конструкторов писать не нужно

НЛО прилетело и опубликовало эту надпись здесь
Аналогично. Воспринимается как латынь. Сильно уважаю, но писать предпочитаю на чем-то другом.
НЛО прилетело и опубликовало эту надпись здесь
Одно из достоинств Lisp и Scheme в том, что это языки, для которых есть множество реализаций от разных групп разработчиков и компаний. Если одни накосячат, можно перейти к другим. Сколько подобных языков сейчас? Я знаю только Си. Даже независимых реализаций плюсов осталось не так уж и много, хотя язык архиважный для индустрии. Поддерживать же форк самостоятельно во многих случаях теоретически возможно, но практически не реально — слишком велики трудозатраты.
НЛО прилетело и опубликовало эту надпись здесь
>Я в Java не шарю, но есть же как минимум опенсорсная и от Оракла.
Их намного больше. Но далеко не все они совместимы с последними OpenJDK и оракловыми версиями.
Сколько подобных языков сейчас? Я знаю только Си.

JavaScript (V8, SpiderMonkey, Chakra, и куча менее популярных)

С Лиспом всё так. Вот только ему нечего предложить в современном мире по сравнению с другими языками. Он уже давно не "элегантное супероружие джедая". Многие языки впитали из него достаточное количество свойств. А те что остались, либо не сильно нужны, либо и вовсе вредны. А та же гомоиконность оказалась переоценённой.

>А те что остались, либо не сильно нужны, либо и вовсе вредны.
Да это в общем-то уже и не важно. Для массовости не нужно, чтобы язык был идеален. У него скорее не доолжно быть особо слабых сторон, хотя и такое бывает (особенно если учитывать, что не все свойства разные люди оценивают одинаково — потребности ведь тоже разные).
Скорее нужно, чтобы язык делал хоть что-то ощутимее лучше других.
Ну, давайте попробуем найти такое у популярных… javascript?

Не очень удачный пример, т.к. он во многом "взлетел" тупо из-за отсутствия альтернативы в своей изначальной нише (в браузере).

Это контр пример. Я специально такой выбрал :)

>чтобы язык делал хоть что-то ощутимее лучше других
Ну т.е. да, наверное — но при наличии этих других как минимум.
Работает в любом браузере и этого достаточно. Свойство не языка, конечно, а реализации, но уж такое, что ничем не перебьешь.
Я бы так не сказал. В индустрию еще не впитались макросы, condition-restarts / сигнальный протокол, метаобьектного протокола тоже не завезли, так что элегантному супероружию джедая есть что предложить

Из перечисленного только макросы интересны и они (или другие инструменты кодогенерации) появились в других языках (макросы в Rust, Sweet.js/Babel в JS, и, простите, Lombok в Java).


Рестарты это сомнительная вещь сама по себе. Она запутывает поток выполнения и не известно как будет работать и будет ли вообще в многопоточных приложениях.


MOP переоценён. В любом динамическом языке (Python, Ruby, JS) это вообще не проблема. А в статических обходятся рефлексией и кодогенерацией, если нужно.


Можно ещё было бы вспомнить экзотику вроде комбинаторов методов. Но не будем :)

К предыдущему комментарию только добавлю макросы в Scala и Elixir. В последнем они довольно широко используются. Только я не уверен, что за пределами языка с S-expressions макросы это хорошая идея.
Макросы есть например в D. Пишутся на нем же. Понятно, что это не совсем такие же макросы — но те кто ими пользуется, ими довольны. Осталось реально сравнить.

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

Ну т.е. преимущества у лиспа есть — но видимо таки не решающие.
Я могу только своими ощущениями поделиться тут, т.к. пробовали в лиспе их (кложура) и в эликсире, эрланге и совсем немного в скале — в лиспе макросы это легко и приятно, потому так часто ими пользуются. В других языках сразу как-то становится несколько трудно и начинает требовать дополнительных ментальных усилий. Я связываю это исключительно с синтаксисом — S-expressions идеально подходят для такого стиля, а вот остальные языки — не очень.
>начинает требовать дополнительных ментальных усилий
Ну вообще это естественно — вы же работаете на другом уровне, с другими сущностями.

Ну и насколько я читал (а я только читал), в D синтаксис именно что одинаковый — т.е. я к этому и клоню, что макросы можно сделать в общем-то в любом синтаксисе. Можно сделать в том же, что основной язык, можно в другом. Если синтаксис одинаковый — такие макросы будут лучше.
Я бы сказал, что в Common Lisp эти преимущества хорошо скомпонованы в довольно стройную картину и дополняют друг друга — все же язык долго совершенствовался и притирался за всю свою более чем полувековую историю. Может быть именно это стройность — и есть существенное преимущство
Это преимущество. Если язык согласован, содержит немного базовых конценпций, они друг с другом работают вместе — конечно это преимущество. Решающее ли — ну это вопрос такой. Как минимум — для кого как.
Оно становится преимуществом только когда все концепции поняты. Пока поняты по кускам — преимущества нет
Если язык согласован

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

Не так уж плохо в итоге получилось — может быть отчасти потому что над стандартом работало много умных людей. Я вот уже лет 10 не могу найти ничего лучше
А кто оценивал гомоиконность?

Я могу привести те фичи, которые не перенял ни один язык полностью (хотя тут речь больше про реализации и культуру разработки):

  • REPL Driven Development. Сам подход разработки через REPL используется ограниченно (это либо полное написание программы в REPL или когда ты по мере написания кода в редакторе посылаешь куски кода в REPL, который работает на фоне и видишь сразу же результат вычисления). Из мейнстрима наверное ближайший к такому подходу Ruby, из немейнстрима языки семейства ML (SML, Ocaml, Haskell)
  • Хотрелоад. Можно изменять код по мере его работы через REPL, не перезапуская ни разу программу полностью. Erlang любят за подобный функционал, но он очень далёк от удобства того, что дают лиспы (могу ошибаться, с Erlang очень поверхностно знаком).
  • Компиляция в бинарник с рантайм системой и дебаггером. Когда какая-нибудь Java требует установки рантайма в системе, чтобы запускать программы на Java, программы на Common Lisp, собранные при помощи SBCL, дают эту рантайм систему в конечном бинаре. Из минусов всё это дело весит достаточно много и поставляется каждый раз, из плюсов смотреть предыдущий пункт.
  • Макросы даже сейчас далеко не в каждом языке есть. Если они есть, то зачастую весьма ограниченные.
  • Агностицизм стиля программирования. Вытекает из предыдущего пункта с макросами, так как язык можно расширять как вздумается. Потенциально лисп может быть приспособлен к любой парадигме без значительных сложностей. На данный момент можно писать императивно как в си (можно хоть вставки на ассемблере использовать), функционально как в каком-нибудь Haskell и в объектно-ориентированном стиле как в какой-нибудь Java. Сейчас популярно «каждый язык для своей задачи», который силён в чем-то одном, лиспы же помогают выражать свои мысли вне зависимости от задачи, хотя это не освобождает от учёта специфики используемой реализации
  • Рестарты. В CL есть система рестартов, которая позволяет в рантайме исправить возникающую ошибку. По неизвестной мне причине в мейнстримовых языках такого нет.


Если рассматривать язык в отрыве от реализаций и культуры разработки, то в лиспах как в наборе из текста действительно ничего примечательного нет, а скобки могут только затруднять чтение кода. Другие языки в основном впитали именно языковые особенности, а не особенности реализаций и культуры.
REPL Driven Development.
Erlang/Elixir. Но это подход из далеких 80-х и Смолтолка вполне вытеснился «пишу тест, запускаю тест». REPL DD это архаика.

Хотрелоад.
даже в Erlang, если вы не пишете для железки, никто практически этим не пользуется. Эра кубернетеса и контейнеров делает это все ненужным. Работаю с Эрлангом последние 7 лет если что.

Макросы даже сейчас далеко не в каждом языке есть.
макросы это один из видов решения конкретной проблемы. Не единственная. Макросы за пределами Лиспа очень трудны в освоении и очень сомнительная фича.
НЛО прилетело и опубликовало эту надпись здесь

Перенимать всё же стоит полезные и уместные фичи.


  • REPL Driven Development выбивается из современной практики ведения истории кода в VCS. Дампы состояния интерпретатора (ну или лисп-машины) на роль версий не подходят никак. А уж про коллективную разработку и речи нет.
  • Хотрелоад есть много где. Erlang, JRebel для Java, Spring gem в Ruby on Rails, Webpack dev server для JS-а.
  • Компиляция в бинарник с рантаймом? Это скорее похоже на выдачу единственного что лиспы умеют за преимущество. А вот нормального tree shaking не завезли. Но если уж так хочется всё запаковать, то тот же докер-контейнер с любым интерпретатором вполне на эту роль подойдёт.
  • Про макросы я уже написал выше, там где они нужны, они есть (Rust, Scala), а в динамических языках и без них обходятся. Даже в Clojure макросы хоть и есть, их используют крайне редко.
  • Разные парадигмы в одном языке. Разве этим хоть кого-то можно удивить? Все более-менее популярные языки такие. Если же взять избитый лисперами пример про Prolog внутри лиспа, то вот пожалуйста — http://minikanren.org/ реализации на любой вкус.
  • Про рестарты тоже уже написал выше. Они необычные, но вот полезные ли? То что они делают достигается простой передачей замыкания.
— Какие проблемы выгрузить из REPL то что было нафигачено в образе и положить это под VCS? И как насчет практики парного (или больше чем парного) одновременного программирования в нескольких реплах, одновременно общаясь по аудиосвязи и находясь в разных концах мира? Современная практика в сравнении с этим выглядит более ограниченной.
— Нигде ктоме Common Lisp хот-релоад не реализован на основе _любого_ куска кода — везде надо выгружать помодульно и тщательно следить за состоянием. В CL это просто прозрачно и очень удобно
— Видел много реализаций tree shaking и даже несложно написать свою. Впрочем, сам пока не делал, может есть грабли.
— У нас разные мнения относительно макросов, не будем спорить
— Рестарты очень полезные — они увеличивают выразительность и упрощают понимание кода.
>Какие проблемы выгрузить из REPL то что было нафигачено в образе и положить это под VCS?
Никаких. Если вы откроете один из моих постов, вы увидите там Scala REPL в виде Spark Shell. Ну т.е. тут все просто — REPL давно не только в лиспе.

>Нигде ктоме Common Lisp хот-релоад не реализован на основе _любого_ куска кода — везде надо выгружать помодульно и тщательно следить за состоянием.
Ну мы это обсуждали вроде. Это хорошо — но это же потенциально и опасно. Зарелоадив произвольный кусок кода произвольным образом можно не только сделать хорошо, но и сломать тоже неплохо. Поэтому если у этого средства нет хотя бы Undo — оно рисковано для прома.

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

Такого REPL как в лиспе я нигде не видел, даже Clojure в этом плане на шаг позади. Больше всего кайфовал на отладке багов где без потери стейта системы можно поменять функцию (добавить отладку и т.п.) и заново прогнать вызов и тут же поправить

Это в Java тоже можно. Ограничений больше — это да. Ну т.е. вы не можете менять сигнатуры методов класса — в принципе, очевидно почему (потому что найти всех, кто зависит от ваших методов, может быть весьма и весьма дорого).

В этом вся соль в Lisp можно менять что угодно до\после\вместо функции
В жабке это прибито гвоздями, ну и будем честны REPL в массы в Java не пошел
БОльшинство команд, с которыми мне приходилось общаться, предпочитают классику — пошаговую отладку в Idea

Тем не менее — вы можете поменять класс, перекомпилировать и перезагрузить его в работающую JVM, и в общем-то этого достаточно в большинстве реальных случаев. Ну т.е. скажем так — личный опыт мне подсказывает, что поменять сигнатуру класса иногда хочется — но это единицы процентов случаев в моей практике. Жить без этого можно. А hot reload есть.

И потерять весь стейт и это без учета всяких Spring boot'ов и других фреймворков которые накладывают свои ограничения на этот процесс
В мире Java ближе всего к CL REPL подошел Clojure но и тот недотягивает

>И потерять весь стейт и это без учета всяких Spring boot'ов и других фреймворков которые накладывают свои ограничения на этот процесс
Ну, это очень хороший вопрос, на него боюсь нет простого ответа. Ну вот смотрите, забъем на spring boot, аннотации, и т.п. магию, которая там есть.

Возьмем простой старый спринг, с xml конфигами для контекстов. Чисто для простоты. Вот вы перезагрузили этот конфиг. Понятно, что все дерево контекста нужно будет перестроить, вообще говоря. Каждый объект при инициализации может что-то сделать, например, загрузить в память некие ресурсы, или скажем установить соединение с базой данных, и даже достать оттуда что-нибудь. Ну или из сети что-то запросить. Так вот, проблема при работе со спрингом из отладчика в том, что я могу перекомпилировать класс, но я не могу вот эти вот все вещи, которые были сделаны при старте приложения, просто так из отладчика повторить. А если могу — это де-факто эквивалентно рестарту приложения, и этот рестарт будет безопаснее.

Вот вы когда из лиспового REPL что-то делаете — вы уверены, что ваши изменения вот это вот все учитывают, а не просто работают потому, что в лиспе этих сложностей просто нет? Ну так, чисто условный пример — у вас есть приложение, оно работает. У него заполнен данными какой-то кеш. И вы решили из REPL поменять структуру той сущности, что лежит в кеше. В итоге, то что там уже лежало, осталось старой структуры. А новое стало иметь новую. Вопрос — кто это изменение учтет? В случае Java в кеше скорее всего лежал бы экземпляр класса. И при попытке поменять его сигнатуру, т.е. добавить поля, скажем, мне бы дали по рукам. И мне отчего-то совсем не кажется, что такое поведение неразумное.
Боже, какой геморрой, я просто ставлю курсор за скобкой, нажимаю комбинацию клавиш — и у меня все окей, код обновился, со стейтом тоже все прекрасно… В языке все это уже давно учтено и работает без всякого ручного вмешательства — как магия
Извините, но не верю. Стейт может происходить откуда угодно. Из сети, из базы и так далее. Лисп про это ничего не знает, и этот стейт обновить не может. Поэтому, в некоторых случаях внесения изменений в коде нужно проделать некоторую работу, о которой знает только сам этот код. Т.е. перезагрузить стейт, или наоборот, очистить, как кеш. Никакой магии тут нет — но язык тут не при чем, действия требуются от приложения, и могут быть сделаны только приложением.
Рекомендую попробовать на какой-то задаче. Я ни разу не встречался с ситуацией, когда горячая замена кода требовала каких-то телодвижений — рантайм все разруливает сам
Я повторю вопрос — рантайм разруливает запросы к базе данных? Кейс же вполне описан — расскажите, как рантайм разрулит то, что ваш кеш после горячей замены кода стал неконсистентным? Откуда он вообще узнает, что это нужно сделать? В случае спринга и java большое число случаев, когда нужен рестарт, а не горячая замена кода, связаны именно с такими случаями — горячая замена приводит к тому, что внешние ресурсы нужно обновить тоже. Рантайм про внешние ресурсы ничего не знает, про их структуру и API тоже.
Рантайм может разруливать только то что контролирует — внешня база данных к этому не относится. Я говорил про стейт внутри образа
Ну, видимо тут недопонимание в процессе возникло. Я говорил, что тот стейт, который в случае спринга JVM не может перезагрузить сама — он в основном (по моему опыту) относится к стейту внешнему. Т.е. его в принципе нельзя перезагрузить.

В какой-то степени — еще к тому, что у нас статически типизированный язык — т.е. если вы поменяли тип — то что делать с тем кодом, который ожидает старого типа? Он ведь может и не скомпилироваться.

Не давать менять код из отладки таким способом — это в общем-то и есть текущее решение принятое в JVM.
> т.е. если вы поменяли тип — то что делать с тем кодом, который ожидает старого типа?

он будет автоматически перекомпилирован в момент следующего обращения (в CL)
Почему вы думаете, что он скомпилируется? Ну т.е., очевидный вариант — если вы позволяете вносить любые изменения — значит можно удалять что-то, что использовалось. И?
Я так уже делал — и никаких проблем не замечал.

У меня наоборот есть вопросы к Java — допустим, у меня есть класс, и на работающей системе есть сотня объектов этого класса.

Если я добавлю в класс поле или пару методов — что мешает Java обновить объекты этого класса при следующем обращении к ним?
>Я так уже делал — и никаких проблем не замечал.
Надо как-то конкретнее. У вас был метод в классе, вы его выкинули. Он использовался где-то (как рантайм найдет те места, где он использовался — это отдельная история, но неважно). Но каким образом предлагается автоматически обновить те места, где он использовался?
Я сам нахожу те места, где он использовался (для этого есть специальный вызов в интроспекции). После этого удаляю их, нажимаю Ctrl+E (evaluate), а затем удаляю метод, нажимаю Ctrl+E (evaluate) — и все. Объекты будут изменены когда к ним произойдет следующее обращение
Вообще-то рантайм в случае JVM не содержит компилятора. И это естественно, потому что а) JVM не имеет дело с исходниками вообще, и б) это многоязыковая среда, хотя и определенными ограничениями (в виде отсутствия ТСО например).

Ну т.е. тут технически рантайм просто не может сам ничего перекомпилировать. Все сценарии hot reload выглядят примерно так — есть исходники где-то в другом месте, мы подключаемся отладчиком, перекомпилируем кусок кода (тут у нас в наличии компилятор с нужного языка или языков), и подсовываем JVM через механизм отладки новую версию байткода.

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

Поэтому все эти плюшки лиспа — это конечно хорошо, но я могу не вставая с места вообразить еще несколько сценариев, когда у меня бы такое было невозможно.
Понимаю и немного сочувствую
Это совершенно лишнее :) Я верю, что на лиспе пишут крупные и сложные приложения — то все-таки ни одного приложения масштаба скажем спарка на нем не написали, почему-то. Ну т.е. у этого подхода видимо тоже есть свои преимущества. Например, возможность писать на двух или трех языках — это точно оно.
Там вроде в британии железные дороги работают на лиспе, но я точно не помню. Не знаю сопоставимо ли это со спарком, но если между делом, то как лиспер, не могу понять зачем кому-то могли бы понадобиться еще языки, если есть лисп :)
Ну это сложно сравнивать, в этом и есть в общем-то основная проблема — одно приложение и другое приложение, два совершенно разных приложения. Я даже функциональность приложения для железных дорог не могу себе представить вот так с ходу.
Можно зайти еще с одной стороны. Можно ли на лиспе написать СУБД? Спарк в каком-то смысле можно считать аналогом (хотя это и не СУБД в точном смысле этого слова, но скажем SQL движок там есть, включая оптимизатор запросов). Можно ли на лиспе написать СУБД? Можно — на кложе как минимум уже писали. Ну а дальше начинаются очевидные непонятки, потому что хотя и то и другое вроде как СУБД, но функциональность все равно сильно разная.
Даже в SICP мимоходом пишут кое-какую учебную СУБД
Не, ну я думаю разница между учебной СУБД и реальным ораклом — огромного масштаба. Даже парсер настоящего PL/SQL это штука далеко не тривиальная, если вдуматься, не говоря уже о том, что там же еще и его рантайм внутри имеется.
Что мешает писать на лиспе программы большего масштаба? Например Genera — операционная система полностью написанная на лиспе
Я не могу правильно оценить масштаб, но на первый взгляд, современная СУБД и ОС — это примерно один масштаб, плюс-минус ерунда. Там есть планировщик задач, там есть управление ресурсами, причем и то и другое — весьма навороченное. Ну разве что GUI в СУБД вообще нет. И с устройствами попроще, не нужны драйвера как класс, скорее всего.

Так что возможность наверное все-таки есть. И Datomic в общем совсем не игрушка. Причем есть ведь еще и такая интересная фиговина.

Действительно если у нас нетривиальное обновление\изменение\инвалидация кэша в зависимости от окружения\запросов и т.д. то заново загрузить его под новую структуру\класс в Lisp мы не сможем. Тут у нас с вами паритет


Но если посмотреть на подходы к разработке в Java и CL они в корне отличаются


На Java бОльшая часть разработки опирается на помощь Idea, автокомплит, типы и т.д. Т.е я не запускаю приложение из раза в раз, потому что это достаточно медленно


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

Ну так а с этим в общем никто не спорит. Я так же в скале делаю, как вы описываете. Единственное что потом нужно сделать — это проделанные изменения как-то зафиксировать.

Ну и я собственно пытался привлечь внимание к тому, что не всегда можно так легко «перезагрузить» код в работающем приложении. Это я еще Spark не упоминал, где это по факту вообще невозможно — и вовсе не потому, что JVM не позволяет.

А как вы расхождение типов фиксите? С лиспом понятно он динамический, а вот с java и scala не понятно

Из REPL? Так по сути ограничения JVM на изменение кода — они как раз и вызваны тем, чтобы не меняли типы. Ну, я упрощаю, причем возможно сильно, но в целом оно близко к такой постановке.

Поэтому в Java REPL это такой "огрызок" (без него жили вполне успешно) — снипеты позапускать, однострочники проверить. Разработку через REPL никто не ведет


В Lisp наоборот вся разработка через REPL, загрузил образ, стейт и погнали

Ну на самом деле скаловский REPL вполне годный. И груви тоже.
Мне показалось или в этой статье Lisp можно заменить на любой другой малоизвестный язык, потому что о нем самом практически ничего не говорится?
Сравнения, рассуждения, мнения, аналогии, умозаключения. Ничего про сам Lisp. По крайней мере для меня это было, мягко говоря «неожиданно».

Задавая себе после прочтения вопрос «Какие новые знания о предмете я почерпнул из статьи», я с сожалением отвечаю сам себе: «никаких». А казалось бы, какой шанс! У тебя есть статья, в которой ты, своими руками, можешь немножко повлиять на популярность языка, рассказав о нем что-нибудь интересное. Но нет.
//если что, это камень в огород автора, но и переводить такую статью с сомнительной полезной нагрузкой, кажется неоднозначным решением.
Спасибо, следующая статья учтет эти пожелания
По личным воспоминаниям пятнадцатилетней давности, «не так» там начиналось с дикой, невероятной фрагментации платформы: если с C++ никакого выбора делать было не надо (под Линуксом gcc, под Виндой пиратишь Visual Studio), а Питон вообще один, то с Лиспом еще до старта начинаются муки выбора (а тем более если ты полный нуб, только-только обчитавшийся Пола Грэма, и снизошло на тебя, и решил приобщиться). ANSI-стандарт, конечно, стандарт, но вот есть такая имплементация, она такая, а вот есть эдакая имплементация, она другая. Десятки имплементаций, и ни одной нормальной. Вот, говорят, хорошая — ее, правда, никто не видел, она стоит дикие сотни денег. Из отдельного заповедника слышны советы языковых пуристов: «Фу-фу-фу, Common Lisp, почему же не Scheme???» Ну и далее, когда ты закончил писать числа Фибоначчи и прочих «обедающих философов» и хочешь уже приспособить язык к чему-то хоть отдаленно практическому, во весь рост встает проблема библиотек: вроде бы, тоже тьмы их, но вот как назло именно того, что тебе нужно, как раз и нет — или есть, но под используемую тобой имплементацию Лиспа хрен ты их поставишь. И я как бы не ожидаю, что мне сразу будет сухо и комфортно программировать на чуждом языке, а потратить «когнитивный ресурс» на освоение языка даже в кайф — но на освоение именно языка, а не очередной глючной и недоделанной системы сборки библиотек под чего-то.
Эти проблемы я немного застал в 2010. Сейчас все уже гораздо более сухо и комфортно
С какой книги стоит начать, если интересно разобраться с лиспом (если в багаже есть c, python, ruby, java)? Насколько имеет смысл смотреть на github.com/kanaka/mal?
Обычно рекоменуют lisper.ru/pcl в качестве первого, mal я еще не смотрел, но чую что завтра начну
Спасибо! Как посмотрите напишите, пожалуйста, что думаете о mal.
У меня есть некоторая мысль, что mal надо смотреть, когда уже есть некоторый (хотя бы базовый опыт) с лиспом, и интересно как самому сделать язык похожий на лисп. Т.е. это как раз мой вариант :) Но расскажу, как пройду весь туториал. Я как раз искал способ применить sixtel или брайль и создание игрушечного лисп-отладчика выглядит интересно в контексте реализации лиспа
Если будет минутка можно попросить вас прокомментировать еще вот этот проект:
github.com/carld/micro-lisp
Записал, посмотрю. Но может занять время
Была прекрасная книга финских авторов Хювяйнена и Сеппяйнена 1990 года «Мир Лиспа».
Lisp — бесконечный источник вдохновения для людей, решивших объяснить миллионам программистов, почему эти миллионы из десятилетия в десятилетие ошибаются и не хотят для своих продуктов (а не для любования списком академических фич) выбирать такой прекрасный язык, но продолжают кушать кактус и даже в удобные для Lisp времена предпочитают то PL/1, то BASIC, то Ada, то COBOL, то Fortran, то Forth, но только не Lisp. ^_^
Из современных диалектов Лиспа есть смысл смотреть в сторону Closure. Он живой и даже новые большие проекты регулярно запускаются. Правда, найти работу в России не получится :)

Скорее Clojure

Если вы про Clojure, то прямо сейчас можно открыть популярный сайн вакансий и найти несколько. А ещё есть группы в телеграмме там часто публикуют.
Хотя на мой взгляд главное не язык а проект и ЗП. Ну а если получится найти отличный проект на Clojure — это вообще замечательно.

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


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

К «самому непереносимому языку в мире»? Ещё как относится! Вам мало того, что придётся писать отсутствующие библиотеки, так ещё и адаптировать их под веер реализаций Scheme.


Когда Если выйдет R8RS (aka Scheme Big), то может семейство Scheme и станет лучше для промышленного программирования. Но R6RS внёс такой раздор в сообществе Scheme, что это маловерятно. У Scheme, похоже, получилось «избежать успеха любой ценой».


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

А когда этот стандарт выйдет?

Я думаю, надо смотреть каждый пункт в отдельности
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории