LINUX.ORG.RU

clojure после common lisp - насколько омерзительно и в чём именно?

 , ,


3

2

Всё ещё думаю о возможности заняться разработкой на clojure. Но ява же тормозная - меня бесит скорость сборки. Вот боюсь, как бы кложа не оказалась слишком уж тормозной.

Расскажите о своих ощущениях (из серии «собираюсь жениться - отговорите»).

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

Никаких экспериментов большие конторы тем не менее никогда не позволяют

Да ладно?

Microsoft Research делает кучу всего «на выброс», у гугла есть куча полуофициальных проектов (ну и Google Research), фейсбук приютили Александреску и разрешили ему что-то там на D написать/переписать. Примеров более чем достаточно.

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

Это все «эксперименты» внутри устоявшихся парадигм и накатанных рельс. Haskell разве что в MS Research немного выделяется, но это скорее исключение.

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

В случае провального проекта всегда надо обосновать причину провала. На лисп списать гораздо проще, чем на Java, например.

Не могу с полной уверенностью судить или это ты наивен или может я чего-то не знаю. (:

Из моего опыта, никого оно на таком уровне не волнует. Не получится так, что тебя спрашивают почему облажался, отвечаешь, что дело в лиспе и все такие «ааа… ну ладно, действительно, на тебе бонус, ты не виноват».

Кстати, как это вообще работает? Если на лисп легко свалить - то его наоборот надо выбирать на рисковые проекты. Если не взлетело, то (как руководитель) валишь всё на команду и технологию, которую они выбрали. Если взлетело, то понятное дело - все заслуги себе.

Стартапы обычно создаются командами.

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

Контора может, отдельный менеджер - нет.

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

https://docs.rs/papyrus/0.17.2/papyrus/ 6,858 Downloads all time

Не густо. Ну если так посмотреть, то и для С репл где-то был.

Это заполнение ниши «нужно что-то с макросами и желательно с REPL’ом».

Всё-таки не согласен. Четыре года пишу на расте, поработал в трёх командах и как-то не замечал использования репла. Насчёт макросов мысль уже писал: считаю, что они скорее приятное дополнение. Сомневаюсь, что кто-то думает «нужен С, но с (нормальными) макросами - возьму раст».

Либо как в Typed Racket нужна навороченная система типов:

Ракет читаю с трудом, но интересно во что оно типизируется. Можешь, пожалуйста, словами расписать?

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

Да-да.

Вот нафига с точки зрения бизнеса майкрософту F#? Взлёт языку вообще не грозит, но ведь тянут. Или Singularity они сделали. Verona, опять же.

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

python, ruby, js (надстройки), php, clojure - везде опциональная стат типизация.

Это всё старые языки, которые нельзя так просто выкинуть. Покажи новые с опциональной типизацией.

Речь шла о том, что в лиспе якобы нет статической типизации.

Речь шла о том, что из популярных лиспов типизация есть только в Typed Racket. Ну ОК, про кложуру ещё забыл.

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

Что-то у вас как-то без огонька. Я отпишусь, а если нужен - то позовите.

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

Вот нафига с точки зрения бизнеса майкрософту F#? Взлёт языку вообще не грозит, но ведь тянут.

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

Это всё старые языки, которые нельзя так просто выкинуть. Покажи новые с опциональной типизацией.

Каких языков тебе еще не хватает, что понадобились новые?

Речь шла о том, что из популярных лиспов типизация есть только в Typed Racket. Ну ОК, про кложуру ещё забыл.

В кложе как раз декларация типов, а не стат типизация, в отличии от CL, поэтому «забыл» ты именно общелисп - а именно он самый популярный.

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

А почему не просто «первый аргумент ф-ция»?

Потому что '+ не функция, а символ. А внутри mapc вызывается symbol-function, чтобы по нему найти функцию.

Так вроде в этих ваших хаскелях даже можно гетерогенные списки и как-то их даже типизируют?

Как-то. Нормальные рекурсивные функции на них не работают. Проще делать список [Dynamic] и преобразовывать тип при чтении.

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

Кстати, как это вообще работает? Если на лисп легко свалить - то его наоборот надо выбирать на рисковые проекты. Если не взлетело, то (как руководитель) валишь всё на команду и технологию, которую они выбрали. Если взлетело, то понятное дело - все заслуги себе.

«… которую они выбрали …». Примерно так и работает. Кто-то должен выбирать язык программирования для реализации. Если этот кто-то выбирает Java/C#/C++, вопросов нет, если выбирается какая-то экзотика, то выбор под личную ответственность. Причём начальнику того, кто делает выбор действительно сплошная выгода.

У нас на таких условиях коммутаторы с Cisco на HP переводили. В итоге, организация, конечно, сэкономила денег, админ, который инициировал перевод, уволился, у начальника отдела теперь есть универсальная отмазка, почему что-то не работает, а у руководства повыше уверенность, что HP делает плохие коммутаторы.

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

А так и происходит. Просто потом у заказчика возникает желание прикрутить пару дюжин сервисов, те двое говорят, что это долго и дорого, он нанимает другую команду человек на 50, а те переписывают всё на Java, так как знают Java или видят, что из тех сервисов у половины на Java уже есть готовая реализация.

Всё-таки не согласен.

Скорее всего, ты прав. Я со стороны смотрю. Могу оценивать неверно.

Ракет читаю с трудом, но интересно во что оно типизируется. Можешь, пожалуйста, словами расписать?

- : (All (c a b ...)
      (case->
       (-> (-> a c) (Pairof a (Listof a)) (Pairof c (Listof c)))
       (-> (-> a b ... b c) (Listof a) (Listof b) ... b (Listof c))))

Для любых типов c, a и списка типов (b …) тип map один из:

  • первый аргумент: функция с аргументом a и результатом c, второй аргумент пара из a и списка a, результат — пара из c и списка c.

  • первый аргумент функция с первым аргументом типа a и остальными аргументами с типами совпадающими со списком типов (b …), возвращающая тип c, второй аргумент список типа a, дальнейшие аргументы списки с типами, соответствующими типам из списка (b …), результат — список c.

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

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

Команда = руководитель, который за эту команду принимает решение, эту команду набирает, эту команду увольняет. Нуежели ты работал на проектах только как наемник-одиночка? Более того, некоторые стартапы выезжают только за счет того, что используют громкие технологии. И это не только в IT — классическим примером хайповых технологий является Илон Маск: только он заявил, что собирается делать роботов, которые поработят мир — сразу пошли инвестиции. Когда же выяснилось, что выбрашенный только на обучение роботов (даже не на разработку технологии) бюджет многократно превышает суммарную стоимость всех турнирова Dota International в несколько раз, а ИИ по прежнему не может обыграть профессиональных игроков на равных — тогда Маск выкатывает какую-то показушную халтуру, чтобы пустить пыль в глаза.

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

Также есть коррупционная составляющая, когда руководитель получает вполне конкретную материальную выгоду за то, что покупает что-то у IBM/Oracle/SAP/etc. И эти же фирмы прикроют эту схему, скажут, прямо как ты написал: «проект хороший, годный, и руководитель умничка — но команда подвела; дайте ему хорошую команду — и он сделает чудеса».

Короче говоря — самая обычная коммерция в сфере с большим оборотом денег.

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

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

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

Вот нафига с точки зрения бизнеса майкрософту F#? Взлёт языку вообще не грозит, но ведь тянут. Или Singularity они сделали. Verona, опять же

И винду тянут, хотя взлет ей не грозит. У F# ниша узкая. но она есть, и отнять ее у MS не получится. К тому же, MS тратит на F# не так много ресурсов, как некоторые могут подумать — это все-таки проект второго эшелона.

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

Потому что '+ не функция, а символ. А внутри mapc вызывается symbol-function, чтобы по нему найти функцию.

Ну это чисто особенность CL, по смыслу здесь просто подходит функция.

Нормальные рекурсивные функции на них не работают.

А можно какой-то короткий пример?

Проще делать список [Dynamic] и преобразовывать тип при чтении.

В каком смысле при чтении?

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

Ну это чисто особенность CL, по смыслу здесь просто подходит функция.

Это API стандартной библиотеки. Там ещё CLOS на символах с именами классов построен. А если делать «по смыслу», получится Racket.

А можно какой-то короткий пример?

map1 f (x:xs) = f x:map1 xs
map1 f [] = []

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

В каком смысле при чтении?

При чтении из списка

a = fromDynamic (myList !! 3) :: Int
monk ★★★★★
()
Ответ на: комментарий от alienclaster

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

Вот прям «много где»? Мне кажется, что тот же хаскель больше используется. А на фоне джавы или C# это и вовсе незаметно.

Каких языков тебе еще не хватает, что понадобились новые?

Это странный аргумент. Вон «всем хватало» objective-c, а потом сделали swift и народ радуется. Аналогично с Go, Rust, Kotlin, Dart. Новые языки вполне себе появляются. Кстати, последний, вроде как, в версии 2.0 как раз обзавёлся статической типизацией.

Вообще мне просто интересно сравнить какая типизация (статическая или динамическая) преобладает в новых языках. Из динамически типизированных вспомнил Elixir, кстати.

В кложе как раз декларация типов, а не стат типизация, в отличии от CL, поэтому «забыл» ты именно общелисп - а именно он самый популярный.

Насчёт популярности - спорно. Люди пишущие на кложе мне попадались несравненно чаще. Понимаю, что критерий так себе, но поискал сейчас на stackoverflow: по запросу «lisp» находится две вакансии (и в обеих из них это в разделе «хорошо если есть опыт в языках»), по «clojure» тоже, в основном, мусор, но есть и реальные вакансии.

Но это не принципиально, про типизацию интереснее. Ты же сам говорил «sbcl много где типы выводит, но статической типизацией назвать это все же нельзя». Хочешь всё-таки сказать, что Common Lisp статически типизированный?

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

Хочешь всё-таки сказать, что Common Lisp статически типизированный?

Настолько же, насколько статически типизирован TypeScript, например.

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

Не буду продолжать спор про перекладывание ответственности. Добавлю только, что я (как технарь) готов предлагать раст, если есть реальная возможность его применения. Скажем, сейчас работаю в конторе, где есть здоровенный монолит на С++ и дописывать/переписывать его на расте нет смысла. А вот отдельные сервисы на нём делать - вполне можно.

Ну а если вдруг проект умрёт и меня уволят - ну и ладно, работу найду. Зато буду заниматься тем, что мне интересно, а не грызть ненавистный кактус ради «стабильности».

Просто потом у заказчика возникает желание прикрутить пару дюжин сервисов, те двое говорят, что это долго и дорого, он нанимает другую команду человек на 50, а те переписывают всё на Java

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

Если нет, то нормальное руководство заранее бы подумало о масштабировании: в конце концов лисперов учить/переучивать можно и внутри, а не искать готовых. Тем более, что потом им будет сложнее куда-то сбежать, чем джавистам. (:

Для любых типов c, a и списка типов (b …) тип map один из:

Спасибо, вроде, понял. А почему бы это просто двумя функциями не сделать? Или это как раз из раздела «впихивания в ограничения типов»? Наверное, я (как человек не дружащий с динамикой) просто не считаю это (серьёзными) ограничениями.

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

И винду тянут, хотя взлет ей не грозит.

Смерть в обозримом будущем - тоже. (:

Ну и винда помогает продавать другие сервисы. Мне кажется, что роль F# в этом плане куда скромнее. Да и F# всё-таки был лишь одним из примеров.

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

Нуежели ты работал на проектах только как наемник-одиночка?

Нет, конечно. Руководителем команды тоже доводилось побыть. Поэтому я и понимаю, что этих руководителей будет целая иерархия. И если ты технарь и состоялся как специалист (без работы не останешься), то можешь (пробовать) продавливать технологии, которые считаешь перспективными. Если веришь, что с лиспом/растом/немерле разработка пойдёт быстрее и/или качественнее, то тебе и карты в руки. Ну а если хочется поиграться, но так чтобы за это ничего не было, то это другой разговор.

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

И в чём тут провал, если деньги заносить продолжают? (:

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

Настолько же, насколько статически типизирован TypeScript, например.

То есть, никак. (:

Ну ладно, убедил. Но тогда в чём разница с кложурой, где, как мне выше сказали, «декларация типов, а не стат типизация»?

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

Ну а если вдруг проект умрёт и меня уволят - ну и ладно, работу найду. Зато буду заниматься тем, что мне интересно, а не грызть ненавистный кактус ради «стабильности».

Я также утилиты на Racket пишу.

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

Так аппетит приходит во время еды, по изначальному ТЗ никаких сервисов не предполагалось и быстрее было написать на лиспе. Хотя некоторые пишут даже сайт-визитку на Kubernetes в надежде, что он когда-то разрастётся в портал c миллионами пользователей. И пишут всегда сразу на Java.

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

Так по смыслу это одна функция. Берём первый аргумент-функцию и применяем поэлементно к остальным аргументам-спискам. Просто для одного списка диапазон типов не получится сделать, поэтому как бы два типа.

Также как у операции ‘+’ вот такой тип: https://pastebin.com/qbSVCKFG

«Без аргументов тип Zero, если один из аргументов 0, то тип второго, если два аргумента Positive-Byte, то результат Positive-Index, если …». Тоже разбить на 100500 функций?

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

Но тогда в чём разница с кложурой, где, как мне выше сказали, «декларация типов, а не стат типизация»?

Ни в чём :-)

Просто под нормальной стат.типизацией подразумевают язык, где нет типа Any.

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

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

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

Конечно, с более-менее грамотным руководителем такое не прокатит, и Маск бы полетел со своей должности за провал проекта

И в чём тут провал, если деньги заносить продолжают?

Деньги заносить продолжают, пока их печатают. Даже на год вперед ситуация не ясна, и Маск уже начинает потихоньку лизать анус даже Путину:

https://www.bbc.com/russian/news-56058800 — Илон Маск пригласил Путина побеседовать в Clubhouse. Что ответил Кремль?

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

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

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

Хочешь всё-таки сказать, что Common Lisp статически типизированный?

Нет. Он динамически типизированный с опциональной стат типизацией и выводом типов (в реализациях).

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

Но ява же тормозная

Как там дела в 2003ем? Мороженное еще вкусное?

Я из 2006 года — там ява почти такая же, как у тебя.

byko3y ★★★★
()

Кложа гораздо тормознее. Хорошо подойдёт только если будет большой упор на параллелизм. А так, такой себе вариант.

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

Кложа гораздо тормознее. Хорошо подойдёт только если будет большой упор на параллелизм. А так, такой себе вариант

Сударь, вы не правы. Питон тоже «тормозной» — и, тем не менее, на нем работает ютьюб и инстаграм... А, ладно, тормозной. Но я уже отвечал, что горячие куски кода можно просто писать на жаве. Нет, вот так: горячие куски кода обязательно нужно писать на жаве.

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

Горячие куски писать надо на С и подключать по JNI. Кложа не просто тормоз, но ещё она жрёт память как никто другой.

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

Горячие куски писать надо на С и подключать по JNI

А ты точно этим серьезно занимался? Проблема JNI заключается в том, что оно вырубает JIT оптимизацию вокруг себя, плюс сам вызов не может быть оптимизирован. То есть, чтобы получить какую-то выгоду, нужно прям здоровенные законченные функции выносить, а это уже скорее C++/Rust — и потому что они лучше подходят для написания большой программы, и потому что Си слишком уж сильно нивелирует жавовую надежность исполнения, особенно если речь идет про большую законченную функцию.

Кложа не просто тормоз, но ещё она жрёт память как никто другой

Опять, ответ один и тот же — писать на жаве.

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

Но тогда в чём разница с кложурой, где, как мне выше сказали, «декларация типов, а не стат типизация»?

Ни в чём :-)

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

Просто под нормальной стат.типизацией подразумевают язык, где нет типа Any.

А IRL можно ли вообще обойтись без Any? Мне кажется, что нет - в любой большой и нетривиальной программе понадобится какой-либо заменитель динамики.

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

А IRL можно ли вообще обойтись без Any? Мне кажется, что нет - в любой большой и нетривиальной программе понадобится какой-либо заменитель динамики.

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

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

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

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

Вот спорно. По определению, ни то ни другое к проверкам типов отношения не имело. Декларация типа в лиспе была обещанием программиста для оптимизации, никакого вывода типов и проверок ошибок не подразумевалось. Для проверки типа был check-type. И только разработчики SBCL решили слегка поменять семантику. Также и с тайпхинтами: сначала документация, потом статические анализаторы, потом поддержка компилятором для оптимизации…

Сейчас что clojure core.typed, что SBCL declare type делают почти одно и то же.

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

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

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

Хотя спорить не буду, в вебе я не силён и описываемый случай выглядит слишком абстрактно.

«Без аргументов тип Zero, если один из аргументов 0, то тип второго, если два аргумента Positive-Byte, то результат Positive-Index, если …». Тоже разбить на 100500 функций?

Тут-то разбивать зачем? Это (с оговорками) даже на хаскеле выразить можно: просто реализуем Num для разных типов. Правда есть ограничение, что + только с одинаковыми типами работать может, но ведь можно ввести и новый тайпкласс. С другой стороны, в ракете, насколько я понимаю, не получится сложение расширить снаружи?

В этом плане, в расте нет обоих недостатков: трейт std::ops::Add может быть реализован для разных типов (и возвращать третий тип). И заодно сам трейт ровно одну операцию реализует, а не тянет за собой кучу всего как Num. Правда остаётся ограничение на всего два аргумента, но тут уже особенность лиспов, кроме них мало какой (никакой?) язык такое позволяет.

Мне кажется, что в итоге всё упирается в «излишнюю» гибкость: мы хотим произвольное количество аргументов с произвольными типами. Да и раз Racket может это типизировать, то проблема решаема. Вопрос в том насколько это нужно «в реальной жизни». Ответ будет зависеть от того кого спрашивать будем. (:

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

Просто под нормальной стат.типизацией подразумевают язык, где нет типа Any.

Но ведь даже в хаскеле есть Dynamic?.. (:

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

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

Yahoo купил Viaweb, написанный на Common Lisp, за 49 миллионов долларов, а затем весь код переписал на C++ и Perl. Что уж говорить про более мелкие проекты.

С другой стороны, в ракете, насколько я понимаю, не получится сложение расширить снаружи?

Там есть некий аналог тайпклассов: https://docs.racket-lang.org/reference/struct-generics.html

Кроме того никто не мешает сделать

(define/match (+ . rest)
  [((list (? mytype? _) ...)) (apply my-+ rest)]
  [(_) (apply racket:+ rest)])```

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

кроме них мало какой (никакой?) язык такое позволяет.

C, C++, python, JS, …

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

Но ведь даже в хаскеле есть Dynamic?.. (:

К типу Any он имеет такое же отношение, как монада IO к нечистым функциям.

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

Кстати. Common Lisp и Haskell находятся на противоположных краях шкалы статики/динамики. В лиспе можно в любой момент переопределить тип, класс, функцию, сделать любой побочный эффект (даже при компиляции). В хаскеле всё это максимально затруднено. А мотивация «В идеале каждое использование as any в Typescript должно требовать 20 подтягиваний, что бы его могли использовать только самые сильные программисты.» (c) bash.im

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

А мотивация «В идеале каждое использование as any в Typescript должно требовать 20 подтягиваний, что бы его могли использовать только самые сильные программисты.» (c) bash.im

И я с этим согласен. (:

К типу Any он имеет такое же отношение, как монада IO к нечистым функциям.

Не уверен, что понял аналогию (даже вместе с последующими объяснениями). То есть, разница только в том сколько (специально созданных) «сложностей» нужно преодолевать? Не уверен, что это правильный критерий.

В C# вон dynamic, вроде, работает без всяких приседаний (с исключением в рантайме). Но разве это делает язык динамически типизированным?..

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

Yahoo купил Viaweb, написанный на Common Lisp, за 49 миллионов долларов, а затем весь код переписал на C++ и Perl.

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

Там есть некий аналог тайпклассов: https://docs.racket-lang.org/reference/struct-generics.html

В ракете чего только нет. (:

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

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

Если я правильно понял что значит racket:+, то это ведь не будет работать, если так решат сделать две независимых библиотеки? Ну и в целом, наверное, будет странно, если библиотека будет экспортировать переопределённую «стандартную» функцию?

C, C++, python, JS, …

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

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

То есть, разница только в том сколько (специально созданных) «сложностей» нужно преодолевать? Не уверен, что это правильный критерий.

Именно. Также как операционные системы сделаны, чтобы усложнить доступ к данным чужого процесса.

В C# вон dynamic, вроде, работает без всяких приседаний (с исключением в рантайме). Но разве это делает язык динамически типизированным?..

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

Вообще, нельзя, наверное, противопоставлять статическую и динамическую типизацию. В Common Lisp и C# есть обе. В Haskell и C только статическая. В perl5 только динамическая.

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

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

Хотя на мой взгляд разделение проходит не по границе «есть ли (удобный) Any», а по «есть ли другие типы» (и что это значит).

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

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

Вот этим Racket существенно отличается от Haskell/Rust/Common Lisp. Я когда только перешёл на Racket, воспринимал его как Common Lisp с нормальными модулями и call/cc (любую программу на Common Lisp можно почти 1-в-1 перенести в Racket). Пытался сделать то, чего мне, казалось, не хватало (было привычным из Common Lisp’а): отладчик с произвольными командами, разработку в образе, CLOS на все функции.

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

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

Тоже ограничения, хоть и в другой плоскости.

В Common Lisp не так:

(setf (symbol-function +) 
      (let ((old (symbol-function +)))
      (lamda (&rest args) 
        (if (my-cond args) 
            (my-+ args)
            (apply old args))))

именно добавит новую ветку выполнения к системному CL:+.

Ну и в целом, наверное, будет странно, если библиотека будет экспортировать переопределённую «стандартную» функцию?

Для Racket в этом ничего странного. Пакет racket экспортирует функции из racket/base (да, неизменённые). typed/racket экспортирует переопределённые функции и синтаксисы из racket (функции с типами, синтаксис define слегка отличается, …).

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

На C++ это однострочник:

template<typename... Args> auto sum(Args... args) { return (args + ...); }

sum(1, 2, 5);

На python: sum([1, 2, 5]) // ладно, не чистый пример

В остальных, согласен, «не принято». Но никто не мешает написать библиотеку и будет «из коробки». Также как есть CLOS в Racket.

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

Хотя на мой взгляд разделение проходит не по границе «есть ли (удобный) Any», а по «есть ли другие типы» (и что это значит).

Тогда Common Lisp статически типизированный изначально с момента выпуска стандарта. И Visual Basic статически типизированный.

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

На C++ это однострочник:

Начиная с С++17, но я немного о другом: польская нотация способствует появлению функций, которые работают с произвольным количеством аргументов. В С++ такая sum разве что при кодогенерации полезна будет. Eсли нужно сложить три числа, то и заморачиваться никто не будет и напишет a + b + c. В остальных случаях используют std::accumulate на итераторах.

Но никто не мешает написать библиотеку и будет «из коробки».

Ну нет. Из коробки - это именно «есть в языке» (ну или стандартной библиотеке).

К слову, продолжая обсуждение из соседних сообщений: если в языке можно сделать Any тип, который будет слабо отличаться от «встроенных» типов, то этот язык тоже становится динамически типизированным? Mне кажется, что в С++ можно попробовать такие изобразить.

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

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

Сложение было просто пример. Можно также попробовать типизировать printf, std::make_unique, python print, js console.log, go append

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

Тогда Common Lisp статически типизированный изначально с момента выпуска стандарта.

И что будет с этими типами, если сделать (declare (optimize (safety 0)))?

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

И что будет с этими типами, если сделать (declare (optimize (safety 0)))?

Если в программе ошибок нет, то будет продолжать работать также. Если есть optimize speed, то будет использовать типы для оптимизации. Проверка типов при компиляции будет, при выполнении — нет.

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

Начиная с С++17

Так на дворе 2021 уже.

В С++ такая sum разве что при кодогенерации полезна будет.

Там есть функции с initializer_list, то есть те же произвольные аргументы, но в фигурных скобках: min, max, вектора всякие, …

Да и просто с переменным числом аргументов: make_uiniquie, format, …

Mне кажется, что в С++ можно попробовать такие изобразить.

Очень сомневаюсь. Могут, конечно, вслед за C# изобразить что-то подобное, но пока std::any для чтения требует any_cast.

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

printf

А как эта штука работает?

go append

Эта функция ведь просто добавляет значения к слайсу? В чём тут проблема? Пока искал, то даже попалась сигнатура:

func append(s []T, vs ...T) []T

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

std::make_unique

Если пытаться делать аналог на расте, то можно придумать трейт New, тогда такая функция может выглядеть как-то так:

trait New {
    type Params;

    fn new(params: Params) -> Self;
}

fn make_box<T: New>(params: T::Params) -> Box<T> {
    Box::new(T::new(params))
}

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

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

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

Не. Это всё просто примеры к тезису, что функции с переменным числом параметров широко распространены.

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

А как эта штука работает?

Сложно.

printf :: (PrintfType r) => String -> r
printf fmts = spr fmts []

class PrintfType t where
    spr :: String -> [UPrintf] -> t

instance (IsChar c) => PrintfType [c] where
    spr fmts args = map fromChar (uprintf fmts (reverse args))

instance (PrintfArg a, PrintfType r) => PrintfType (a -> r) where
    spr fmts args = \a -> spr fmts (toUPrintf a : args)
monk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.