Короче говоря, макросы преобразования кода. Они позволяют представлять много новых конструкций синтаксиса. Например, рассмотрите LINQ в C#. В шепелявости существуют подобные расширения языка, которые реализованы макросами (например, встроенная конструкция цикла, выполните итерации). Макросы значительно уменьшают дублирование кода. Макросы позволяют встраивать В «мало languagesВ» (например, где в c#/java можно было бы использовать xml для конфигурирования в шепелявости, то же самое может быть достигнуто с макросами). Макросы могут скрыть трудности использования использования библиотек.
, Например, в шепелявости можно записать
(iter (for (id name) in-clsql-query "select id, name from users" on-database *users-database*)
(format t "User with ID of ~A has name ~A.~%" id name))
, и это скрывает весь материал базы данных (транзакции, надлежащее закрытие соединения, выбирающие данные, и т.д.), тогда как в C# это требует создания SqlConnections, SqlCommands, добавляя SqlParameters к SqlCommands, цикличному выполнению на SqlDataReaders, правильно закрывая их.
Макросы Lisp представляют шаблон, который происходит почти в любом большом проекте программирования. В конечном счете в большой программе у Вас есть определенный раздел кода, где Вы понимаете, что это было бы более простым и менее подверженным ошибкам для Вас для записи программы, что выходной исходный код как текст, в котором можно тогда просто вставить.
В объектах Python имеют два метода __repr__
и __str__
. __str__
просто человекочитаемое представление. __repr__
возвраты представление, которое является допустимым кодом Python, который должен сказать, что-то, что может быть введено в интерпретатор как действительный Python. Таким образом, можно создать небольшие отрывки Python, которые генерируют допустимый код, который может быть вставлен в Ваш на самом деле источник.
В Lisp этот целый процесс был формализован макро-системой. Уверенный это позволяет Вам создать расширения синтаксиса и сделать все виды необычных вещей, но это - фактическая полноценность, подведен итог вышеупомянутым. Конечно, помогает, что система макроса Lisp позволяет Вам управлять этими "отрывками" с полной мощностью всего языка.
Макрос шепелявости берет фрагмент программы, как введено. Этот фрагмент программы представлен структура данных, которой можно управлять и преобразовала любой способ, которым Вам нравится. В конце макро-выводы другой фрагмент программы и этот фрагмент - то, что выполняется во времени выполнения.
C# не имеет макро-средства, однако эквивалент был бы то, если бы компилятор проанализировал код в дерево CodeDOM и передал это методу, который преобразовал это в другой CodeDOM, который тогда компилируется в IL.
Это могло использоваться для реализации "сахарного" синтаксиса как for each
- оператора using
- пункта, linq select
- выражения и так далее, как макросы, которые преобразовывают в базовый код.
, Если Java имел макросы, Вы могли бы реализовать синтаксис Linq в Java, не нуждаясь в Sun для изменения основного языка.
Вот псевдокод для того, как мог посмотреть макрос стиля шепелявости в C# для реализации using
:
define macro "using":
using ($type $varname = $expression) $block
into:
$type $varname;
try {
$varname = $expression;
$block;
} finally {
$varname.Dispose();
}
Макросы Lisp позволяют Вам решать, когда (если вообще) какая-либо часть или выражение будут оценены. Для помещения простого примера думайте о C:
expr1 && expr2 && expr3 ...
то, Что это говорит: Оцените expr1
, и, должен это быть верным, оценить expr2
, и т.д.
Теперь попытка сделать это &&
в функцию... правильно, Вы не можете. Вызов чего-то как:
and(expr1, expr2, expr3)
оценит весь три exprs
прежде, чем привести к ответу независимо от того, был ли expr1
ложью!
С макросами шепелявости можно кодировать что-то как:
(defmacro && (expr1 &rest exprs)
`(if ,expr1 ;` Warning: I have not tested
(&& ,@exprs) ; this and might be wrong!
nil))
теперь Вы имеете &&
, который можно назвать точно так же, как функция и это не оценят форм, которые Вы передаете ему, если они не все верны.
, Чтобы видеть, как это полезно, контраст:
(&& (very-cheap-operation)
(very-expensive-operation)
(operation-with-serious-side-effects))
и:
and(very_cheap_operation(),
very_expensive_operation(),
operation_with_serious_side_effects());
Другие вещи, которые можно сделать с макросами, создают новые ключевые слова, и/или мини-языки (проверьте (loop ...)
макрос для примера), интегрируя другие языки в шепелявость, например, Вы могли записать макрос, который позволяет Вам сказать что-то как:
(setvar *rows* (sql select count(*)
from some-table
where column1 = "Yes"
and column2 like "some%string%")
И это даже не входит макросы Читателя .
Hope это помогает.
Макросы языка Common LISP по существу расширяют "синтаксические примитивы" Вашего кода.
, Например, в C, конструкция переключателя/случая только работает с целочисленными типами и если Вы хотите использовать его для плаваний или строк, Вас оставляют с вложенным если операторы и явные сравнения. Нет также никакого способа, которым можно записать макрос C, чтобы сделать задание для Вас.
, Но, так как макрос шепелявости является (по существу) программой шепелявости, которая берет отрывки кода, как введено и кода возвратов для замены "вызова" макроса, можно расширить репертуар "примитивов", насколько Вы хотите, обычно заканчивая с более читаемой программой.
, Чтобы сделать то же в C, необходимо было бы записать пользовательский препроцессор, который ест начальную букву (not-quite-C) источник и выкладывает что-то, что может понять компилятор C. Это не неправильный способ пойти об этом, но это является не обязательно самым легким.
Вы найдете всесторонние дебаты [приблизительно 113] макрос шепелявости здесь .
интересное подмножество той статьи:
На большинстве языков программирования, синтаксис сложен. Макросы должны демонтировать синтаксис программы, проанализировать его и повторно собрать его. У них нет доступа к синтаксическому анализатору программы, таким образом, они должны зависеть от эвристики и лучших предположений. Иногда их сниженный анализ является неправильным, и затем они повреждаются.
, Но Lisp отличается. Макросы Lisp делают , имеют доступ к синтаксическому анализатору, и это - действительно простой синтаксический анализатор. А макросу Lisp не вручают строку, но предварительно проанализированную часть исходного кода в форме списка, потому что источник программы Lisp не является строкой; это - список. И программы Lisp действительно хороши в демонтировании списков и откладывании их вместе. Они делают это надежно каждый день.
Вот расширенный пример. Lisp имеет макрос, названный "setf", который выполняет присвоение. Самая простая форма setf
(setf x whatever)
, который устанавливает значение символа "x" к значению выражения "вообще".
Lisp также имеет списки; можно использовать функции "автомобиля" и "командира" для получения первого элемента списка или остальной части списка, соответственно.
Теперь, что, если Вы хотите заменить первый элемент списка с новым значением? Существует стандартная функция для того, чтобы сделать это, и невероятно, ее имя еще хуже, чем "автомобиль". Это - "rplaca". Но Вы не должны помнить "rplaca", потому что можно записать
(setf (car somelist) whatever)
для установки автомобиля somelist.
, Что действительно происходит, вот то, что "setf" является макросом. Во время компиляции это исследует свои аргументы, и это видит, что первый имеет форму (автомобиль ЧТО-ТО). Это говорит себе, "О, программист пытается установить автомобиль чего-то. Функция для использования для этого является 'rplaca'". И это бесшумно переписывает код на месте к:
(rplaca somelist whatever)
Думайте о том, что можно сделать в C или C++ с макросами и шаблонами. Они - очень полезные инструменты для управления повторяющимся кодом, но они ограничены довольно серьезными способами.
Lisp и макросы Lisp решают эти проблемы.
Говорят с любым, кого это освоило C++ и спрашивает их, сколько времени они потратили изучение всего шаблона fudgery, они должны сделать шаблонное метапрограммирование. Или все сумасшедшие приемы в (превосходных) книгах как современный Дизайн C++, которые все еще жестки для отладки и (на практике) непортативный между реальными компиляторами даже при том, что язык стандартизировался в течение десятилетия. Все это тает, если язык, который Вы используете для метапрограммирования, является тем же языком, Вы используете для программирования!
Я не уверен, что могу добавить некоторое понимание к общим (превосходным) сообщениям, но...
макросы Lisp работают отлично из-за природы синтаксиса Lisp.
Lisp чрезвычайно регулярный язык (думайте обо всем, список ); макросы позволяют Вам рассматривать данные и код как то же (никакой строковый парсинг, или другие взломы необходимы для изменения выражений шепелявости). Вы сочетаете эти две функции, и Вы имеете очень чистый способ изменить код.
Редактирование: то, Что я пытался сказать, - то, что Lisp гомографический , что означает, что структура данных для программы шепелявости записана в самой шепелявости.
Так, Вы заканчиваете со способом создать Ваш собственный генератор кода сверху языка с помощью самого языка со всем его питанием (например, в Java необходимо взломать путь с переплетением байт-кода, хотя некоторые платформы как AspectJ позволяют Вам делать это использование другого подхода, это - существенно взлом).
На практике, с макросами Вы заканчиваете тем, что создали свое собственное мини-язык сверху шепелявости без потребности выучить дополнительные языки или инструменты, и с использованием полной мощности самого языка.