Макросы являются преобразователями кода.
Существует несколько способов реализации синтаксиса макроса:
Common Lisp предоставляет список аргументов макроса, который также предоставляет форму деструктуризации.При использовании макроса исходная форма деструктурируется в соответствии со списком аргументов.
Это ограничивает внешний вид синтаксиса макроса, но для многих применений макросов предоставляет достаточно механизмов.
См. Макро-лямбда-списки в Common Lisp.
Common Lisp также предоставляет макросу доступ ко всей форме вызова макроса,Макрос затем отвечает за анализ формы.Анализатор должен быть предоставлен автором макроса или является частью реализации макроса, выполненной автором.
Примером может быть макрос INFIX:
(infix (2 + x) * (3 + sin (y)))
Реализация макроса должнареализовать анализатор инфиксов и вернуть выражение префикса:
(* (+ 2 x) (+ 3 (sin y)))
Некоторые Лиспы предоставляют синтаксические правила, которые сопоставляются сформа вызова макроса.Для соответствующего правила синтаксиса соответствующий преобразователь будет использоваться для создания новой исходной формы.Это легко реализовать в Common Lisp, но по умолчанию это не предусмотренный механизм в Common Lisp.
См. синтаксис case в Scheme.
LOOP
Для реализации LOOP
-подобного синтаксиса необходимо написать синтаксический анализатор, который вызывается в макросе для синтаксического анализа исходного выражения.Обратите внимание, что синтаксический анализатор работает не с текстом, а с интернированными данными Lisp.
В прошлом (1970-е годы) он использовался в Interlisp в так называемом 'Conversational Lisp', который является синтаксисом Lisp сболее естественный язык, как поверхность.Итерация была частью этого, и затем идея итерации была перенесена в другие Лиспы (например, LOOP
Маклиспа, откуда она затем была перенесена в Common Lisp).
См. PDF на ' Разговорный Лисп 'Уорреном Тейтельманном из 1970-х годов.
Синтаксис макроса LOOP
немного сложен, и не легко увидеть границы между отдельными под-операторами.
См. Расширенный синтаксис для LOOP в Common Lisp.
(loop for i from 0 when (oddp i) collect i)
, такой же как:
(loop
for i from 0
when (oddp i)
collect i)
Одной из проблем макроса LOOP является то, что такие символы, как FOR
, FROM
, WHEN
и COLLECT
не совпадают с пакетом "COMMON-LISP" (пространство имен).Когда я сейчас использую LOOP
в исходном коде с использованием другого пакета (пространства имен), тогда это приведет к появлению новых символов в этом пространстве имен источника.По этой причине некоторые любят писать:
(loop
:for i :from 0
:when (oddp i)
:collect i)
В приведенном выше коде идентификаторы для LOOP
соответствующих символов находятся в пространстве имен KEYWORD.
Для облегчения как анализа, так и чтения имеетбыло предложено вернуть скобки обратно.Пример такого использования макроса может выглядеть следующим образом:
(iter (for i from 0) (when (oddp i) (collect i)))
аналогично:
(iter
(for i from 0)
(when (oddp i)
(collect i)))
В вышеприведенной версии проще найти подвыражения и пройти их.
Макрос ITERATE для Common Lisp использует этот подход.
Но в обоих примерах необходимо просмотреть исходный код с помощью пользовательского кода.