Что делает макросы Lisp настолько особенными?

284
задан Filipp W. 12 February 2018 в 23:16
поделиться

8 ответов

Короче говоря, макросы преобразования кода. Они позволяют представлять много новых конструкций синтаксиса. Например, рассмотрите 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, правильно закрывая их.

5
ответ дан dmitry_vk 23 November 2019 в 01:52
поделиться

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

В объектах Python имеют два метода __repr__ и __str__. __str__ просто человекочитаемое представление. __repr__ возвраты представление, которое является допустимым кодом Python, который должен сказать, что-то, что может быть введено в интерпретатор как действительный Python. Таким образом, можно создать небольшие отрывки Python, которые генерируют допустимый код, который может быть вставлен в Ваш на самом деле источник.

В Lisp этот целый процесс был формализован макро-системой. Уверенный это позволяет Вам создать расширения синтаксиса и сделать все виды необычных вещей, но это - фактическая полноценность, подведен итог вышеупомянутым. Конечно, помогает, что система макроса Lisp позволяет Вам управлять этими "отрывками" с полной мощностью всего языка.

6
ответ дан dnolen 23 November 2019 в 01:52
поделиться

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

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();
    }
10
ответ дан Brooks Moses 23 November 2019 в 01:52
поделиться

Макросы 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 это помогает.

40
ответ дан dsm 23 November 2019 в 01:52
поделиться

Макросы языка Common LISP по существу расширяют "синтаксические примитивы" Вашего кода.

, Например, в C, конструкция переключателя/случая только работает с целочисленными типами и если Вы хотите использовать его для плаваний или строк, Вас оставляют с вложенным если операторы и явные сравнения. Нет также никакого способа, которым можно записать макрос C, чтобы сделать задание для Вас.

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

, Чтобы сделать то же в C, необходимо было бы записать пользовательский препроцессор, который ест начальную букву (not-quite-C) источник и выкладывает что-то, что может понять компилятор C. Это не неправильный способ пойти об этом, но это является не обязательно самым легким.

53
ответ дан Vatine 23 November 2019 в 01:52
поделиться

Вы найдете всесторонние дебаты [приблизительно 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)
102
ответ дан configurator 23 November 2019 в 01:52
поделиться

Думайте о том, что можно сделать в C или C++ с макросами и шаблонами. Они - очень полезные инструменты для управления повторяющимся кодом, но они ограничены довольно серьезными способами.

  • Ограниченный синтаксис макроса/шаблона ограничивает их использование. Например, Вы не можете записать шаблон, который расширяется до чего-то другого, чем класс или функция. Макросы и шаблоны не могут легко поддержать внутренние данные.
  • сложный, очень неправильный синтаксис C и C++ мешает писать очень общие макросы.

Lisp и макросы Lisp решают эти проблемы.

  • макросы Lisp записаны в Lisp. У Вас есть полная мощность Lisp записать макрос.
  • Lisp имеет очень регулярный синтаксис.

Говорят с любым, кого это освоило C++ и спрашивает их, сколько времени они потратили изучение всего шаблона fudgery, они должны сделать шаблонное метапрограммирование. Или все сумасшедшие приемы в (превосходных) книгах как современный Дизайн C++, которые все еще жестки для отладки и (на практике) непортативный между реальными компиляторами даже при том, что язык стандартизировался в течение десятилетия. Все это тает, если язык, который Вы используете для метапрограммирования, является тем же языком, Вы используете для программирования!

9
ответ дан Matt Curtis 23 November 2019 в 01:52
поделиться

Я не уверен, что могу добавить некоторое понимание к общим (превосходным) сообщениям, но...

макросы Lisp работают отлично из-за природы синтаксиса Lisp.

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

Редактирование: то, Что я пытался сказать, - то, что Lisp гомографический , что означает, что структура данных для программы шепелявости записана в самой шепелявости.

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

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

8
ответ дан Miguel Ping 23 November 2019 в 01:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: