LINUX.ORG.RU

Vim или Emacs? А LISP в 2021?

 , ,


1

3

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

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

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

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

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


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

надо запретить ПЕРЕопределения. и разрешить только определения.

Не совсем. В Haskell можно доопределить новый тип к типу классов Num и у нового типа появятся арифметические операторы. При этом для нового типа для «+» должны сохранятся ассоциативность и коммутативность.

Можно доопределять без изменения смысла оператора.

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

А определить новые в Си++ невозможно.

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

alysnix ()

Что выбрать? Vim или Emacs?

Emacs

Изучать в 2021 году Lisp?

Да

Если изучать, какой?

Clojure

А не засмеют сотрудники?

Нет

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

может понять даже абсолютно несведущий в этой библиотеке человек

Код, описывающий грамматику с помощью Boost.Spirit.

Ну что делает эта грамматика:

phrase_parse(first, last,

        //  Begin grammar
        (
            int_[ref(v) += k >> _1] >> *((',' | '.') >> int_)
        )
        ,
        //  End grammar

        space);

?

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

для строк тоже коммутативность?

Арифметическое сложение к строкам неприменимо. Можно разве что приводить строки к числам и складывать. Для векторов арифметика поэлементная.

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

Ну что делает эта грамматика:

пишет в лор от анонимуса

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

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

Оператор * соответствует * из регулярных выражений, >> обозначает следование, | обозначает «или», int_ соответсвует регулярке -?\d+. Собственно, задача не составит особого труда для любого, кто умеет читать регулярные выражения. Единственная нетривиальная вещь здесь это квадратные скобки, но этот концепт объясняется чуть ли не на первой странице Boost.Spirit – ассоциация действия с парсером.

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

Никак. В С++, к сожалению, не допускаются пользовательские операторы.

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

Как, например, в с++ определить операторы ← или ↑ ?

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

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

отделяемых точкой либо запятой.

Не угадал. Здесь «|» обозначает побитовое сложение :-)

Вообще, такого бреда в Си++ навалом

s = a;
s = s + b;

и

s = a + b;

часто дают разные результаты.

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

Не угадал.

Я не гадал.

Здесь «|» обозначает побитовое сложение :-)

Да, согласен. Чтобы обозначало то, что я написал, нужно было писать их в lit.

Хотел это отметить, но теперь уже никто не поверит.

часто дают разные результаты.

Кто бы мог подумать – разные операции дают разные результаты.

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

Кто бы мог подумать – разные операции дают разные результаты.

В математике или, например, в Паскале это одна операция. А в Си++ даже s = s + a и s += a разные операции.

Хотел это отметить, но теперь уже никто не поверит.

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

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

даже в Rust добавили https://docs.rs/fluid-let/0.1.0/fluid_let/

«Добавили в раст» слишком громко сказано для простой библиотеки, у которой за два года 500 скачиваний. Я даже заглянул в единственный (публичный + на данный момент) зависимый крейт - так там оно нигде в коде не используется, а саму зависимость вероятно забыли убрать. Не похоже, что оно кому-то сильно нужно.

Если считать это полноценной реализациeй, то на таком уровне её можно «добавить» в вообще любой язык. Не буду утверждать, что никто так вообще не делает, но большой популярности такой подход явно не имеет. Иначе и правда динамические переменные на уровне языка были бы.

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

на Си хотя бы понятна что этот код делает. А на Хаскеле сплошной мусор из монад

Ты просто язык не знаешь, поэтому и видишь мусор. Что в приведённом коде такого страшного (относительно «безмонадного хаскеля»)? Несколько IO () и do?

К слову, «мусор из монад» звучит как «мусор из объектов» применимо к какой-нибудь джаве.

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

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

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

Разве не потому вообще индустрия использует кресты? Потому что можно выкинуть крестовые фичи и получить почти Си.

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

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

Это тупо синтаксический сахар над чем-то вроде

puts("Hello");
puts("World");

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

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

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

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

stdin, stdout, stderr

Однопоточное-однозадачное говно мамонта.

переменные окружения для процесса

Read-only.

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

Даже в статическом подмножестве Racket не покидает ощущение, что типы там сверху приклеены.

А можешь подробнее расписать почему?

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

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

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

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

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

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

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

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

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

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

Сделать переопределением смысла операторов нечитаемый код — на это способен только Си++.

Разве только в С++ можно переопределять стандартные операторы?..

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

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

Можно исправить данные. Можно загрузить другой код для того же дотнета.

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

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

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

if not well_formed_log_entry_p(text):
    breakpoint()

Аналогично в JS:

if (!well_formed_log_entry_p(text)) breakpoint();

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

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

Odin, Felix, V

Даже не слышал про них.

D — у них же вроде все-таки упор на сборщик мусора, не? А если да, то это конкурент Go/JVM/CLR, а не C++.

Zig — да, только язык очень молодой и с неясными перспективами. Беглое ознакомление с описанием языка мне откровенно не понравилось — это не тянет на убийцу C++ и Rust, скорее на убийцу Си, а как можно убить то, что уже мертво?

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

Питон тут вообще сбоку, нынешний бум ML/AI связан с ростом вычислительных мощностей вообще и вычислениями на GPU в частности, что нужно для коннективистов

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

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

При этом для нового типа для «+» должны сохранятся ассоциативность и коммутативность.

Компилятор это проверит?

В Haskell можно доопределить новый тип к типу классов Num и у нового типа появятся арифметические операторы.

Хочешь сказать в хаскеле нельзя определить новый оператор + для типа? Да, придётся NoImplicitPrelude использовать, чтобы сбить с толку читающего код. Вероятно, так обычно не делают, но можно же.

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

Среди тех, у которых сравнимая скорость (си, фортран), проблема с дженериками

Еще у Go проблема с обобщениями.

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

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

Вронг, Дейкстра писал про эту проблему еще в 80-х годах. Просто, в нулевых эта проблема приобрела настолько чудовищный размах, что программисты не только не могли писать свою лапшу так быстро, как быстро ее компьютер выполняет — они в принципе не могли нагрузить компьютер своими инструментами, даже если лапшу выполнять в цикле много раз. То есть, скриптовуха приняла массовый оборот еще в 80-х, когда производительности компьютеров стала измеряться десятками МГц, то есть, несколько процессор за секунду выполнял десятки человеколет линейного асмового кода. Сейчас, конечно, процессор за секунду выполняет уже тысячи человеколет программного кода.

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

Ещё web. Там производительность была не нужна, зато была нужна возможность быстро поправить программу и проверить результат

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

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

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

Но теперь на LLVM много языков.

Вторичных.

Если я ничего не путаю, то в LLVM почти сразу эпл начали деньги вливать. В «алмазных» спонсорах именно они (ну и Qualcomm), гугл и прочие - платиновые. Подозреваю, что протолкнуть всё необходимое (например, для Swift) они легко смогут, даже если это не будет нужно для С++. В самом крайнем случае, будут держать свои патчи - ресурсов хватит. Языки, за которыми не стоят большие компании так (легко) не смогут, это да. Но в общем и целом, нет никакой особой «первичности» у плюсов. Как обычно решают деньги.

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

Код Boost.Spirit очень читаемый, его с легкостью может понять даже абсолютно несведущий в этой библиотеке человек

Это странно, потому что, как правило, любой код библиотеки обобщений — это 10% алгоритмов и 90% объявлений. К аналогичной цели ударными темпами стремится и Rust.

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

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

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

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

Это путь вникуда прежде всего потому, что такой принцип построения процессоров (однопоточные высокоспециализированные арифметико-логические устройства) чудовищно неэффективно использует транзисторы. Если у высокопараллельного исполнителя на очень примитивных АЛУ у каждого АЛУ будет лишь одна десятая производительности современных высокопроизводительных АЛУ, то он все равно будет в сотни раз эффективнее современного ЦП, поскольку производительность современного ЦП в тысячи раз меньше теоретически возможной для того же чиста транзисторов.

И что же думает по этому поводу Intel? Давайте засунем в процессор аппаратный декодер Quick Sync и набор инструкций AVX512 — еще более высокоспециализированные вычислители. Причем, NVidia со своим трассировщиком лучей поноса идет по тому же маршруту.

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

Если изучать, какой?

Clojure

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

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

Имелся в виду код, использующий Boost.Spirit, я раскрыл в следующем сообщении.

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

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

Касательно «с минимумом STL» – вместо STL берут Qt, или Folly, или еще какую-то библиотеку, выполняющую роль стандартной. Не потому что стандартная плоха, а потому что она стандартная, тогда как нужна нестандартная, которую можно заточить под нужды компании и менять в любой момент.

Siborgium ★★★ ()
Ответ на: комментарий от DarkEld3r
  1. Синтаксис. Причины выбора такого синтаксиса понятны, но выглядит это ужасно.
  2. Все, связанное с дженериками, находится в зачаточном состоянии.
  3. Главный смысл всего этого развлечения – оптимизация – работает очень условно, см. https://docs.racket-lang.org/ts-guide/optimization.html
  4. Все по ссылке https://docs.racket-lang.org/ts-guide/caveats.html

Я в свое время попробовал на этом писать, и понял, что на untyped racket писать значительно проще, при этом я почти ничего не теряю.

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

Касательно «с минимумом STL» – вместо STL берут Qt, или Folly, или еще какую-то библиотеку, выполняющую роль стандартной. Не потому что стандартная плоха, а потому что она стандартная

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

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

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

На самом деле индустрии чудовищно не хватает языка, который был бы не такой жестко заточенный на производительность, как кресты, но был бы прост в работе, и при этом не дергал бы сборщик мусора на каждый чих (привет p-машине). Хотя бы потому, что в 2021 проблема заключается в утилизации ядЕР, а не в утилизации ядРА, и потому плюс-минус 30% производительности не значат ничего. Какой-нибудь инстаграм крутится на питоне, и ему норм — какой еще прозводительный код, какие бесплатные абстракции? Они остались где-то в начале нулевых.

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

Я в свое время попробовал на этом писать, и понял, что на untyped racket писать значительно проще, при этом я почти ничего не теряю

А на питоне писать еще проще, при этом, опять-таки, почти ничего не теряешь... кроме статуса бунтаря.

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

Так же «фичи питона» «хорошо ложатся» на Си, позволяя дергать производительный код.

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

А хаскель вообще идеально ложится.

Не ложится по тем же причинам. Хотя отмечу, что из него С дергать проще, чем из питона.

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

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

Какие?

строки ты можешь иметь только такие, какие тебе дали.

А какие должны быть?

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

Это тупо синтаксический сахар над чем-то вроде

Там ещё fixed, setprecision, … И всё это относится к конкретному объекту, а не к системе в целом. Синтаксически полный эквивалент

cout.setprecision(5).out(x).setprecision(3).out(y).endln();

На функции заменить можно только если первым аргументом поток передавать. Типа

cputs(cout, "Hello");
cputs(cout, "World");
monk ★★★★★ ()
Ответ на: комментарий от byko3y

Дернул функцию, которая тоже думает, что она одна использует это глобальное имя

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

Однопоточное-однозадачное говно мамонта.

После fork() в каждом процессе независимые значения.

переменные окружения для процесса

Read-only.

man setenv

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

Интересно, есть ли под это готовые инструменты.

Common Lisp :-)

А для остального CRIO есть.

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

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

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

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

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

для «+» должны сохранятся ассоциативность и коммутативность.

Компилятор это проверит?

Liquid Haskell — да. Обычный — нет.

Да, придётся NoImplicitPrelude использовать, чтобы сбить с толку читающего код.

И не использовать в этом коде числа. Тоже вариант.

В C++ проблема в том, что строка

a = b >> c;

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

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