Clojure - наиболее захайпованный, вот и все. Никто там особо Java не использует, все пишут свои велосипеды, причем кривые. Язык является смесью кривых костылей вследствие JVM, той части стандартной библиотеки CL которую Рич Хики осилил реализовать(многие полезные вещи, да и главные основные даже - не осилил), и каких-то упориновых взглядов на Ъ фп, абсолютно непрактичных, даже менее практичных чем в настоящих Ъ ФП(ML, Haskell), всеобъемлющей тормознутости, и адском сракотане в плане отладки.
Racket и прочее - ресерч проекты, использующиеся максимум для обучения студентов. В быту бесполезны.
CL - наиболее практичный, доступный и развитый из всех трех, с самыми навороченными компиляторами, с кучей библиотек, включая доступ к дотнету (а в коммерческих реализациях или в ABCL - и к Java тоже), и вообще чему угодно.
Потому что это CLTL2. Он понятия не имеет как устроен вывод типов в SBCL.
А кто имеет понятие? Естественно SBCL.
CL-USER> (defmacro foo (&environment env) env)
FOO
CL-USER> (let* ((x 123) (y x)) (foo))
; in: LET* ((X 123) (Y X))
; (Y X)
;
; caught STYLE-WARNING:
; The variable Y is defined but never used.
;
; compilation unit finished
; caught 1 STYLE-WARNING condition
#S(SB-KERNEL:LEXENV
:FUNS NIL
:VARS ((Y . #<SB-C::LAMBDA-VAR :%SOURCE-NAME Y {1003E80723}>)
(X
. #<SB-C::LAMBDA-VAR
:%SOURCE-NAME X
:TYPE #<SB-KERNEL:NUMERIC-TYPE (INTEGER 123 123)>
:FLAGS (SB-C::DELETED) {1003E80633}>))
:BLOCKS NIL
:TAGS NIL
:TYPE-RESTRICTIONS NIL
:LAMBDA #<SB-C::CLAMBDA
:%SOURCE-NAME SB-C::.ANONYMOUS.
:%DEBUG-NAME (SB-C::&AUX-BINDINGS (SB-C::LAMBDA-VAR))
:KIND :ZOMBIE
:TYPE #<SB-KERNEL:BUILT-IN-CLASSOID FUNCTION (read-only)>
:WHERE-FROM :DEFINED
:VARS (Y) {1003E80E93}>
...
Но я еще раз повторюсь, что нижележащий язык в макросах как правило не нужен, и типизация его тем более. Типизация и метапрограммирование вообще не особо совместимы.
inb4, «Переносимый UI» в жопу никому нахер не сдался, кроме тех комплюхтерщиков, которые предпочитают сидеть на линуксе, а программы для клиентов писать виндовые. Но таким надо визин от красноглазия закапывать почаще, и помнить что они для клиентов программы пишут а не для развлечения. Все вещи реализующие «переносимый UI» это либо ад и сракотан типа Electron, который из себя тупо представляет веб-браузер на стероидах, либо говно которое выглядит как говно и работает как говно, потому что является говном и нигде нормально не работает кроме м.б. линуксов, и кроме них же выглядит чужеродно и всрато (GTK, Tk и Qt всякие)
Если это, то в каком Линуксе оно есть? Я её даже в Debian не вижу.
«Переносимый UI» в жопу никому нахер не сдался
Сейчас импортозамещение и санкции. Соответственно, программы должны работать, как минимум на Windows (так как не все рабочие места возможно перенести) и Астре (у большинства пользователей).
помнить что они для клиентов программы пишут а не для развлечения
Именно так. Сейчас даже 1С клиента для Линукса запилил.
Все вещи реализующие «переносимый UI» это либо
Вот Racket GUI и является исключением не попадающим ни в одну из этих двух категорий.
Метапрограммирование, запомни, нужно для того, чтобы приспосабливать инструмент - то есть язык программирования, под задачу, а не для того чтобы с типизацией дрочиться.
Вынесу из одного чата, где я недавно это обсуждал, в частности
в Java и C# метапрограммирование пытаются пропихнуть средствами GraalVM и PostSharp, и где-то это даже используется, но получается это адски черезжопно по той простой причине, что нормальное метапрограммирование возможно только в лиспе. В C# и Java - слишком много самого_языка, и во-первых оперировать им ты задолбаешься(сложные языки усложняют правило оперирования ими - дохерища всяких ключевых слов, специальных corner-case правил, и я это еще не говорю про типизацию - тут кстати можешь посмотреть как делается составление AST в лиспе у меня в либе и там же в C#), а во-вторых когда ты пишешь свое расширение языка под задачу, или доменно-специфичный язык под задачу - то тебе часто термины нижележащего языка нахер не всрались.
Не всрались в каком плане. Вот допустим у нас в некоем абстрактном мета-C# есть возможность написать язык для оперирования бизнес-правилами ипотечного кредитования(от которых в США можно повеситься). У этого гипотетического доменно-специфичного языка LQL будут ключевые слова loan, fico, reject и прочее. Прямо аки у SQL ключевые слова table, select, и так далее.
Но так как мы его пишем на гипотетическом мета-C#, то нам придется каким-то образом обрабатывать термины C# в этом языке, и пропихивать их в этот язык, хотя они там в жопу не сдались. Например в C# есть ключевое слово class. И че с ним делать? На кой хер нам этот class и вообще это ООП если мы хотим в нашем условном LQL сделать так чтобы class значил класс заема в терминах ипотечной торговли? То есть мы не можем нормально встроить этот наш DSL в наш мета-C# получается. Поэтому никакого мета-C# и нету(PostSharp не считается, потому что это говно и костыли), а есть говноинтерпретаторы конфигов на XML, потому что вот у XML, никаких таких ограничений нет, это тупо древовидная структура, семантику которой ты определяешь сам. Что собственно и делается постоянно в энтерпрайзе.
Но так как мы его пишем на гипотетическом мета-C#, то нам придется каким-то образом обрабатывать термины C# в этом языке, и пропихивать их в этот язык, хотя они там в жопу не сдались. Например в C# есть ключевое слово class. И че с ним делать?
Не понял. В реальном CL никто не мешает внутри DSL дать другое значение ключевым словам go и if. Что мешает в гипотетическом мета-C# внутри DSL переопределить class?
А там, где нет проблем, у пользователей нет Линукса. Чему радуешься? Тому, что отсутствие переносимого GUI у CL не так мешает? Кстати, а на Линуксе какой нынче актуальный GUI? cl-cffi-gtk два года как заброшен… cl-gtk4?
ЛОЛ, я же говорю ты не понимаешь как работает лисп.
Это как раз не как в лиспе. Это как в ASP.NET - в Razor, Blazor и прочее - это называется внешний DSL, для которого построен отдельный лексер, отдельный парсер, и отдельный компилятор и/или интерпретатор.
А по-другому никак! Потому что class в C# ты не переопределишь без переопределения работы компилятора. А компилятор C#, как и большинства современных ЯП работает следующим образом - там ФИКСИРОВАННАЯ грамматика, причем ОЧЕНЬ сложная и контекстно-зависимая, поэтому там РУКАМИ написан хитровыебанный парсер, РУКАМИ написан не менее сложный лексер с обратной связью от парсера, и все такое. И ключевое слово типа class ты там просто так не переопределишь, потому что тебе придется менять грамматику и перехерачивать парсер с лексером(и это, для КЗ-грамматик, да и вообще для любых грамматик, это не вопрос «одну функцию написать»(inb4 макросы в лиспе), а вопрос переопределения всей схемы построения дерева анализатором).
Ключевое слово in в C# в LINQ переопределено.
LINQ это часть C#, але. Это никакой не пример метапрограммирования.
Потому что class в C# ты не переопределишь без переопределения работы компилятора.
Так в CL мы также переопределяем работу компилятора. От компилятора требуется только распознать начало макроса и передать в тело макроса поток литер.
LINQ это часть C#, але. Это никакой не пример метапрограммирования.
Этот подход возможен в любом метапрограммировании. LING распознаётся по слову from. Можно добавить конструкцию macro, позволяющую создавать новые слова и будет аналогично
macro lql(Stream code) { ... }
lql здесь макрос читает произвольный синтаксис с class имеющим другое значение;
Да тебе не нужна типизация блеать, нижележащего языка, в твоем DSL приспособленном под задачу, алё. Она тебе там только МЕШАЕТСЯ.
Это одна из причин почему Template Haskell или макросы Scala или Rust такое говно, и ими пользоваться вообще нахер невозможно кроме совсем простеньких кейсов(аля циклы поудобнее писать, или прости г-ди printf в compile-time раскрыть в последовательность print)
Вот где здесь и на какой хер нужна типизация нижележащего языка? Ты понимаешь, что тут работается с объектной системой дотнета, которая вообще совершенно отличается от ООП в лиспе(хотя я там делаю связку потом, конечно, но это про другое). И вот эта функция - она вызывается в зависимости от типа объекта дотнета в рантайме. Тут твоя типизация твоего всратого Racket, будь это написано на Racket - не сдалась нахер вообще от слова совсем.
И вот подавляющее большинство настоящего(inb4 Production Quality) метапрограммирования - оно такое. Оно про то, чтобы делать что-то не относящееся к самому базовому языку.
Так в CL мы также переопределяем работу компилятора. От компилятора требуется только распознать начало макроса и передать в тело макроса поток литер.
Ты не понимаешь вообще чтоли? В CL ты пишешь одну сраную функцию времени компиляции, ВСЁ. И она автоматически подставляется при транскрипции правил компилятора. В C# тебе для каждого ключевого слова придется перепидорашивать ВСЁ НУТРО КОМПИЛЯТОРА.
Этот подход возможен в любом метапрограммировании. LING распознаётся по слову from.
Это не метапрограммирование, это часть C#
Можно добавить конструкцию macro, позволяющую создавать новые слова и будет аналогично
Блеать какой ты упоротый а. НЕТ, НЕЛЬЗЯ. Иди почитай сорцы компилятора C#, и вообще про грамматики, парсеры и компиляторы, начиная там хотя бы со сраного Dragon Book.
Там нельзя менять синтаксис. Только сопоставлять уже разобранный. Впрочем, как и в defmacro. Сделать через него макрос типа (my-macro f[x] = g(x), 4) не получится. Потому что скобки и запятая уже определены.
Никто не мешает в любой из них добавить аналог set-dispatch-macro-character. Думаю, не хотят, так как тогда слишком легко будет «творить дичь» (по твоему определению).
А по-другому никак! Потому что class в C# ты не переопределишь без переопределения работы компилятора. А компилятор C#, как и большинства современных ЯП работает следующим образом - там ФИКСИРОВАННАЯ грамматика, причем ОЧЕНЬ сложная и контекстно-зависимая, поэтому там РУКАМИ написан хитровыебанный парсер, РУКАМИ написан не менее сложный лексер с обратной связью от парсера, и все такое.
и что такого в грамматике шарпа, что там парсер меняет этап лексического анализа всерьез? то есть парсер должен менять правило для лексем, а это странно
в классическом компиляторе предопределенные слова меняются легко. если они есть идентификаторы.
когда лексер выделяет из потока идентификатор, например foo или class, он должен быстро определить, не является ли идентфикатор предопределенным. например class. тут либо лезут в мапу предопределенных идентфикаторов навроде c++ std::map<string, symbol>, либо делают через хеш таблицу.
подменить, добавить, удалить любую пару слово->лексический символ можно через мэпу влегкую. можно добавлять и новые лексические символы, расширяя грамматику, вот что не рекомендуется - удалять старые, ибо сломается обратная совместимость.
карочи, добавить новые лексемы вообще не проблема, они не главное, главное чтобы в парсер добавлялись новые семантические правила, для которых эти лексемы нужны.
А почему нет-то. Вот макросы, например, писать можно, прям как в коммон лиспе. В питоне и руби так нельзя, а в коммон лиспе и кложе можно. И в схеме можно, хотя внутре это и устроено по-другому.
Наверное, всё-таки что-то есть между ними общее, а?
освой вопрос для начала. в грамматику добавляются не правила «интерпретации слов», а грамматическое правило. выбор граматического правила в граматиках LL1 осуществляется по первому лексическом символу. если этот символ - «class_sy» какой-нить, то выбирается процедура разбора правила «class».
в любой компилятор написаный по учебнику, легко вставить новые лексемы, и новые служебные слова, и ввести даже новые правила, если этим конечно озаботится. просто надо ввести в язык синтаксис правил «добавления правил».
Когда ты в грамматику добавляешь правило интерпретации слова class в новом контексте - это по-твоему, как делается?
ручками это делается и головой, а не «волшебством лиспа», как у тебя вечно.
у лиспа тваво грамматика есть. это грамматика S-выражений.
точечная пара - это правило, цитирование, список атомов в скобочках через разделители - это тоже правило. числа, строковвые константы и так далее…
не всякая строка текста является S выражением. поскольку чтобы быть таким выражением, строка должна удовлетворять грамматике s выражений… которой у тебя нет. гы.
и еще - про «отсутствие грамматики» у лиспа - это лютый треш из попсовых книжек евангелистов. грамматика там есть, но она минимальна.
у лиспа «сложные грамматические правила», навроде классического
if <boolean_expression> <statement>
else <statement>
спрятаны внутри интерпретатора, как «стандартные формы», или как оно там у вас называется. с одной стороны это хорошо, поскольку обеспечивает минимализм входной грамматики, с другой плохо, поскольку все равно излагаются в описании «стандратных форм», они тоже имею правило, но это не правило грамматики, а правило данной стандартной формы… короче поменяли шило на мыло. из грамматики правило убрали, и перенесли в другое место.
без понятия?.. ты ж главный спец…
я нарисовал неправильную точечную пару. лисп твой ругается. это я первый попавшийся взял
Unhandled SB-C::INPUT-ERROR-IN-LOAD in thread #<SB-THREAD:THREAD "main thread" RUNNING
{10015B0003}>:
READ error during LOAD:
Nothing appears after . in list.