LINUX.ORG.RU

Vim или Emacs? А LISP в 2021?

 , ,


1

3

https://www.youtube.com/watch?v=8Q9YjXgK38I&t=42s

Парень в определённых кругах, личность известная.
посмотрел я его ролик, стал ковыряться по истории:

А ведь Crashbandicoot была годной игрой…

Что выбрать? Vim или Emacs?
Изучать в 2021 году Lisp? Если изучать, какой? Практика?
А не засмеют сотрудики?

Времени в сутках маловато, на всё не хватает.


Ответ на: комментарий от anonymous

А ты хотел, чтобы всё выглядело, как хелловорлд? Посмотри исходники буста и поделись с нами своим ценным мнением.

Puzan ★★★★★ ()
Ответ на: комментарий от Puzan

А ты хотел, чтобы всё выглядело, как хелловорлд? Посмотри исходники буста и поделись с нами своим ценным мнением.

Зачем мне не с вами спорить?

anonymous ()
Ответ на: комментарий от anonymous

Ты меня с кем-то путаешь, я тебе не дружище.

Puzan ★★★★★ ()
Ответ на: комментарий от alysnix

а если ввести понятие именованный параметризованный список - все вроде еще читабельней становится.

Я уже писал, есть расширение.

Это тоже лисп:

defun area-circle (rad)
   format t "Radius: ~5f" rad
   format t "~%Area: ~10f" {3.141592 * rad * rad}
monk ★★★★★ ()
Ответ на: комментарий от monk

Это тоже лисп:

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

alysnix ()
Ответ на: комментарий от monk

Это локальный контекст. Динамические переменные позволяют установить значение глобальной переменной для куска кода. Самый близкий аналог (param как динамическая переменная)

Это максимум костыль, который только может быть. Прям как в фортране, коболе, и прочих теплых ламповых языках. Уже к 80-м годам от использования глобальных переменных в роли аргументов отказались, правда, почему-то создатели Emacs Lisp об этом не слышали.

byko3y ★★★ ()
Ответ на: комментарий от monk

Для восстановления соединения не обязательно перезапускать всю программу

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

Когда ты в ОС работаешь с Интернетом, ты делаешь снимок только своей ОС, а не всего Интернета. И если соединение с сайтом упало, не перезагружаешь всю ОС

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

byko3y ★★★ ()
Ответ на: комментарий от monk

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

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

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

byko3y ★★★ ()
Ответ на: комментарий от monk

Много DSL под лиспом знаешь? cl-sql, loop, … Они все единообразны и полностью интероперабельны с произвольным кодом на лиспе (то есть DSL можно воткнуть вместо любого выражения и выражениями внутри DSL может быть любое выражение лиспа)

Вот буквально на этой странице треда, выше и ниже твоего сообщения, человек не может жить без кастомных областей видимости, отличных от лексических замыканий. Статистики злоупотребления reader macros-ами у меня нет, тот же loop можно считать частью компилятора (которой он и является) и не рассказывать басни про «вот я бы мог переписать loop по другому, еще лучше» — потому что переписывание таких фундаментальных вещей уничтожает читаемость.

Это и убило лисп — индустрии не нужен твой DSL.

Убило не это, а AI Winter. И UNIX

И в 80-х AI Winter, и в 90-х? Такой AI WInter, что аж питон успел с нуля раскрутиться в этой нише на границе веков, а у лиспа ни в какую не получается даже на фоне огромного наследия.

А что такое cout << setprecision(4) << value;, если не Builder?

Разве «арифметический сдвиг» не возвращает тот же cout, который был его аргументом?

И огромное количество DSL в нём почему-то не убило Си++. Так что это контрпример к твоей теории

«Убило» в том плане, что опытные крестовики избегают буста. Безбустовые кресты спокойно себе поживают. Если ты посмотришь на популярность крестов, то когда-то они были топ 1, они полностью доминировали индустрию. Сейчас же индустрия при первой же возможности с крестов валит — проблема заключается только в том, что особо некуда валить. Если против лиспа есть питон, то против крестов есть только Си и Rust. По сути ведь кресты без буста и с минимумом STL — это и есть Си. А вот про лисп без макросов я пока что не слышал.

byko3y ★★★ ()
Ответ на: комментарий от monk

Вся реализация DSL - два файла: https://queue.acm.org/downloads/2011/racket/5-lang/txtadv-reader.rkt (148 строк) и https://queue.acm.org/downloads/2011/racket/5-lang/txtadv.rkt (343 строки)

regexp-match-peek, regexp-try-match — зачем мне лисп, когда то же можно сделать на перле?

Можешь попробовать написать аналог на питоне в 500 строк, чтобы получалась кодогенерация модуля питона

Могу, но не буду.

byko3y ★★★ ()
Ответ на: комментарий от no-such-file

В реальности там абстрактные фабрики фабрик поверх фасадов адаптеров билдеров и код размазан по 100500 файлов

Да, это фреймворковая лапша, и ей нужно не рулить, а выбрасывать ее в мусорку. Ну или если за деньги работаешь, то смириться и ковырять дальше.

byko3y ★★★ ()
Ответ на: комментарий от monk

классический майкрософтовский Hello-Windows

Какой-то дзенский Hello-World без надписи вообще. В Haskell хоть надпись есть и автоматически центрируется

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

byko3y ★★★ ()
Ответ на: комментарий от monk

Он убог. Нельзя идти по нескольким коллекциям, нельзя добавить условие на элементы. Это не loop, а map

Да, потому я и писал, что подход составления программы из элементарных функций заранее обречен на провал. Даже создатели CL это поняли и добавили loop. Да, его функциональность можно один в один повторить на функциях, но функция эта будет жирная и выглядеть уродливо — потому никто такого не пытается делать. Реально же на loop-е вся красота CL заканчивается, в то время, как в том же питоне есть list comprehension, которые позволяют записывать циклы еще лаконичнее.

byko3y ★★★ ()
Ответ на: комментарий от monk

Теоретически, да. А практически на порядок проще дёргать из IO

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

byko3y ★★★ ()
Ответ на: комментарий от ugoday

Бинарь ноды влезает в 15 Мб

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

Ты виндой 98 пользовался? Там блокнот (базовое офисное приложение, ага) не умеет открывать большие файлы в принципе. Большая часть ноды — это компилятор, в том числе WAsm, и отладочные инструменты. В те годы жиробас GCC весил 2+ МБ в пожатом состоянии и 5+ МБ в распакованном:
http://snapshot.debian.org/archive/debian-archive/20090802T004153Z/debian/dis...
Ну типа если из ноды «лишние» фичи повырезать, то тоже скромненький интерпретатор JS получится.

byko3y ★★★ ()
Ответ на: комментарий от Puzan

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

Понимаю. Костыльным говнокодом прежде всего является попытка реализации динамических биндингов — и это ты должен понимать. Как после тебя программист придет и будет твой код читать?

byko3y ★★★ ()
Ответ на: комментарий от Puzan

Ох ты ж еп! Кого-то еще пугают скобки в лиспе?

Уже который раз за тред одно и то же оправдание «а вот в крестах еще хуже». Да, в крестах еще хуже, потому индустрия массово мигрирует с крестов. Но индустрия на крестах не заканчивается.

byko3y ★★★ ()
Ответ на: комментарий от byko3y

Ты виндой 98 пользовался?

Я с неё начинал. И по большому счёту, всё, что нужно пользователю тогда уже было. А учитывая, что для многих сейчас ОС — это запускалка для браузера, подхачить хром для смеха, чтобы на страрой винде работал и хоть сейчас в бой.

ugoday ★★★★★ ()
Ответ на: комментарий от anonymous

но прошу заметить что практически любой лиспер предпочтет именно cl’овский loop циклу любого другого языка

«Любой гомик предпочтет долбиться в сраку» — такая себе логика. А питонист предпочтет list comprehension.

byko3y ★★★ ()
Ответ на: комментарий от byko3y

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

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

anonymous ()
Ответ на: комментарий от Puzan

Вот без макроса:

(foo `((var1 ,var1) (var2 ,var2) (var3 ,var3))

Вот с макросом:

(foo var1 var2 var3)

Видишь разницу?

То есть язычок такой убогий, что без макросов никак.

Psilocybe ()
Ответ на: комментарий от Psilocybe

Опа, у очередного блаба пригорело… Впрочем, ничего нового.

anonymous ()
Ответ на: комментарий от alysnix

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

Для длинных списков остаётся стандартный формат или формат с именем перед скобкой:

list
  list(1 2 3 4
    5 6 7 8 9)
  (list 1 2 3 4
    5 6 7 8 9)
monk ★★★★★ ()
Ответ на: комментарий от byko3y

А питонист предпочтет list comprehension.

Питонист предпочтёт писать

# [1,100] ... [10,110]
# 99 = 100-1, 11=10+1
[[i,i+99] for i in range(1,11)]

вместо

loop for i from 1 to 10
     for j from 100
     collect [i,j]

?

Или «предпочтёт» потому что у него выбора нет?

monk ★★★★★ ()
Ответ на: комментарий от byko3y

По сути ведь кресты без буста и с минимумом STL — это и есть Си.

Очень интересно послушать, как родилось такое умозаключение.

Siborgium ★★★ ()
Ответ на: комментарий от byko3y

Разве «арифметический сдвиг» не возвращает тот же cout, который был его аргументом?

Если брать определение операции, то не возвращает. Если брать его изнасилованную версию в iostream, то возвращает и получается обычный паттерн Строителя как раз потому, что «арифметический сдвиг» возвращает сам объект и, соответственно, предполагает его использование в цепочке вызовов.

monk ★★★★★ ()
Ответ на: комментарий от Siborgium

Этот аргумент работает в обе стороны.

Написать вместо loop что-то вроде (l* (list i (+ i 99)) for i in (range 1 11)) можно и в лиспе. И l* реализуется не слишком сложно. Но на фоне loop это ужасно неудобная конструкция.

monk ★★★★★ ()
Ответ на: комментарий от byko3y

Уже к 80-м годам от использования глобальных переменных в роли аргументов отказались

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

Аналогом является stdin, stdout, stderr и переменные окружения для процесса. Не вижу стремления от них отказаться.

monk ★★★★★ ()
Ответ на: комментарий от byko3y

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

Почему? Если у тебя скачивание файла может откатиться по таймауту, это запрещает механизм гибернации в ОС?

Использование снимков до наших дней дошло разве что в виртуальных машинах.

Гибернация работает без виртуальных машин.

потому делать снимок менее чем всей ОС не имеет смысла

Прикладные программы постоянно производят побочные эффекты с сетью. Делать снимок менее чем всего Интернета не имеет смысла?

monk ★★★★★ ()
Ответ на: комментарий от byko3y

потому индустрия массово мигрирует с крестов

Ага, на раст. Да что там раст, в твоём прекрасном питоне мусорного кода не меньше. Заканчивай уже за индустрию говорить, индустриализатор, ё-моё :D

Puzan ★★★★★ ()
Ответ на: комментарий от byko3y

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

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

Абсолютно все ЯП отказались от возобновляемых исключений

???

Common Lisp, Racket, … - уже два примера, которые не откзались.

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

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

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

И каким же образом. Например, если я пишу разборщик журнала на лиспе, я могу написать

(defun parse-log-entry (text)
  (if (well-formed-log-entry-p text)
    (make-instance 'log-entry ...)
    (restart-case (error 'malformed-log-entry-error :text text)
      (use-value (value) value)
      (reparse-entry (fixed-text) (parse-log-entry fixed-text)))))

То есть, если запись корректна, вернуть разбор. Иначе вызвать исключение malformed-log-entry-error с текстом записи и позволить обработчику заменить результат разбора (use-value) или заменить текст записи журнала (reparse-entry) для продолжения разбора. Как решишь при помощи невозобновляемого исключения? Вручную запишешь весь контекст парсера?

monk ★★★★★ ()
Последнее исправление: monk (всего исправлений: 1)
Ответ на: комментарий от byko3y

рассказывать басни про «вот я бы мог переписать loop по другому, еще лучше»

Таки переписали. Стандарт де-факто сейчас cl-iterate.

Такой AI WInter, что аж питон успел с нуля раскрутиться в этой нише на границе веков, а у лиспа ни в какую не получается даже на фоне огромного наследия.

Да. Мода жестока.

Если против лиспа есть питон, то против крестов есть только Си и Rust.

D, Zig, Odin, Felix, V

А вот про лисп без макросов я пока что не слышал.

Autolisp, picolisp

monk ★★★★★ ()
Ответ на: комментарий от monk

D

Допустим.

Zig

Нет. Конкурент он скорее сишке, даже с учетом функций над типами.

Odin

Нет. Сишка с альтернативным синтаксисом и дженериками.

Felix

Первый раз слышу. Компилируется в С++ – никакой заменой ему служить не может.

V

Серьезно? Он мог бы служить конкурентом Go, если бы не был Yandere Simulator’ом от мира ЯП.

Siborgium ★★★ ()
Последнее исправление: Siborgium (всего исправлений: 1)
Ответ на: комментарий от anonymous

именно cl’овский loop циклу любого другого языка

Поосторожнее с квантором всеобщности. Я предпочитаю Racket’овский for/list.

Ещё достаточно красиво получается на Haskell:

odd = (== 1) . (`rem` 2)

map (\(i,j) -> [i,j]) 
  . filter (odd . fst) 
  $ zip [1..10] [100..]
monk ★★★★★ ()
Последнее исправление: monk (всего исправлений: 2)
Ответ на: комментарий от Siborgium

Нет. Конкурент он скорее сишке, даже с учетом функций над типами.

Почему? Си++ выбирают из-за скорости и типизированных коллекций. Оба пункта в Zig есть.

Аналогично про Odin. Дженерики есть, значит использовать можно.

Компилируется в С++ – никакой заменой ему служить не может.

Первые версии C++ компилировались в C. Тем не менее могли служить ему заменой. Не говоря уж о том, что C++ компилируется в ассемблер и успешно служит ему заменой.

monk ★★★★★ ()
Ответ на: комментарий от monk

Такой AI WInter, что аж питон успел с нуля раскрутиться в этой нише на границе веков, а у лиспа ни в какую не получается даже на фоне огромного наследия.

Да. Мода жестока.

В оракле tnsnames.ora пишется в стиле лисп. В общем-то это уродство.

Psilocybe ()
Ответ на: комментарий от byko3y

ей нужно не рулить, а выбрасывать ее в мусорку

И брать ЛИСП, да.

no-such-file ★★★★★ ()
Ответ на: комментарий от Psilocybe

В оракле tnsnames.ora пишется в стиле лисп. В общем-то это уродство.

Как говорил Сомов из «Белое солнце пустыни»

Лучше конечно помучиться
anonymous ()
Ответ на: комментарий от byko3y

в том же питоне есть list comprehension, которые позволяют записывать циклы еще лаконичнее

Эта параша там есть только потому что там нет лямбд и поэтому в принципе очень геморно сделать «loop на функциях», а так-то тот же map/forEach намного лучше, хотя бы потому что универсальнее и можно пайпить map().map().map() вместо убожества [ for [ for[]]]. Я насмотрелся этих деятелей которые делают циклы на компрехеншенах 100500 вложенности на два экрана. Хочется просто взять и уе.

no-such-file ★★★★★ ()
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)