Существуют ли макросы для преобразования всей программы в Лиспе или Схеме? - PullRequest
6 голосов
/ 21 января 2011

Я видел один ответ Как Lisp позволяет вам переопределить сам язык? Вопрос переполнения стека (ответил Ноа Лавин):

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

После прочтения этого мне интересно узнать, существуют ли "макросы, преобразующие целую программу" в Lisp или Scheme (или некотором другом языке).

Если нет, то почему?

  • Это бесполезно и никогда не требуется?
  • Та же самая вещь может быть достигнута другими способами?
  • Невозможно реализовать это даже в Лиспе?
  • Возможно, но никогда не пробовали или не реализовывали?

Обновление

Один вид использования например,

Как в коде stumpwm вот некоторые функции в разных исходных файлах lisp использует динамическую / глобальную переменную defvar * screen-list *, которая определена в primitives.lisp , но используется в screen.lisp , пользователя. lisp , window.lisp . (Здесь у каждого файла есть функции, класс, переменные, связанные с одним аспектом или объектом)

Теперь я хотел определить эти функции под замыканием, где * screen-list * переменная доступна в форме let, она не должна быть динамическая / глобальная переменная, но без перемещения всех этих функций в одно место (потому что я не хочу, чтобы эти функции потеряли место от их связанный файл) Так что эта переменная будет доступна только этим функциям.

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

Обратите внимание, один из способов может быть реализовать и использовать некоторый макрос defun_with_context для defun, где первый аргумент контекст, где let, определяют переменные flet. Но помимо этого это может быть достигнуто читателем-макросом как Ватин и Гарет Рис ответили.

Ответы [ 7 ]

5 голосов
/ 21 января 2011

Вы процитировали слова Ноа Лавина:

Макрос может взять только одно поддерево вашего кода и сгенерировать одно поддерево для его замены

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

См. Раздел Hyperspec , раздел 2.2 и функцию set-macro-character.

5 голосов
/ 01 февраля 2011

В Racket вы можете реализовать макросы, преобразующие всю программу.См. Раздел документации о определении новых языков .Есть много примеров этого в Racket, например, ленивый язык и Typed Racket.

2 голосов
/ 21 января 2011

От макушки головы, несколько подходов:

Во-первых, вы можете. Норвиг указывает , что:

Мы можем написать компилятор как набор макросов.

так что вы можете преобразовать всю программу, если хотите. Я видел это редко, потому что обычно пересечение между «вещами, которые вы хотите делать с каждой частью вашей программы» и «вещами, для которых вам нужны преобразования типа макрос / AST», является довольно небольшим набором. Одним из примеров является Parenscript , который преобразует ваш код на Лиспе («расширенное подмножество CL») в Javascript. Я использовал его для компиляции целых файлов кода на Лиспе в Javascript, который предоставляется напрямую веб-клиентам. Это не моя любимая среда, но она делает то, что рекламирует.

Другая связанная функция - это «совет», который Йегге описывает как :

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

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

1 голос
/ 21 января 2011

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

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

0 голосов
/ 26 января 2011

В Common LISP, по крайней мере, вы можете обернуть формы верхнего уровня в PROGN, и они все еще сохраняют свой статус как формы верхнего уровня (см. CLTL2, раздел 5.3 ).Следовательно, ограничение макроса, генерирующего единственное поддерево, не является большим ограничением, поскольку оно может обернуть любое количество результирующих поддеревьев в PROGN.Это делает макрос всей программы вполне возможным.

Например

(my-whole-program-macro ...)

= expands to =>

(progn
  (load-system ...)
  (defvar ...)
  (defconstant ...)
  (defmacro ...)
  (defclass ...)
  (defstruct ...)
  (defun ...)
  (defun ...)
  ...
  )
0 голосов
/ 21 января 2011

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

0 голосов
/ 21 января 2011

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

Есть читательмакросы, они преобразуют входные данные «как они читаются» (или «перед чтением», если хотите).Я не проводил много масштабных хакерских операций чтения-макроса, но я написал некоторый код, позволяющий (в основном) читать elisp sourec в Common Lisp, с довольно небольшими различиями в синтаксическом сахаре между ними.

...