LINUX.ORG.RU

Макросы в Scala против макросов в Common Lisp

 , ,


2

8

Я почитал туториал от 2016 года и написал очень краткую выжимку из него.

Что можно сказать? Во-первых, CL как язык для МП устаревает и теряет привлекательность буквально у нас на глазах. В scala, конечно, МП менее удобно из-за более сложного синтаксиса, зато в Scala появилась концепция семантической БД - это результат семантического анализа текста со всеми типами данных и декларациями. В CL такой семантической БД нет. Притом что Scala - это даже не первый такой язык. Если я правильно понял, clang тоже такое умеет.

Среди не афишируемых целей проекта Яр есть цель сделать именно такую семантическую БД. Теперь нет смысла это скрывать.

Поимимо этого, кто не в курсе - Common Lisp _не является_ гомоиконным языком, потому что есть #. , квазицитаты частично обрабатываются, а комментарии теряются. Другие побочные эффекты чтения - это создание символов в пакетах. macro character-ы назначенные пользователем, могут делать что угодно, вплоть до запуска ракеты. Т.е. нельзя зачитать файл лиспа и проанализировать его средством без последствий для среды. Вообще нельзя. Для Java и C это сделать можно, а для лиспа - нет. Фига себе, да? Ещё одной целью проекта Яр является создание истинно гомоиконного языка. Причём это не моя прихоть, а обязательное условие для создания полноценной IDE, а не набора костылей, каковым является SLIME.

Если ещё остались энтузиасты лиспа, можно попробовать сделать семантическую БД для CL. Есть augment-environment, к-рая поддерживается в CCL. В ней есть кое-какая информация о типах. Хотя на самом деле скорее всего придётся патчить компиляторы.

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

И ещё одно странное наблюдение - похоже, что макросы в Scala никому особо не нужны.

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

Иллюстрирующий пример этого - фейл Nemerle.

Надеюсь ты понимаешь, что строить доказательную базу на одном (да ещё и таком) примере глупо? У Nemerle была/есть целая куча «проблем», начиная от выбора платформы (назови хоть один живой язык на .NET не от майкрософт) и заканчивая специфическими взглядами команды (джетбрейнс их подобрали, а потом пути снова разошлись). Макросы тут есть и повлияли, то где-то в самом конце списка.

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

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

и исчислением зависимых типов выполнять model checking требуемый, по ситуации. типа синтаксические и семантические предикаты в парсере.

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

На макросах в Scala сделали удобный интерфейс к базам данных (http://getquill.io/) и сериализаторы JSON.

По мне так лучше бы приделали удобный синтаксический сахар для монад, чем эти макросы, по примеру того же F#.

Чем не устраивает for comprehension?

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

Это обещание компилятору

Ну так и любая статическая типизация - это обещание компилятору. Просто обычные компиляторы за этим жёстче следят и не дают собрать программу с ошибками типизации.

В случае SBCL, он не верит на слово и всё равно проверяет при выполнении, если не может доказать, что утверждение верно при компиляции.

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

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

Я сказал «иллюстрация», а не «доказательная база». На самом деле я точно не знаю и в этом признался сразу.

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

HEALED LISP

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

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

зачем продолжать насиловать лисп?

инкрементная компиляция в нативный код + весь дизайн языка заточен на инкрементную разработку + тулчейн под пермиссивной лицензией (ну, почти). Раньше я думал, что в лиспе ещё хорошая сборка мусора, но в SBCL она плохая. Также я раньше думал, что он круто поддерживает треды, но теперь я думаю, что треды - это вообще не круто. Однако продолжаю ими пользоваться.

Кроме того, если они и обошли лисп, то у Яра ещё есть шанс догнать и перегнать. Хотя, конечно, тяжело конкурировать с крупными коллективами, они идут наперерез и вполне могут обогнать. В мою пользу говорит то, что если язык изначально не был рассчитан на инкрементную разработку, то это (как мне кажется) уже практически невозможно исправить. Может быть, я слишком оптимистичен здесь.

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

Чем не устраивает for comprehension?

Ну, это же не аналог нисколько!

Он больше ориентирован на коллекции, чем на абстрактные вычисления. Там лишь map, flatMap и filter. А где return, хотя бы? Я уже не говорю про поддержку while, if, match, try-catch, try-finally. В общем, предлагаю сначала ознакомиться с F# все же.

Вижу, как for-comprehension часто стараются использовать для разных Future, иногда Option, но это не то, потому что получается не очень

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

Давайте вернёмся к теме: кто-нибудь хочет сделать библиотеку, содержащую слой переносимости для извлечения инфы о типах и декларациях для разных реализаций CL? Или может быть кто-нибудь знает о такой?

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

Теоретически return, while, if, match, try-catch, try-finally должно быть в ScalaZ. Хотя обычно хватает лишь map, flatMap и filter.

Вижу, как for-comprehension часто стараются использовать для разных Future, иногда Option, но это не то, потому что получается не очень

Ну в Slick получается неплохо.

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

Теоретически return, while, if, match, try-catch, try-finally должно быть в ScalaZ. Хотя обычно хватает лишь map, flatMap и filter.

К слову, return - это специфика самого вычисления. Его не определить извне.

С while, for (обычный цикл) есть такой интересный нюанс. Их можно определить в общем виде, и такие определения подойдут для абсолютно любой монады, но для многих простых монад эти функции можно определить куда эффективнее, что позволяет делать F#. Try-функции, вообще, сложная вещь.

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

Определенно, есть еще над чем поработать в Scala, но я боюсь, что этого никогда не добавят в язык. Поезд ушел. Кардинально менять язык уже поздно, да и далеко не всем нужны монады, хотя Future - довольно раскрученная вещь, и многие до сих пор пытаются приделать к Future удобный синтаксический сахар. Такая проблема была бы решена раз и навсегда, если бы были computation expressions по типу F#

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

Для С++ даже этого нет.

Вообще-то ctags давно есть

ctags разве умеет в references? Актуальный точно не умеет. Ну и ctags слабовать для c++, тут лучше работает rtags, который построен на базе libclang.

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

а с этим? (declaim (ftype ...)...)

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

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

В Яре я добавляю и declaim, и proclaim, до компиляции функции. Только после этого SBCL начинает на этапе компиляции изрядно ругаться. Ну, смеяться над lisper.ru рано, мне там дали полезный ответ, которого здесь не дал никто.

http://lisper.ru/forum/thread/1354#comment-12298

Может быть, ещё теплится сообщество лисперов, ура.

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

при высоком уровне оптимизации SBCL никаких проверок на то, что пришёл integer, вставлять не будет

При safety 0 не будет. Но тогда, если придёт не integer, может просто упасть вся среда.

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

Ну так и любая статическая типизация - это обещание компилятору. Просто обычные компиляторы за этим жёстче следят и не дают собрать программу с ошибками типизации.

Так в этом и есть определение статической типизации. Статическая типизация — это однозначное определение типа переменных на этапе компиляции.

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

Кстати, тут кто-нить вкурсе как в коммон-лисп со скоростью и массивами?
Я слышал, что быстро работают только simple-array.
Т.е. если добавить fill-pointer, то производительность сразу резко просядет?
Есть какие-нить бенчи по разным вариациям опций массивов, типо там как ведут себя simple-array, simple-array но не с простым типом элемента, с fill-pointer, displaced и т.д. вместе и по отдельности?

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

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

И именно поэтому в нём невозможна статическая типизация. Вот есть у тебя foo : integer → integer и bar(x) = foo(x) + 1 : integer → integer. При разработке понимаешь, что нужны не только целые значения, но и вещественные. То есть типы должны стать number → number. Но ты не можешь поменять инкрементально тип ни у foo (сломается bar), ни у bar (со старым foo он не скомпилируется).

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

Давайте вернёмся к теме: кто-нибудь хочет сделать библиотеку, содержащую слой переносимости для извлечения инфы о типах и декларациях для разных реализаций CL?

Вроде везде можно просто парсить результат describe. Нет?

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

Но ты не можешь поменять инкрементально

Сможешь. Но я обнаружил, что эта тварь SBCL считает нормой передавать Number туда, где ожидается integer, и даже предупреждения не выдаёт. Это очевидный баг, потому что если туда пытаться передать string, то предупреждение будет (warning и compilation failed, но можно дать пинка и этот код загрузится).

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

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

Это делается только с одной целью - костылять автокомплит в IDE при отсутствии родного ридера. Но получается хреново, т.к при этом невозможно учесть рантайм эффекты которых ты так боишься. Нахрен мне твой анализатор синтаксиса, если я могу работать с кодом in vivo?

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

Это делается только с одной целью

Я угадал. Ты не знаешь. Иди поучи ещё что-нибудь.

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

можно просто парсить результат describe

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

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

Завёл новую тему про типы (точнее, про конкретное дерьмо, к-рое я там обнаружил)

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

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

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

К слову, return - это специфика самого вычисления. Его не определить извне.

Можно реализацию монады как implicit передать и вызвать у неё return. Без ScalaZ нужно писать название конкретной монады(Future.successful например)

для многих простых монад эти функции можно определить куда эффективнее

А не решает ли эту проблему введение метода tailRecM в Cats? Если это не так, какие монады могут быть эффективно реализованы в F# но не в скале?
Кстати в F# ведь нет higher-kinded types и monad transformers сделать не получится?

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

В скалу уже и так много возможностей добавили, не хотелось бы ещё сильнее усложнять язык. Тем не менее, скала всё ещё активно развивается, убедиться в этом можно посмотрев на проект Dotty.

userd
()

Ты в Common Lisp нихрена не понимаешь, он тебе не нравится, лисперы тебя игнорируют, но ты упорно не желаешь менять ЯП для реализации своих «идей».

Ты дебил или мазохист?

anonymous
()

И ещё одно странное наблюдение - похоже, что макросы в Scala никому особо не нужны.

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

А вообще ты посягнул на священную корову общелиспа, да :).

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

How to make Lisp go faster than C

2. На самом деле не только simple-array.
3, Проблема не в «fill-pointer», а в «adjustable».

Пруфы-то есть? Где бенчи?
A Critique of Common Lisp

Тут пишут:

4.7 Arrays
COMMON LISP arrays are incredibly complex. As a concession to non-micro-coded machines, vectors, simple vectors, and simple strings were included as types. The resulting tangle of types (all simple vectors are vectors, all simple strings are strings, all strings are vectors, but no simple strings are simple vectors) is clearly a political compromise and not something that would exist after careful design.
Simple vectors are a fixed-size set of pointers in contiguous locations; they are called simple because they don’t have fill pointers, are not displaced, and are not adjustable in size. Cleary such vectors can be implemented much more efficiently on stock hardware than can general arrays. Unfortunately the default assumption is that a vector is not simple unless explicitly declared simple—making the programmer using stock hardware have to work harder to acheive efficiency, and making programs which work well on micro-coded machines perform poorly on stock hardware.

И везде говорят о симпл-аррей, а аррэй с филл-поинтером уже не симпл.

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

Ты дебил или махозист?

Мудак он, воинствующая модификация и того и другого.

Anonimous безобидно хейтит CL выдавая тексты которые никто не читает. Воспитанный, людей грязью не поливает.

Этот махровый Практик с большой буквы :) Тут не до расшаркиваний, он «Дело делает».

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

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

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

ctags разве умеет в references?

Почитал мануал про ctags. Вместо нормальной поддержки препроцессора увидел набор костылей. Хоть и не видел rtags, думал как раз про то, что правильные инструменты должны основываться на clang, к-рый есть аналог семантической базы Скалы. Единственный способ прочитать исходник на Си - это имитировать процесс сборки, в частности, задать для каждого файла именно те дефайны, которые задаются при сборке. Соответственно,можно прочитать не исходник на Си вообще, а исходник с этими конкретными дефайнами. Си - это как параллельные миры у Ричарда Баха, они взаимосвязаны, но каждый из них - отдельный. Соответственно, по-хорошему правильно работать со всеми конфигруациями проекта, имеющими разные наборы дефайнов, и переключаться от одного к другому. Каждое исправление должно проверяться на всех нужных пользователям конфигурациях (наборах дефайнов).

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

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

А не решает ли эту проблему введение метода tailRecM в Cats? Если это не так, какие монады могут быть эффективно реализованы в F# но не в скале?

Кстати в F# ведь нет higher-kinded types и monad transformers сделать не получится?

Это я о другом. О том, что while можно по-разному раскрывать для разных монад. Можно в общем виде через bind, а можно сделать частную оптимизацию без bind, например, для Reader и State.

HKT в F# нет, впрочем, его много где нет, в том числе, в Rust. Последний с первого взгляда записался в число моих любимых языков.

Касательно monad transformers, по-моему они нормально выглядят только в Haskell. В остальных языках - это будет страх и ужас. Примерно как пытаться реализовать type classes через Scala implicits с тем же эффектом :)

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

А кстати, касательно Dotty, computation expressions вполне могут относиться к тому, что называется Effects в списке Features, но это только предположение

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

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

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

HKT в F# нет, впрочем, его много где нет, в том числе, в Rust.

Как будто что-то хорошее. HKT в расте многие хотят и какие-то обсуждения на эту тему есть, но дело движется медленно.

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

Emacsy — проект и LitProg среда

вот, недавно наткнулся:

отсюда

в ту же кучу: Literate DevOps обучающее видео гитхаб

тезис#№1 можно IDE для лиспа или ЯРа устроить по аналогии

тезис#№2 инсталятор делать полуавтоматически в духе Literate DevOps

тезис#№3 потом взять например guile-skribilo и переписать 1 в этой LitProg среде (Guile уже есть в Emacsy)

тезис#№4 дописывать нужную семантику как наборы DSL в LitProg среде

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

https://common-lisp.net/project/cmucl/doc/cmu-user/compiler-hint.html#htoc186

Вот и тут пишут:

Access of arrays that are not of type simple-array is less efficient, so declarations are appropriate when an array is of a simple type like simple-string or simple-bit-vector. Arrays are almost always simple, but the compiler may not be able to prove simpleness at every use. The only way to get a non-simple array is to use the :displaced-to, :fill-pointer or adjustable arguments to make-array. If you don't use these hairy options, then arrays can always be declared to be simple.

Because of the many specialized array types and the possibility of non-simple arrays, array access is much like generic arithmetic (see section 5.11.4). In order for array accesses to be efficiently compiled, the element type and simpleness of the array must be known at compile time.

Короче без бенчей, сказать определённо нельзя. Т.к. я не понимаю как филл-поинтер может мешать производительности.

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

den73>

Давайте вернёмся к теме: кто-нибудь хочет сделать библиотеку, содержащую слой переносимости для извлечения инфы о типах и декларациях для разных реализаций CL? Или может быть кто-нибудь знает о такой?

ctags разве умеет в references?

в literate programming среде, типа noweb автоматически генерируется типа такого:

.... Identifiers

Knuth prints his index of identifiers in a two-column format. I could force this automatically by emitting the \twocolumn command; but this has the side effect of forcing a new page. Therefore, it seems better to leave it this up to the user.

already_warned: U1, U2, D3, U4, U5 ...

.... <variables of the program>: U1, D2, D3, D4, D5, D6, D7, D8

Identifiers

j_prime: U1, D2, U3, U4 mult: D1, U2, U3 ....

... <Write statistics for file>: U1, D2

Indentifiers

argc: D1, U2, U3 argv: D1, U2, U3, U4 ...

то есть, с палками и верёвками, на древнем noweb — задача уже решена.

если

а) исходники переписать в literate programming виде

б) IDE должна делать что-то подобное, «за кадром»

например, если взять skribilo на Guile как literate programming tool, или какое-то litprog средство на Common Lisp (например, обзор, также интересная публикация про L), или тот же Emacs org-mode

то есть, основная идея: Litprog средство должно работать с исходниками не в виде plain text как тот же noweb, а со структурированными S-выражениями — как в skribilo, racket scribe, org-mode

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

то есть, тащем-та как offline tool — это уже вполне себе есть в literate programming tools, том же noweb. есть некоторые, которые работают с S-выражениями.

как там с инкрементальностью — самому интересно, конечно же.

то есть, чтобы было не offline, а online и использовало не файлы, а какие-то inmemory DB на S-выражениях.

ЕМНИП, ничего готового такого вот нету, но можно допилить в этом направлении.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.