LINUX.ORG.RU

Макросы + история успеха

 , , ,


2

3

Комрады. Сабж собственно - чем макросы racket лучше/хуже макросов cl и наоборот?

Второе - где, какой диалект и для чего (лиспа) вы применяете?

Всем спасибо.

З.Ы.: интерес к этому так как начали писать с коллегами большую система на racket. Стало интересно. Делаем just for fun

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

Тут нет никакого «специального синтаксиса»

Ты как-то определись, или it имеет особое поведение против чего ты протестуешь, или это обычный символ и всё так и должно работать.

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

А чем так кардинально racket'овский syntax отличается от s-expr? По сути только тем, что имеет несколько больше информации об атоме.

Тебя же не смущает, что массивы, хэш-таблицы, структуры, объекты в CL — атомы, со своими функциями/методами работы с ними, а не S-expr / cons-ячейки, с которыми можно работать с помощью cons/car/cdr/тысячами-функций-для-работы-со-списками?

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

Так будет?

Если loop for … collect … имеет семантику (let ((it …)) …), то да. В racket в стандартной библиотеке нет loop.

Можно проще: (aif 1 (aif 2 it nil) nil)

Твоя версия вернёт 1. aif здорового человека — 2.

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

а делает полезными лишь для небольших преобразований базового языка,

Никто не мешает сделать syntax->datum + жуткое преобразование над списками + datum->syntax.

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

Можно проще

Нельзя, мне интересно именно посмотреть на поведение макроса который задаёт свой язык.

В racket в стандартной библиотеке нет loop.

Именно поэтому и интересно, как оно работает с неизкоробочным DSL.

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

Ты как-то определись, или it имеет особое поведение против чего ты протестуешь, или это обычный символ и всё так и должно работать.

Нет, это ты лучше вспомни, что такое quote и как вообще работает Eval. =)

С точки зрения CL (да и Scheme) it — это в первую очередь символ, будет ли он вычислен (использован как имя переменной) или останется просто символьным литералом, зависит от того, заквочен он или нет. Точно так же, как интерполяция строк в других языках, например:

fun main() {
    aif({ 4 }, {
    	println("it is $it") // similar to (println `(it is ,it))
    }, {});
}

https://ideone.com/XFvAqU

Что в SICP, что в PAIP есть примеры простеньких интерпретаторов, там и quote разбирается, ЕМНИП.

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

С точки зрения CL (да и Scheme) it — это в первую очередь символ

Нет никакой «точки зрения» CL, есть язык, который задаётся макросом. Он похож но CL, но it имеет особый смысл. То, что на базовом уровне это реализуется на символах - дело десятое, можно с тем же эффектом строки использовать.

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

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

И это неправильный ответ. Numba или GDScript вполне предоставляют возможность статической типизации и компиляции, что серьезно упрощает задачи разработки. Нелогичность, действительно, существует - я уже здесь делал обзор проблем питона, из цитат собрал статью: https://habr.com/ru/post/481782/

Однако, статья не описывает преимущества питона. То, что ты решительно забываешь - это простота читаемости кода. У лиспа есть тенденция к созданию write-only-software, когда кодер предпочитает переписывать косок кода заново, чем пытаться понять, что же в нем написано. Сама идея питона как читаемого языка замечательна, но эталонная реализация, CPython, ужасна, поскольку изначально создавалась без тшательного проектирования и развивалась методом добавления фич. Из-за чего и возникло такое число альтернатив питона разной степени совместимости с CPython.

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

Нет никакой «точки зрения» CL, есть язык, который задаётся макросом. Он похож но CL, но it имеет особый смысл.

Если бы ты написал и использовал свой eval, можно было бы говорить о языке, а так ты лишь преобразуешь одно S-выражение в другое и используешь CL'ный eval/compile, чтобы его вычислить, так что не надо тут про язык.

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

Если бы ты написал и использовал свой eval

Зачем мне свой eval?

(defmacro aif (test then &optional else)
  (let ((it (gensym)))
    `(let ((,it ,test))
       (if ,it ,`(subst-if ,it (lambda (x) (equal x "it")) ,then) ,`(subst-if ,it (lambda (x) (equal x "it")) ,else)))))

(aif (+ 2 2) `(it is "it"))

(IT IS 4)

Опаньки, у нас строки теперь выполняются. Ну это-то точно не CL, или как?

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

Опаньки, у нас строки теперь выполняются.

Не выполняются, ты просто подменил один атом другим до выполнения.

Ну это-то точно не CL, или как?

Конечно CL. Или по-твоему, любая макра, не описанная в стандарте, а реализованная кем-то другим — это уже не CL? Почему? Чем твой aif менее CL'ный, чем let* или loop или defclass?

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

А чем так кардинально racket’овский syntax отличается от s-expr?

Это AST, а не s-выражения

Тебя же не смущает, что массивы, хэш-таблицы, структуры, объекты в CL

Это и есть s-выражения, S-выражения в CL это любой объект лиспа. Макросы над ними и работают. Ну положим, хеш-таблички в выхлоп макроса редко кладут, но объекты - вполне.

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

Это работает не совсем как в CL, во-первых, где-то на SO есть пост по этому поводу. Во-вторых - зачем мне этот бойлерплейт там где у меня вообще нет синтаксиса racket от слова совсем? В третьих, мы тут же упремся в кучу проблем как раз с именами в том числе из-за того что схема - лисп-1.

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

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

Не до, а во время. До я сделал выражение которое делает такую подмену во время выполнения.

любая макра, не описанная в стандарте, а реализованная кем-то другим — это уже не CL?

Разумеется всё что не в стандарте, это не CL. В этом дзен макросов в принципе - возможность описания своего языка.

Чем твой aif менее CL’ный

Тем что it в нем «спецформа» которой нет в CL. Очевидно же.

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

Это AST, а не s-выражения

В чём отличия?

Это и есть s-выражения, S-выражения в CL это любой объект лиспа.

Не делай вид, что ты не понял о чём я, S-выражение — это либо атом, либо список атомов. Вопрос был про то, что перечисленный мной типы объектов являются атомами со своими «API», а не списками с cons/car/cdr, которыми представлен код, который ты обрабатываешь в макре.

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

А вот и нет. В схеме и всяких racket это уже не просто символ, а identifier некоторый.

Не суть. Суть в том, что он либо как-то интерпретирован, либо нет.

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

В чём отличия?

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

S-выражения это тупо любой объект, чо передали то и есть.

S-выражение — это либо атом, либо список атомов.

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

На уровне компилятора в CL S-выражение это любой объект вообще. Атом кстати, это все что не cons-ячейка.

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

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

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

Не до, а во время. До я сделал выражение которое делает такую подмену во время выполнения.

Молодец. Угадаешь, что выведет следующий код?

(aif (+ 2 2)
  (format t "~a~%" "it"))

Разумеется всё что не в стандарте, это не CL

А что? А всё что не в JDK — не Java?

Тем что it в нем «спецформа» которой нет в CL. Очевидно же.

В loop целый ворох «спецформ», по-твоему loop — это CL только потому, что он в стандарте?

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

либо как-то интерпретирован

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

(basic 
  (5 let i = 5)
  (10 let it = it + i)
  (20 print it)
  (30 if it < 100 goto 10)
)

Какое нам дело что это символы с точки зрения CL?

no-such-file ★★★★★
()

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

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

Угадаешь, что выведет следующий код?

Щас бы докапываться до PoC, ага. «Не суть» (С)

по-твоему loop — это CL только потому, что он в стандарте?

Да.

А всё что не в JDK — не Java?

А в Java есть макросы? Впрочем на JVM много язычков, которые не Java, да.

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

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

S-выражения это тупо любой объект, чо передали то и есть.

Т.е. AST — это S-выражение? Любой же объект.

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

Как и в Racket.

На уровне компилятора в CL S-выражение это любой объект вообще. Атом кстати, это все что не cons-ячейка.

Ну да, атом — любой объект, который не cons-ячейка. Ещё раз вопрос: почему ты считаешь, что любые объекты реализованные не через cons-ячейки — это нормально, а иметь в syntax не просто symbol, а различные более специфичные вещи (identifier, keyword, etc) — нет? При том, что структура кода остаётся всё той же: либо атом, либо список.

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

Щас бы докапываться до PoC, ага. «Не суть»

Ну ты сам сказал, что у тебя теперь строки интерпретируется. Но что-то не доинтерпретировались. =)

А в Java есть макросы?

При чём тут макросы? Почему ты их ставишь на особое место? Для CL — это штатная фича языка.

Кроме того, ты же акцентируешь внимание на наличие мары в стандарте.

korvin_ ★★★★★
()
Последнее исправление: korvin_ (всего исправлений: 1)
Ответ на: комментарий от no-such-file

Здесь — инкакого, потому что использется транслятор/интерпретатор и вызывать CL-код внутри этого Basic'а нужно будет явным способом выделяя это. aif же не более чем небольшое расширение основного языка, намного меньшее, чем тот же loop.

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

Почему ты их ставишь на особое место? Для CL — это штатная фича языка.

Потому что для Java это нештатная фича. Ты же про java спрашивал.

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

Т.е. AST — это S-выражение? Любой же объект.

В контексте «вообще» - объекты AST, да, s-выражения.

В контексте интерпретации кода макросами - AST это AST. Это метаобъекты, завязанные на конкретную интерпретацию s-выражений. В лиспе не первый раз пытаются такое впихнуть, раньше вон были F-выражения, а когда-то совсем давно M-выражения. Не прижилось en masse, потому что тупо неудобно и непрактично. Это шаг в сторону от homoiconicity.

а иметь в syntax не просто symbol, а различные более специфичные вещи (identifier, keyword, etc) — нет?

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

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

aif же не более чем небольшое расширение основного языка

Ещё раз, «не суть». Сколько нужно преобразований чтобы считать нечто бейсиком, а не лиспом? Важен сам принцип преобразований во время компиляции.

вызывать CL-код внутри этого Basic’а нужно будет явным способом

Ну, а в моём aif нужно символ it вставлять явным способом. Т.е. всё-таки это спецязык?

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

Потому что для Java это нештатная фича. Ты же про java спрашивал.

Про Java я спросил лишь про наличие отсутствие чего-то в стандартной библиотеке. Можешь взять любой другой язык и его стандартную библиотеку.

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

Да, можно довольно многое наворотить, и тот же loop — более «не CL», чем твой aif, хоть и присутствует в стандарте.

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

Это шаг в сторону от homoiconicity.

Да брось, у тебя всё равно макра будет либо иметь «минимальный» синтаксис, основываясь исключительно на cons-ячейках, и просто перестраивать их нужным образом, либо некоторые символы/кейворды будут таки иметь особое значение. Что первое, что второе есть как в Racket, так и в CL, в первом — явно, во втором — нет. Вот и вся разница.

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

Но ты же метапрограммируешь на CL, используешь его компилятор, макросистему? Или как, ты можешь просто взять и скормить исходники своего bike компилятору любого другого языка и он схавает? )

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

Всегда, когда читаю дискуссии о лиспе и схеме, представляются достопочтенные господа во фраках, с гигиенически чистыми лицами, которые за партией в преферанс и со стаканом виски мирно обсуждают последние веяния в мире Rackispeme, причём каждый на своём собственном языке, неизвестным никому из присутствующих, и долго выясняют между собой, чем S-выражения отличаются от AST, чем символ отличается от объекта и отличается ли вообще, и почему это три скобки - CL или не CL.

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

будь она сторонним пакетом (как iter, например), ничего бы не поменялось

В ракетке loop не в стандартной библиотеке и, внезапно, loop это не ракетка.

макры являются штатной фичей языка

Да, а результат их использования - нет.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от korvin_

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

Это будет синтаксис макроса а не синтаксис CL. Свой, и не зависящий от базового языка. Вот как пример - VOP из SBCL. Или defcfun из CFFI. Или LOOP. При их обработке - вообще совсем абсолютно нахрен не нужно AST CL. Потому что их синтаксис не является синтаксисом базового CL.

Но ты же метапрограммируешь на CL, используешь его компилятор, макросистему?

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

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

причём каждый на своём собственном языке, неизвестным никому из присутствующих, и долго выясняют между собой, чем S-выражения отличаются от AST, чем символ отличается от объекта и отличается ли вообще, и почему это три скобки - CL или не CL.

Ещё один всё понял.

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

Ещё раз, «не суть». Сколько нужно преобразований чтобы считать нечто бейсиком, а не лиспом? Важен сам принцип преобразований во время компиляции.

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

В общем, спор ни о чём. Для меня aif — слишком небольшое расширение для языка со штатной, интегрированной макросистемой, и называть это «языком» я бы не стал. Так же как не стал бы называть «языком лямбд» поддержку лямбд в Java 8, не стал бы называть «языком» введение try-with-resources в Java 7 и т.п. Расширение языка — да. Но «отдельный язык» — как-то слишком. =)

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

Как я уже писал…

Это не ответ на вопрос. Твой метакод на метаязыковой виртуальной машине можно скормить, например LLVM?

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

Потому что их синтаксис не является синтаксисом базового CL.

Тем не менее, тот же loop — не reader-макра, не читает char'ы из текстового потока, а работает с уже прочитанным деревом.

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

Дело не в количестве, а в степени разделения

Родной, а тогда кто решает какая степень это CL, а какая уже не CL?

У aif эта степень всё же крайне мала

Достаточная, чтобы начали визжать про то, что оно «сломано» и не работает. Оно не работает в контексте CL, а в собственном контексте «так задумано» и прекрасно работает. Вот в чём проблема вкусовщины.

называть это «языком» я бы не стал

А я бы стал, потому что CL c aif это совсем не тоже самое что просто CL. В CL нет такой языковой конструкции. Совершенно пофиг, насколько она отличается от того что есть и можно ли её сделать из того что есть.

В общем, спор ни о чём

Ясное дело, что ни о чём. Я ведь признал, что оно не будет работать. Но не потому что это символ или не символ, а потому что (aif … (basic …) принципиально не будет работать, т.к. не знает ничего про basic и как с ним поступать.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 2)
Ответ на: комментарий от lovesan

зачем код одной VM скармливать другой VM?

Тогда в чём же отличия между использование CL-VM и Racket-VM? В том, что в Racket чуть больше типизации?

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

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

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

У лиспа есть тенденция к созданию write-only-software, когда кодер предпочитает переписывать косок кода заново, чем пытаться понять, что же в нем написано.

Нет такой тенденции. Это у программистов на JS есть такая тенденция. Код на CL в крупных проектах остается простым из-за хороших возможностей для абстракции.

Из-за чего и возникло такое число альтернатив питона разной степени совместимости с CPython.

Нет никаких альтернативных питонов, их никто в реальности не использует. Все библиотеки пишутся под CPython, в т.ч. из-за обилия модулей на си.

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

Достаточная, чтобы начали визжать про то, что оно «сломано» и не работает.

Так оно и сломано.

Оно не работает в контексте CL, а в собственном контексте «так задумано» и прекрасно работает.

У него нет собственного контекста, ты его используешь в контексте CL. И вопрос изначальный был в том, как заставить его нормально работать в контексте CL. Потому что в контексте Racket оно работает. Просто и непринуждённо.

А я бы стал, потому что CL c aif это совсем не тоже самое что просто CL. В CL нет такой языковой конструкции. Совершенно пофиг, насколько она отличается от того что есть и можно ли её сделать из того что есть.

Т.е. ты любую макры, кем-то написанную, не включённую в стандарт, считаешь отдельным языком? Ок, твоё дело.

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

В racket мы завязаны на racket не только «снизу», но и сверху.

В CL макросы в конечном итоге делают sexpr->стандартный синтаксис CL. А не в конечном итоге делают произвольные преобразования sexpr->sexpr, не принимая во внимание в этом конкретном месте тот самый стандартный синтаксис и его правила, объекты и операторы.

В Racket сверху донизу syntax->syntax. То есть мы работаем со схемой всегда.

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

Потому что в контексте Racket оно работает. Просто и непринуждённо

Я что-то не вижу пруфца, о котором спрашивал (про loop).

Так оно и сломано

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

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

Разумеется. Я понимаю, что в ракетке это нет так, но в CL так.

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

В racket мы завязаны на racket не только «снизу», но и сверху.

Не вижу повода для беспокойств. В CL мы завязаны на CL также и сверху и сниху.

В Racket сверху донизу syntax->syntax. То есть мы работаем со схемой всегда.

Этот syntax отличается от sexpr практически ничем.

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

Не вижу повода для беспокойств. В CL мы завязаны на CL также и сверху и сниху.

Не завязаны, потому что мы не обязаны оперировать идентификаторами, вычисляемостью/невычисляемостью, биндингом переменных и прочими понятиями «базового» уровня интерпретации CL.

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