Часто приходится видеть, как новички пробуют Common Lisp и потом жалуются, что с ним невозможно нормально работать. Как правило, это происходит из-за того, что они не понимают как настроить себе процесс, обеспечивающий тот самый "быстрый отклик" от среды разработки, когда ты поменял функцию, скомпилировал её и изменения тут же начали использоваться внутри уже "бегущей" прогрммы без её перезапуска.
Понять, как это выглядит, можно посмотрев какой-нибудь ролик на youtube, где демонстрируется интерактивная разработка на Common Lisp.
Сегодня я хочу показать, как настроить себе dev окружение для такой разработки. В 2018 году это стало совсем просто, благодаря постоянно улучшающемуся тулингу.
Заранее прошу прощения за то, что следующие ролики записаны в Asciinema, а Habrahabr его не поддерживает. Кликайте на скриншоты консоли, чтобы посмотреть ролики.
Для начала, надо установить SBCL, Roswell и Emacs. Рассказывать я буду на примере установки всего в OSX, и буду рад если в комментариях вы поделитесь своим опытом на Windows и Linux. Тогда я смогу дополнить статью примерами для всех трех платформ.
SBCL это одна из многочисленных реализаций Common Lisp. Из опенсорсных?-?самая быстрая. При желании, на SBCL можно запускать код по скорости сопоставимый с кодом на C++, но при этом имея все плюшки от быстрой интерактивной разработки.
Roswell, это утилита, для установки и запуска Common Lisp программ. В том числе она умеет запускать преднастроенный Emacs, а так же собирать программы в бинарники.
Emacs вы наверняка знаете?-?такая операционная система, в которой есть и редактор кода. Можно писать на Common Lisp и в любом другом редакторе, но на сегодняшний день у Emacs лучшая интеграция и поддержка смантического редактирования кода. С ним вам не придётся считать скобочки, он всё делает за вас.
Итак, если вы используете OSX, то нужно сделать
brew install roswell emacs
После того, как brew пошуршит диском и поставит всё нужное, просто запустите в терминале:
ros run
Эта команда автоматически поставит вам последнюю версию SBCL и стартует Lisp repl, куда можно вводить код:
Но это не дело, разрабатываться так нелья. Поэтому давайте настроим Emacs для полноценной разработки:
ros emacs
Команда запустит Emacs в консоли и настроит Quicklisp?—?пакетный менеджер для Common Lisp.
Но прежде чем мы продолжим, давайте настроим терминал, emacs и OSX так, чтобы они хорошо работали вместе.
Сначала надо в OSX и iTerm поменять некоторые настройки
Делаем так, чтобы CapsLock работал как Control. В Emacs без этого?—?никуда:
Затем отключить в шоткатах MissionControl все комбинации, связанные с использованием Control и стрелок:
Затем поставить iTerm2 и переключить в настройках профиля поведение Alt с Normal на Esc+:
После чего, создать файлик с минимальным конфигом для Emacs, ~/.emacs.d/init.el
:
(package-initialize)
(require 'package)
(add-to-list 'package-archives
'("MELPA" . "http://melpa.milkbox.net/packages/") t)
(defun install-package (package)
(unless (package-installed-p package)
(package-refresh-contents)
(package-install package)))
(install-package 'paredit)
(install-package 'expand-region)
(defun setup-lisp-mode ()
(require 'paredit)
(paredit-mode)
(define-key paredit-mode-map (kbd "C-w") 'paredit-backward-kill-word))
(add-hook 'lisp-mode-hook
'setup-lisp-mode)
(add-hook 'emacs-lisp-mode-hook
'setup-lisp-mode)
;; используем C-w для удаления слова с опечаткой и последующего набора его заново
;; вместо kill-region
(global-set-key (kbd "C-w") 'backward-kill-word)
;; вместо кучи команд начинающихся с kmacro-
(global-set-key (kbd "C-x C-k") 'kill-region)
;; вместо indent-new-comment-line
(global-set-key (kbd "M-j")
(lambda ()
(interactive)
(join-line -1)))
;; поиск и замена
(global-set-key (kbd "C-c r s") 'replace-string)
(global-set-key (kbd "C-c r r") 'replace-regexp)
;; по этому сочетанию emacs начинает выделять формы
;; и дальше можно просто нажимать =, чтобы расширить
;; выделение на родительскую форму.
(global-set-key (kbd "C-c =") 'er/expand-region)
;; это сочетание удобно использовать с предыдущим,
;; чтобы быстро выделить и закомментировать кусок кода
(global-set-key (kbd "C-c c") 'comment-or-uncomment-region)
(global-set-key (kbd "C-c C-\\") 'goto-last-change)
(setq custom-file "~/.emacs.d/customizations.el")
(when (file-exists-p custom-file)
(load custom-file))
После чего, снова запускаем ros emacs, жмём Alt-X
и вводим команду slime
. В результате получаем командную строку для ввода лисповых команд:
Теперь можно уже кодить
Но мы не будем вводить команды в репл, лучше сразу приступим к разработки микросервиса. Если нужно только API, то проще всего использовать Ningle. Если нужен более продвинутый фреймворк, типа джанги, то можно попробовать Radiance или Caveman2. Но сейчас не будем делать ничего сложного, а замутим простую HTTP апишечку.
Откройте в Emacs файл server.lisp
(C-x C-f server.lisp
) и начинайте писать код. Примерно так:
В итоге, у вас внутри инстанса окажется запущен вебсервер, в который на ходу можно добавлять роуты и переопределять вьюхи.
Вот весь код, для ленивых:
;; Micro-framework for building API
(ql:quickload :ningle)
;; Now ningle is installed and we need to install a clack which is analog of WSGI
;; stack from Python
;; I've pressed C-c C-c to eval this form
(ql:quickload :clack)
;; To parse json:
(ql:quickload :jonathan)
(defvar *app* (make-instance 'ningle:<app>))
(setf (ningle:route *app* "/")
;; in case, if you need to parse or serialize JSON,
;; use Jonthan library.
(jonathan:to-json '(:foo 100500)))
(defvar *server* nil
"This variable will store currently running server instance.")
(defun start ()
(if *server*
(format t "Server already started")
(setf *server*
(clack:clackup *app*))))
(defun stop ()
(if *server*
(clack:stop *server*)
(format t "Server is not running")))
В Лиспе конструкции, которые внутри скобочек, называются “формами”. Формы, которые на верхнем и не вложены ни в какие другие, называются top-level. Такие формы можно компилировать нажав сочетание C-c C-c
, когда курсор находится внутри такой формы. Если вы перебиндили CapsLock
на Сontrol
, то это сочетание очень удобно нажимать.
После того, как форма скомпилирована новая версия функции сразу же вступает в силу и перезапуск сервера не требуется. Так очень удобно отлаживаться и фиксить баги. Кроме того, можно настроить автоматический прогон тестов сразу после компиляции части кода, но это уже совсем другая история.
Если вам интересны ещё какие-то темы, пишите в комментариях, постараюсь сделать посты и про них.
VioletGiraffe
У меня другой вопрос: зачем писать на LISP, и что писать на LISP? Для чего этот язык хорош, кроме как развлечься и попытаться сломать процедурные парадигмы в своём мышлении?
andreysmind
Этих причин разве недостаточно?
GeekberryFinn
На F# или Erlang тоже можно ломать процедурные парадигмы в своём мышлении, а за них ещё и платят деньги.
Потому хотелось бы аргументов почему лучше выбрать именно LISP, а не F# или Erlang?
PS функционально развлечься можно и на Logo и на unLambda.
AlexTheLost
Гомоиконичности в приведенных вами языках нет, как минимум:)
domix32
Чтобы написать лисп в лисп, чтобы можно было исполнять лисп, пока пишешь на лисп. Случайно написав плагин для Emacs
evgajukov
Вот тоже хотел задать этот вопрос. Есть ли реальные задачи, которые на этом языке быстрее и проще решаются или это просто академическая игрушка…
anatoly62
Обычные прикладные задачи, особенно, если заказчик не до конца представляет что хочет.
У меня на CL написано что-то типа 1С. И CL — это не функциональный а мультипарадигмальный язык программирования.
GeekberryFinn
AutoCAD содержит LISP, но для его изучения лучше поставить сам AutoCAD.
PerlPower
Хоть я и многолетний пользователь емакса, регулярно что-то пишущий по мелочи на лиспе, я так и не понял преимущества этого языка перед типовым мейнстримным языком типа питона. И в свое время я пытался понять чего же я в упор не замечаю в лиспе, но те примеры что приводили его фанаты, все равно не позволяли понять что в нем такого особенного что можно было бы взять для ежедневной работы. Пока для себя решил, что фанаты лиспа ничем принципиально не отличаются от фанатов другого языка — выбранный язык хорошо ложится на их предпочтения.
Лисп в емаксе удобен для сложных хозяйственных вычислений, где нужно подгонять параметры чтобы уложиться в сумму или размер, и при этом чтобы можно было кажду строчку сопровождать комментариями.
bormotov
на вопрос «что писать на лисп?» ответ простой — всё.
А вот «зачем?» — да, вопрос.
Хорошо язык тем, что сам язык — суть AST, всё остальное сделано на нём самом же (ну, почти). Когда начинаешь «дмать на лисп», сначала обретаешь ясное понимание, как всё вокруг работает, и далее, если интересно — никаких ограничений.
Ломать парадигмы в голове, на мой вкус лучше хаскелем (и потом на хаскеле тоже можно писать всё). По крайней мере, после сотен тысяч строк кода, что мне довелось читать за свою жизнь, очень хочется, что бы авторы были не ближе к машине, а ближе к сути прикладной задачи.
babylon
Если бы сделали Lisp в нотации JSON я стал бы первым кто стал бы на нём программировать. А пока…
bormotov
что такое «в нотации json»? Фигурные скобочки вместо круглых? Идентификаторы в кавычках?
Кажется, что написать интерпретатор лиспа в любой нотации — это такой проект-на-выходные. Не удивлюсь, если внезапный 'npm install js-notated-lisp' вытащит пакет и установит. Хотя это скорее троллейбус из буханки хлеба…
babylon
[] это список, {} это множество. Добавьте туда функции и будет, то что надо. Куда двигаться показал JSONNET. Вы можете использовать JSONPath like запросы. Код будет компактнее чем в лиспе. Допустим, вы знаете как работает траверсер. Вы таким образом составляете запросы, чтобы получить искомый результат, не переделывая сам код, а просто расставляя данные или импортируя нужные функции извне если вам надо расширить фунционал.
Так только кажется. Игрушечный интепретатор можно написать, согласен. Но не более.
bormotov
Кому-то нужен неигрушечный лисп в нотации json?
Мне кажется, кому сейчас нужен современный клевый лисп — все на closure перешли.
masai
Почти так устроен, например, Wolfram Language. Квадратные скобки в нём — это список. Причем для того, чтобы не пугать людей, первый элемент списка пишется перед первой квадратной скобкой. И получается почти привычное
f[x]
вместо[f, x]
. Люди пользуются и не подозревают, что пишут практически на Лиспе. :)Фигурные скобки тоже есть, но это синтаксический сахар для списка, у которого первый элемент — слово
List
. Это что-то вроде пометки, что список содержит данные. Да и вообще, в Wolfram Language практически все — это сахар над списками.babylon
Здесь фигурные скобки выполняют роль разделителя контекста и замыкают объект.
TheDeadOne
Пока программисты на других языках решают задачу в рамках установленных их языком правил, программисты на LISP пишут DSL, чьи правила подходят для решения задачи наилучшим образом. © Нил Форд
slonopotamus
… в результате у программистов на других языках задача решена, а программисты на LISP только закончили делать DSL?
Svetlyak Автор
В результате у программистов на других языках лапшекод, который надо будет через год полностью переписать, а у программистов на Lisp лаконично сформулированная бизнеслогика, которую легко читать и поддерживать.
TheDeadOne
LISP тем и хорош, что написание DSL на нём — это относительно простой и быстрый процесс. Можно справиться ещё до того, как java-программист закончит набирать SimpleBeanFactoryAwareAspectInstanceFactory.
bormotov
Языки, на которых легко писать DSL, есть еще, это не только лисп.
Наермиер, в рамках питона можно соорудить DSL поиск по «python dsl» вываливает кучу статей и даже видео. В той же группе, скажем и ruby.
Из этого направления выпадает java, и может еще какие-то…
true-grue
К сожалению, частые разговоры о DSL в Лисп-кругах мало подкрепляется реальными делами. Да, DSL написать можно, но в реальности пишут нечто маловразумительное на уровне все тех же многочисленных скобок. Собственно, с языком Форт подобная ситуация. Декларируется метапрограммирование и создание DSL, но реальных практических примеров подобного очень немного. На мой взгляд, тому в Лиспе есть две причины: 1) слабая существующая поддержка построения внутренних DSL, 2) необходимость для обычного разработчика быть по совместительству еще и неплохим архитектором языков.
Конечно же Лисп имеет смысл применять там, где не хватает готовых решений из традиционных ЯП. Но лично меня удивляет такое внимание именно к неуклюжему Common Lisp. Почему не более изящный Scheme? Добавьте его интерпретатор к тому инструментальному средству, которое востребовано в вашем рабочем проекте (на C/C++, C#, Java или ином «скучном» языке), и у вас будет вполне достойное компромиссное решение.
Svetlyak Автор
Раз уж мы тут про DSL говорим, то при чём тут скобки?
Вот тебе пример из одной библиотеки которую я некоторое время назад написал. Она упрощает парсинг опций командной строки и большую часть работы делает за тебя. Прикладной код выглядит так:
Всё, что ты видишь до строчки
Making real work
, это DSL для описания функции, принимающей параметры командной строки. Под капотом оно разворачивается в такой вот код:Тут видно, как задаются возможные аргументы, какие у них могут быть флаги и короткие названия, как запускается парсинг аргументов и их значения присваиваются переменным внутри функции.
Абстракция defmain, написанная один раз, сама задаёт разумные дефолты и избавляет меня от написания или копирования всего этого бойлерплейта в каждой программе.
Такой вот DSL. Реальный.
true-grue
Скобки здесь при том, что это синтаксический рудимент Лиспа, который просочился в нотацию нашего DSL. Спасибо за пример. Заранее прошу не принимать мою критику в штыки. Заслуживает уважения уже то, что Вы выбрали Лисп в качестве инструмента разработки.
В коде обращает внимание использование известного макро loop, которое является частью стандарта CL. Это действительно специализированная конструкция со своим особым синтаксисом. А вот макро defmain вполне заурядно. На обычном языке, который поддерживает замыкания, можно было бы сделать аналогичный комбинатор, который развернется в нечто подобное тому, что Вы привели.
А примером языка, поддерживающего конструирование DSL, является Rebol с его диалектами.
Svetlyak Автор
При этом скобочность лиспа позволяет не писать поддержку каждого нового DSL в редакторе. Всё работает «из коробки». И манипуляции с кодом серьёзно упрощаются. Так что я бы не считал это рудиментом. Просто особенность к которой быстро привыкаешь.
nemavasi
По своему опыту скажу что хватает недели регулярного кодирования на лиспе чтобы привыкнуть к скобкам и воспринимать их естественно. При этом форматирование кода сильнее всего напоминает, как ни странно, Python.
roman_kashitsyn
Скобки — это не рудимент, это преимущество лиспа. Поначалу они действительно кажутся неудобными, но стоит лишь перестроиться и начать думать "сбалансированными выражениями" вместо символов и строк, работать с кодом становится гораздо удобнее, и современные плагины для работы с Lisp (paredit, lispy) сильно помогают. Они превращают редактор текста в редактор синтаксического дерева программы. Вот небольшое демо с демонстрацией базовых возможностей paredit.
После работы с Lisp начинаешь думать по-другому и в других языках: я в основном пишу на C++ в Emacs, и работа со "сбалансированными выражениями" прочно засела в моём workflow.
anatoly62
Проект в императивном стиле, интерпретатор в функциональном. Зачем такое жесткое разграничения парадигм. К тому же СL и как императивному языку есть что сказать.
Если уж хочется Java+Scheme, то есть Сlojure.
true-grue
На мой взгляд, разграничение вполне логичное и оно проходит не в области парадигм, а в области архитектуры приложения. Нижнему уровню в большинстве случаев и полагается быть императивным. Собственно, примеров, когда интерпретатор Лиспа встроен в большую программную систему для расширения возможностей последней — масса. Даже в старых компьютерных играх такое вполне практиковалось, можно вспомнить древний Zork, где использовался далект Лиспа под названием MDL или более позднюю Abuse. Я уже не говорю про Autocad, Cakewalk и проч.
С другой стороны, сейчас для встраивания в приложения существуют Tcl, Python, Lua и многие-многие другие. Поэтому, кстати говоря, я призываю к критической, объективной оценке того, где действительно целесообразно применять Лисп. Ниже привожу несколько возможных вариантов.
1. Универсальное текстовое представление вычислений и данных для обмена между программными модулями. Здесь фигурирует, вообще говоря, не совсем Лисп, а его существенный элемент под названием S-выражения. В каких-то случаях S-выражения могут быть предназначены и для редактирования пользователями. Например, можно реализовать синтаксис ассемблера для какой-то экзотической архитектуры в форме Лисп-подобной нотации. В большинстве случаев ассемблерный код будет порожден компилятором, но можно учесть и вариант, когда на Лисп-подобном ассемблере придется писать человеку.
2. Миниатюрный диалоговый язык для удаленного управления скромным по ресурсам микроконтроллером. Существуют Лисп-подобные реализации, которые выгоднее использовать в таких условиях, чем даже Lua.
3. Средство для метапрограммирования и программных трансформаций. Тот, достаточно редкий, случай, когда важнейшим свойством Лиспа программа=данные действительно необходимо воспользоваться. Например, если требуется какая-то совершенно экзотическая программная конструкция, поддержки которой еще нет ни у Google, ни у Microsoft. «Нам совершенно необходим встроенный движок для программирования в ограничениях!» Здесь, однако, нужно серьезно поразмыслить, а нужно ли все это городить именно в рамках Лиспа.
Как можно видеть, использование Common Lisp не слишком-то увязывается с описанными выше пунктами. К CL у работодателя могут возникнуть резонные вопросы на тему того, кто будет поддерживать систему после Вас, стоит ли в целом овчинка выделки. В этом смысле показательны примеры игровой компании Naughty Dog и Пола Грэма с Yahoo. Другое дело, что если просто _нравится_ писать на CL, да и условия позволяют — почему бы и нет :)
anatoly62
Во всех моих проектах в качестве нижнего уровня использовался мультипарадигмальный язык. А в качестве встроенного интерпретатора язык на который знают или легко способны выучить большинство программистов. Получилось так Rust+Lua, Scala+(Lua и JavaScript). В случаи с СL он и нижний и верхний уровень.
BelBES
Lisp нужен для того, чтобы писать на нем конфиги к Emacs)
roman_kashitsyn
Common Lisp – очень неплохо спроектированный язык. Да, в стандарте есть несколько моментов, которые сейчас не особо актуальны, но в целом язык очень интересный. Честно говоря, я с трудом переношу языки с динамической типизацией (Python и JavaScript снятся мне в кошмарах), но на CL я бы с удовольствием попробовал написать проект.
Для CL есть качественные компиляторы, в языке есть возможность указать типы, если хочется (да, аналог gradual typing был давным давно). Код, который генерит, к примеру, SBCL, на удивление быстр (я сабмитил решения для computer language benchmark game, мой код для SBCL иногда работает ощутимо шустрее, чем мой код для Haskell, оба решения были в топе).
Slime + Emacs – это приятная и мощная среда разработки, в которую вложено много человеко-лет труда. Её действительно иногда нетривиально настроить (нужно разобраться в терминологии, ASDF, системы, вот это всё). К примеру, компиляция совершенно не мешает разработке, ведь можно инкрементально компилировать код по одной функции за раз. При этом можно попросить компилятор показать ассемблерный код любой функции и посмотреть, как добавление аннотаций типов влияет на код, производимый компилятором.
Ну и если в проекте нужна генерация кода, CL тут просто вне конкуренции.
Единственное, что я бы не стал писать на CL – мелкие утилиты командной строки. Модель исполнения с тяжёлым долго-живущим образом не особо к этому располагает.
К слову, у языка довольно много активных пользователей. Например, бэкэнд ITA (ныне Google Flights) в значительной степени написан на CL.
PerlPower
А компиляторы лиспа по настоящему компилируют или там в экзешнике байткод и виртуальная машина?
Sirikid
Есть разные варианты.
3aicheg
Когда-то, на заре развития сайта StackOverflov, я задавал там подобный вопрос. Несмотря на то, что я сам не очень понимал, что именно спрашиваю, топовый ответ там, имхо, очень крут.
Svetlyak Автор
Да, ответ отличный. Спасибо за ссылку!
Femistoklov
Хотя бы, потому что это Лисп!
lixmix
Менеджеры пакетов работают по https или подписывают библиотеки? Пробовал изучить липс. Что бы запустить сервер, требовалось скачать либу. Насторожило что все качалось по http
Svetlyak Автор
Проверил. Да, по HTTP. Но ведь если параноить, то надо параноить по полной – вычитывать весь код всех своих opensource зависимостей и их зависимостей, и зависимостей их зависимостей.
Кстати, opensource хорош тем, что его можно исправлять. Пока завёл issue про https: github.com/quicklisp/quicklisp-client/issues/167
Arqwer
Про паранойю неверная логика. Всегда есть шанс что вас убьёт молния, но это же не повод не мыть руки перед едой. Пересылать программы по http не вредно до первого роутерного ботнета. Или открытого вайфая. А раз уж http стоит по умолчанию, то это очень очевидная уязвимость которую вирусописателям возможно даже выгодно эксплуатировать.
lixmix
Я замечал подмены пакетов дебиан, но они не ставились из-за неверной подписи
AlexTheLost
У Common LISP есть какие либо преимущества перед Clojure? Или хотя бы то чего не в Clojure, может кто рассказать?
TheDeadOne
Это очень холиварный вопрос :) Первое, что приходит мне в голову — SBCL может компилировать программы в исполняемые файлы и у него есть настоящая оптимизация хвостовой рекурсии.
anatoly62
CL — мультипарадигмальный язык, CLojure — функциональный. В СL есть CLOS система объектно-ориентированного программирования. В CL есть макросы чтения. Скомпилированная программа на CL загружается мгновенно. в отличии от программы на Clojure.
AlexTheLost
В Clojure есть ООП, за счёт полной совместимости с Java. Хотя я не представляю зачем это может понадобиться кроме обратной совместимости.
Макросы чтения в Clojure тоже есть если я правильно разобрался что это означает — можно экранировать выражение используя ` и оно не вычислиться.
Это особенности платформы JVM, на Node.js ClojureScript так же мгновенно запускается.
anatoly62
Нет, в Clojure нет полноценного ООП. Нет, Вы не разобрались с макросами чтения. Нет, это не только оcособенности платформы JVM но и особенности реализации самого Clojure. Напишите helloworld на Java и на Clojure и увидите разницу при загрузке.
igrishaev
Вы все не то пишете, в Кложе нет ООП, только мульти-методы и протоколы, которые близки к идее "пусть объект знает, как сделать это". Напротив, в CL реализована мощная система полноценного ООП, CLOS (commo Lisp object system). Про макросы тоже неверно.
ivan4th
Java-style OOP с CLOS сравнивать как-то даже не смешно. Не, понятно, на ООП в принципе свет клином не сошёлся, но в некоторых случаях мощная система ООП очень даже не мешает.
ivan4th
Мой взгляд на использование Common Lisp — как человека, который использовал его в продакшне, например, для управления промышленными ускорителями электронов.
В каких случаях вам НЕ надо писать на Common Lisp:
В каких случаях вам надо использовать Common Lisp:
Понимаю, что это означает не слишком обширную применимость Common Lisp'а. Я, например, по работе сейчас в основном пишу на Go, и пишу довольно много. Но при всём при этом ни Go, ни Python, C# и C++ перед этим, в отличие от CL, так и не стали для меня языками, на которых мне было бы удобно думать.
AlexTheLost
Все проблемы с библиотеками решены в Clojure.
ivan4th
За что приходится платить, например, отсутствием CLOS / MOP, зависимостью от JVM и тд. К тому же в принципе без дополнительных обёрток использование нелисповских библиотек в лиспах обычно приводит к довольно… хм… своеобразному коду. Мало иметь возможность использовать библиотеку, надо, чтобы она сочеталась с конструкциями языка. Так-то в CL можно тоже библиотеки для C легко использовать, а в Сlasp, например, и C++. В принципе, срач разводить на эту тему не хочется, но у меня как-то Clojure не зашёл. Хотя, наверное, если JVM для вас комфортен, Clojure в каких-то случаях может быть и лучше.
anatoly62
Я лет 5 использовал Clojure в продакшен. Но сейчас использую Scala или CL и по возможности, перевожу написанное на эти языки.
AlexTheLost
Scala, мне не понятно чем он так хорош, на мой взгляд только геморой. То что можно написать на Clojure быстро и хорошо на скала потребует кучу времени и плясок с типами. Это из опыта в продакшене а не домашних хелоуворлдов.
По CL, не могу говорить т.к. его не знаю могу опираться только на clojure, те особенности что вы перечислили я для себя не могу отнести к преимуществам. Интеграция с JVM для меня огромный плюс, думаю это обьективно, есть сомнения что доступность библиотек и базовых возможностей необходимых для современной разработки хоть немного близка — поддержка многопоточной среды, средства отладки и мониторинга. Хотя может вам это не нужно. Но я не представяю как возможны современные серверные приложения без этого.
anatoly62
Вступать в религиозную дискуссию динамическая типизация против статической я не буду.
Попробуйте «быстро и хорошо» написать на Clojure приложение для Android. На Scala я пишу клиентские приложения, которые без изменения кода работают на рабочем столе, в браузере и на мобильном устройстве. Серверные приложения спокойно пишу и на Scala и на СL и на Rust. У каждого из этих мультипарадигмальных языков есть свои прелести. Интеграция с JVM иногда плюс иногда минус, зависит от задач.