Как ворчун попробовал language server и приблизился к мечте лисп-программиста
A curmudgeon tries a language server

Автор, привыкший писать код «по старинке» — редактируя, компилируя и перезапуская программу, — завидует лисп-программистам, которые живут внутри работающего процесса и меняют код на лету. Он решает приблизиться к этому в Haskell, используя language server (hls), ghcid и библиотеку foreign-store. В статье он подробно описывает настройку Emacs, Eglot и Nix, а также делится опытом создания toy-проекта для визуализации дифференциальных уравнений, где при сохранении кода автоматически пересобирается и перезапускается программа с сохранением состояния. Получившийся рабочий процесс позволяет не покидать редактор, хотя и не достигает полной мощи Lisp REPL.
Мы никогда не покидаем наш редактор.
- dieggsy
Как разработчик на Common Lisp, вступление о Лиспе кажется мне в целом (?) правдивым. По моему опыту, мы действительно "компилируем и выполняем" код, просто можем делать это инкрементально и с меньшим переключением контекста из-за описанного рабочего процесса. Но довольно часто всё же есть отдельные шаги компиляции и запуска, просто не на уровне всей программы (например, скомпилировать функцию и запустить её или вызывающую функцию). И несмотря на то, как часто это преподносят как преимущество, переопределение кода во время реального выполнения не так уж распространено, я думаю. Да, иногда это делается, но многие программы в принципе не подходят под эту парадигму. Это может хорошо работать, например, для некоторых игр или долго работающих серверов. Что касается работы в образе без исходного кода: это кажется ужасной идеей. Можно делать так для тривиальных разовых экспериментов, но в целом полезно записывать и организовывать код заранее. Я даже не знаю особенно простого или чистого способа выгрузить исходный код из образа, как описано. Это можно сделать, но все способы, которые я могу придумать, звучат как боль или беспорядок. Может, это просто мой опыт, или я упускаю какую-то удобную фичу коммерческого Lisp или что-то в этом роде.
- cassepipe
Не совсем то же самое, но стоит упомянуть для C/C++ программистов: gdb на самом деле может работать как своего рода "дешёвая" живая среда для C и C++. Когда вы остановились на точке останова, вы можете вычислять C/C++ выражения, изменять состояние, вызывать функции и, с помощью compile code, заставить GDB компилировать и выполнять новый C/C++ код в контексте работающего процесса:
(gdb) set variable state->counter = 42
(gdb) call recompute_state(state)
(gdb) compile code
> printf("counter = %d\n", state->counter);
> do_something(state);
> end
Это даёт удивительно приятный опыт "REPL, прикреплённого к работающей C-программе". Вы можете ковыряться в куче, менять переменные, вызывать существующий код и вставлять небольшие кусочки нового кода без перезапуска процесса. Один случай использования, который я вспоминаю с теплотой, — реализация различных структур деревьев и добавление функции print_dot, которая выводила дерево в формате .dot, и когда я вызывал эту функцию из gdb, окно xdot перерисовывалось с обновлённым графом дерева. Я знаю, что это не совсем то же самое, что образ Lisp, где внедрённый код становится постоянным, но всё равно приятно иметь. P.S.: Если вы впервые пробуете tui gdb и ваша программа всё ещё завалена print-выражениями, вы можете очистить экран после вывода printf с помощью Ctrl+L или команды refresh.
- PaulHoule
Боже, этот подход к программированию, основанный на образах, никогда не был мейнстримом, потому что он создаёт ужасный беспорядок. Посмотрите на кошмарные ноутбуки, которые получаются у специалистов по данным, работающих на Python, когда они хотят, чтобы их ответы были запечены в ноутбук, который можно показать людям, и не осознают, что нужно разделять код и данные в системе контроля версий и иметь скрипт, который можно запускать сверху вниз каждый раз, если они хотят поставить свои навыки на колёса.
- ux266478
Честно говоря, учитывая степень структурного разрушения, которую вы получаете от GHC, разработка на основе образов звучит как очень плохая идея. Haskell — такой странный и неинтуитивный язык с системной точки зрения, потому что это почти как будто вы ограничены написанием макросов для языка, который вы никогда напрямую не видите и с которым не взаимодействуете. Трансформация от вашего исходного кода к тому, что выдаёт компилятор, может быть крайне нелокальной и непредсказуемой, даже до того, как вы начнёте вводить такие вещи, как пользовательские правила переписывания. По мне, умный способ работать с Haskell — это полная противоположность итеративности. Проработайте это на бумаге, отточите, найдите алгебраические правила для этого, отточите ещё немного, и только потом начинайте писать код, когда точно знаете, что делаете. Я думаю, что поддаться искушению "просто начать писать код" — это путь к непрозрачной типовой лапше. Это всего лишь мои ощущения.
- airza
Я узнал много интересных фактов о Haskell и Lisp из этого поста. Эти факты заставляют меня бежать с криками от попыток использовать любой из них для разработки ПО. Моё время с Haskell сделало меня лучшим программистом, и я готов поспорить, что LLM сделали часть документации более понятной, но...