LINUX.ORG.RU

Ворос по раскрытию макросов

 


2

5

Допустим, я пишу новый, «более лучший лисп»(ТМ). Хочу реализовать простенькую макросистему. Мой экспандер анализирует исходник, находит макровызовы, раскрывает их, а дальше возникает вопрос. Что если код, в который раскрывается макрос, содержит еще один макровызов? Его нельзя раскрыть на данном этапе, поскольку еще нет разрешения имен. Значит, мне надо заэвалить все, а раскрывать когда? Скорей всего, когда данный вызов потребуется. Заэвалил, запускаю снова экспандер. вроде норм. Но что если результат 2 вызова требуется уже при первом выполнении? Заставлять пользователя явно указывать, в какой фазе раскрывать каждый макрос, или как?

Мне кажется, ты плохо понимаешь о чем пишешь. Во-первых, нет никакой разницы между раскрытием макроса и рекурсивным вызовом экспандера от макрораскрытия. Во-вторых, «более лучший лисп» не должен быть основан на макросах. Но если уж тебе нужны макросы, то прочитай как их реализовать правильно:

Expansion-Passing Style Beyond Conventional Macros, R.K. Dybvig, D. P. Friedman and C. T. Haynes

Лучше все же копать в сторону fexpr'ов. Не слушай анонимуса, он сам ничего не понимает.

Моя лекция о макросах и fexpr'ах

komputikisto
()

Что если код, в который раскрывается макрос, содержит еще один макровызов? Его нельзя раскрыть на данном этапе, поскольку еще нет разрешения имен.

Не раскрывать, но потом пройтись еще раз. И так до тех пор, пока макросов больше не останется.

Кстати, функция, которая делает первое в Common Lisp называется «macroexpand-1», а которая делает второе - «macroexpand».

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

macroexpand раскрывает форму, а потом если голова является макросом, раскрывает и его. В стандарте CL нет функции, которая бы раскрывала все вложенные макросы. Про macroexpand-1 все верно.

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

Функция macroexpand - не полный экспандер. Конечно, Common Lisp раскрывает и такие формы, просто в его стандарте нет доступа к такому экспандеру в виде функции. Чтобы ее написать нужен code walker, т.к. она должна отличать код от данных. Например, нельзя на раскрывать ничего внутри quote.

komputikisto
()

Его нельзя раскрыть на данном этапе, поскольку еще нет разрешения имен.

В смысле? У тебя раскрытием занимается некий обработчик, который по очереди обрабатывает формы.

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

(defmacro (foo x) `(print ,x))
(defmacro (bar x) `(foo ,x))

(bar 1)

При раскрытии (bar 1) превращается в (foo 1). Затем подаётся (foo 1) на вход этого же алгоритма.

В теле макрос или в голове — неважно. Если экспандер может раскрыть

(progn
  (foo 1)
  (foo 2))

То он может раскрыть и

(defmacro (bar x y)
  `(progn
     (foo ,x)
     (foo ,y)))

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

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

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

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

Никаких оправданий выбора интерпретации вместо компиляции быть не может в принципе

  • Eval не нужен?
  • REPL не нужен?
  • Live coding не нужен?

JIT это что? Компиляция или интерпретация?

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

Это, собственно, по-моему, частный случай интерпретации. Код исполняется не пословно, а кусками. В интерпретаторе, же, все равно каждый примитив транслируется в машкод. А тут не примитивы, а сразу целые куски, но суть та же.

terminator-101
() автор топика
Ответ на: комментарий от Kuzy

Eval не нужен?

Убивать

REPL не нужен?

Каким оно боком к интерпретации?!?

Live coding не нужен?

Каким оно боком к интерпретации?

JIT это что? Компиляция или интерпретация?

Если это JIT для и без того очень низкого IR - то пусть живет. Если JIT у тебя проходит весь путь от исходного языка, то это интерпретатор и за такое надо убивать.

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

Угу, как и eval. Да че там мелочиться, интерпретаторы не имеют отношения к интерпретации, это все происки спецслужб.

terminator-101
() автор топика
Ответ на: комментарий от terminator-101

Ну расскажи, убогий, где ты нашел интерпретатор в OCaml REPL, или в ghci, или, хуже того, в Cling.

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

Вообще, компиляция - частный случай интерпретации. Ибо проекции Футамуры. Я лично согласен с мнением автора приведенной ниже статьи, что компилируемый Лисп - уже не Лисп, т.к. теряется главное свойство - гомоиконность. Хотя это зависит от того, как далеко преобразование первоначальной программы зайдет. Ну а другие языки могут быть компилируемы или интерпретируемы - это не имеет определяющего значения.

Alexander Burger. “Pico Lisp. A Radical Approach to Application Development.”

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

А бабушка - это дедушка без яиц. Это ты потерял главное свойство человека - разум. Потеря гомоиконности из-за компилируемости - это win

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

Автор Pico Lisp - тот еще на всю тупую бестолковку упоротый уебан, который не понимает, зачем гомоиконность вообще нужна.

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

Ты вообще на Лиспе программировал? В любой момент времени программу можно остановить, просмотреть стек, в котором будут содержаться ссылки на еще не вычисленные части программы в ПЕРВОНАЧАЛЬНОМ ВИДЕ. Комоиконность - это свойство всей системы, а не только структур, которые подаются на вход вычислителю.

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

Согласен, что автор Pico Lisp не авторитетен. Но это не уменьшает значимости аргумента.

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

Куда мне до тебя! Я даже не знаю, что такое dwarf. Погуглил, оказалось это человек низкого роста.

Поясню на примере. Если лямбда выражение перевести в форму с числами De Bruijn, и редуцировать, то каким образом восстановить первоначальные имена? Перевод в нотацию De Bruijn - это и есть компиляция.

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

то каким образом восстановить первоначальные имена?

Записать их в dwarf, придурок. Вместе с координатами всех исходных выражений.

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

Это разве не примеры JIT, который «проходит весь путь от исходного языка»?

// Читай уже удаленные, если материшся.

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

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

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

Чтобы удаленные читать, надо зарегистрироваться.

Нет, это не пример JIT. Это компиляция статичных выражений, каждое выражение - рассматривается как отдельный unit.

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

И кому это она «должна», если платить за эту сомнительную радость приходится тормозами убогого интерпретатора?

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

Многие вещи в языках программирования противоречат друг другу. Например, крайне трудно, если не невозможно, совместить unwind-protect и call-with-current-continuation. Я утверждаю, что компиляция противоречит гомоиконности. Я у тебя твой компилятор не отбираю. Просто тогда не стоит называть компилируемый лисп гомоиконным или полностью рефлективным. Если гомоиконность и рефлективность - это то, что мы хотим от Лиспа, то тогда только интерпретация.

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

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

Но лисп гомоиконный и при этом полностью рефлексивный и компилируемый.

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

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

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

Затем, что рефлексия времени компиляции - макросы, являются не единственным методом метапрограммирования в Лиспе. Есть еще модель реификакции/рефлексии, которая основана на работах Brian Cantwell Smith, о которой я подробно рассказываю в лекции (и в еще одной теме про макросы тут). Так вот там в любой момент времени все регистры интерпретатора Лиспа должны содержать только объекты Лиспа. Это так в модели которую я разрабатываю. Тебе нравятся макросы и компиляторы - я не против! Тут, как я понял, принято обвинять всех и каждого в неосиляторстве. Мне это не интересно. Прекращаю с тобой дискуссию.

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

Так вот там в любой момент времени все регистры интерпретатора Лиспа должны содержать только объекты Лиспа.

Именно так во всех лиспах дело и обстоит.

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

Нет, в какой-нибудь SECD-машине это не так. Там в регистрах кроме частей программы еще и инструкции управления машиной, которые не обязательно являются объектами Лиспа. Ты сам компилатор писал?

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

Я конкретный вопрос задал - какая польза от такой модели? Ни ты, ни пиколиспанутые на этот простой вопрос ответа дать не осиливают.

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

Польза в переопределении всего в рантайме. В таком лиспе нет различий меду поведением определенным программистом и встроенным. Нужно ли так поступать - переопределять язык в рантайме - вопрос дискуссионный, но эта идея заслуживает изучения, т.к. продвигает наше понимание языков программирования. Как далеко можно зайти? Где пределы изменчивости? Это все важные научные вопросы. Pico Lisp - не показатель. Я эту ссылку привел, т.к. солидарен с автором, что Lisp в своей сути интерпретируем. Во многом другом я с ним не солидарен, например, в предпочтении dynamic scope.

komputikisto
()

Допустим, я пишу новый, «более лучший лисп»(ТМ).

Проснись, Маня, ты обосралась

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

дык ты и есть неосилятор

Да, не осилил я дискуссию с таким мыслителем как ты.

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

Проснись, Маня, ты обосралась

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

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

SECD-машина - это уже детали реализации. С точки зрения самого лиспа никакой SECD-машины нет.

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

Польза в переопределении всего в рантайме.

Ну так вроде во всех нормальных лиспах можно все переопределять в рантайме. При этом эти лиспы остаются компилируемыми.

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

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

terminator-101
() автор топика
Ответ на: комментарий от terminator-101

А какой прок от лексического скопа в интерпретируемом языке?

Lexical/dynamic scope никакого отношения к компиляции/интерпретации не имеет. Язык с dynamic scope может быть компилируемым. Dynamic scope в Лиспе - это ошибка Джона Маккарти. Либо Маккарти решил сделать как проще, либо не увидел различия между его схемой и лямбда-исчислением, в котором это сделано правильно. В 70-х было много обсуждений этой проблемы. В статье «The FUNARG Problem Explained» Joseph Weizenbaum пишет, что многие разработчики реализаций лиспа не понимают в чем состоит проблема с dynamic scope. Удивительно, что лексические замыкания не присутствовали и в Python изначально. Кстати, они там сейчас реализованы из рук вон как плохо.

Проблема заключается в том, что dynamic scope не соответствует ментальной модели языка (т.е. не все выражения которые мы можем придумать работают как полагается). Пример, где не работает dynamic scope, можно найти в статье (ссылка ниже) на стр. 20. Мне лень его печатать.

Guy Lewis Steele, Jr. and Gerald Jay Sussman. «The Art of the Interpreter or, the Modularity Complex (Parts Zero, One, and Two)»

komputikisto
()
Ответ на: комментарий от terminator-101

В рефлективных лиспах все есть текст.

Строго говоря Лисп абстрагирован от текста, он вычисляет формы. И Pico Lisp - не рефлективный Лисп.

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

Где пределы изменчивости?

Нигде. Тут основной момент — это ответ на вопрос, что такое программа. Программа - не есть текст ее. Текст программы никакого отношения к ней не имеет. Программа — это абстрактная машина, никакого отношения к породившему ее тксту не имеющая. Поэтому, ничто не мешает ей манипулировать своим исходником, как и любым другим текстом. Главная причина того, почему программирование скатилось в такое дерьмо — это непонимание этой фундаментальной вещи. Абстрагирование программы от текста программы есть основа понимания процесса.

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