Читайте макросы: для чего вы их используете?
Я пытаюсь почувствовать те части Лиспа, которыми до сих пор не пользовался. Прочитанные макросы привлекли мое внимание в данный момент. Существует не так много информации об их использовании, и это поможет увидеть, что люди с ними сделали, и получить примеры того, как они работают, а также узнать, какие проблемы можно решить с ними. Исходя из этого, есть ли какие-либо рекомендации для понимания того, что является хорошим и плохим использованием прочитанных макросов?
7 ответов
S-выражения - это синтаксис Lisp для данных Lisp. S-выражения читаются с помощью функции READ, а макросы чтения - это встроенный в Lisp способ расширения читателя. Это означает, что самое непосредственное использование макросов чтения - это реализация предопределенного синтаксиса данных и открытие возможностей изменить или расширить способ, которым Lisp читает s-выражения.
Lisp поставляется с предопределенным внешним синтаксисом для большого количества типов данных: символов, чисел, строк, массивов, символов, выражений, списков, структур и многого другого. Это позволяет печатать и читать объекты данных.
В Лиспе отсутствует синтаксис для нескольких других типов данных - заметных хеш-таблиц и объектов CLOS. Таким образом, первое использование макросов чтения в пользовательском коде состояло бы в том, чтобы расширить возможности считывателя для чтения структур данных, таких как хеш-таблицы, параллельные векторы, новые типы чисел,... в основном каждый тип данных, который разработчик хочет иметь внешний синтаксис, можно прочитать обратно.
Поскольку Lisp также использует s-выражения для кода, второе использование макросов чтения - расширение нотации для программ на Лиспе. Типичным примером является использование [и] для написания встроенного кода SQL. Обычный синтаксис Lisp выглядит аналогично, но использование [и] помогает выражениям SQL выделяться в коде. Другим примером является использование макросов чтения для предоставления идентификаторов для встроенных языков программирования, таких как константы Objective C, сообщения и т. Д. В Clozure CL это используется для представления чувствительных к регистру / сохраняющих регистр идентификаторов и для поиска их определения во время чтения с использованием индекса внешне доступные идентификаторы.
Третье использование - встраивание различных синтаксисов в синтаксис Lisp. Старый пример этого - макрос чтения инфикса, который допускает встроенные выражения инфикса. Другими примерами являются встроенный синтаксис HTML или XML или фрагменты других синтаксисов языка программирования.
Иногда макросы чтения используются для реализации других (связанных) языков, которые используют синтаксисы s-выражений, которые отличаются от предопределенного синтаксиса Common Lisp. Примером может служить читатель для s-выражений Scheme, которые немного отличаются от Common Lisp.
Макросы Reader используются, когда есть синтаксис для литеральных объектов, которые вы можете захотеть иметь. Единственная проблема с ними - плоское пространство имен для возможных синтапов (однако, есть способы обойти это). Существует не так много применений читательских макросов. Вот некоторые примеры, которые приходят мне в голову:
- http://weitz.de/cl-interpol/ - синтаксис для интерполяции строк и расширенной нотации строк
- http://trac.clozure.com/openmcl/wiki/OpenMclFfi - синтаксис, который импортирует символы из языка C (автоматизированная форма FFI)
- http://clsql.b9.com/manual/sql.html - синтаксис для запросов SQL - не очень полезный
- http://www.agentsheets.com/lisp/XMLisp/ - встраивание литеральных фрагментов XML в код Lisp
Я на самом деле склонен избегать их для моего обычного кода на Лиспе; недавно я даже обнаружил, что отказываюсь от сторонней библиотеки из-за использования макросов для чтения. В основном это связано с тем, что, в отличие от символов, для читателей-макросов существует только одно "пространство имен". И я часто, похоже, не согласен с авторами библиотек по поводу их вкуса при выборе подходящего персонажа рассылки.
Тем не менее, я использовал нестандартные читаемые таблицы + чтение успешно для простых задач анализа. Самым сложным синтаксическим анализатором, который я реализовал до сих пор с использованием настраиваемой читаемой таблицы, был механизм шаблонов HTML (еще один, извините) с синтаксисом, аналогичным JSP/ASP, но с использованием Common Lisp в качестве фактического языка шаблонов, так что вы можете иметь такие вещи, как
<% (for (title . link) in breadcrumb do %><a href="<%= link %>"><%= title %></a><% ) %>
(не было сделано только с читаемыми взломами, хотя, код должен был пройти стадию предварительной обработки).
У меня есть два небольших проекта на Github, которые показывают, как и почему можно использовать макросы для чтения в Common Lisp. Это SHELLSHOCK и BOXEN. Как упоминалось в других ответах, CL-INTERPOL является выдающимся и полезным примером.
Является ли это хорошим использованием макросов читателя, очевидно, субъективно, но, конечно, я должен думать, что они полезны, иначе я бы не написал код!
Несмотря на то, что я использую много макросов, я не нашел необходимости использовать макросы чтения, кроме случайных экспериментов. Если это поможет, в "Let Over Lambda" вы найдете подробное обсуждение о них: http://letoverlambda.com/index.cl/toc
Одним из наиболее распространенных и полезных альтернативных синтаксисов, который вы можете встроить в макросы чтения, является синтаксис регулярных выражений. Его совсем нетрудно реализовать, поскольку он просто читает строку с различными правилами экранирования, но если вы часто используете регулярные выражения, это может окупиться. Библиотека CL-INTERPOL, о которой упоминал dmitry-vk, предоставляет эту функциональность наряду со многими другими функциями.
См Vsevolod Dyomkin Ответ Vsevolod Dyomkin на мой вопрос. Написание Common Lisp-кода, который выполняется из командной строки, но не внутри интерпретатора, который является приложением для чтения макросов.