2014-11-03 2 views
4

Здесь мое основное внимание уделяется макросам Scala и Lisp/Scheme, не совсем тем, что в C/C++/Obj-CКакова цель макросов?

Я просто не вижу смысла.

Способ, которым я это понимаю, заключается в том, что макросы расширяют язык. Но так же и функции.

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

В чем же цель? Чистые макросы или другие, кто-то, пожалуйста, просветите меня. Если возможно, укажите пример кода, который можно сделать в макросах, но невозможно/трудно сделать с обычными функциями.

+0

http://stackoverflow.com/questions/267862/what-makes -lisp-macros-so-special? s = 6 | 1.8097 http://stackoverflow.com/questions/5833033/in-lisp-code-is-data-what-benefit-does-that-provide/5833388?s = 11 | 1.6415 # 5833388 –

+0

дубликат http: //stackoverflow.c om/questions/2561221/examples-of-what-lisps-macros-can-be-used-for? s = 7 | 4.5505 –

ответ

7

Существует краткий обзор того, что было сделано с помощью макросов Scala: http://scalamacros.org/paperstalks/2014-02-04-WhatAreMacrosGoodFor.pdf. Подводя итог, известно, что макросы хороши для: 1) генерации кода, 2) расширенных статических проверок, 3) расширения прав доступа к доменам. Наличие макросов в Scala, основанных на типе, обеспечивает дополнительный и мощный поворот к возможностям, обычно встречающимся в макросах на Lisp-подобных языках.

Некоторые примеры в приведенных выше слайдах действительно могут быть реализованы без макросов, но результат будет либо отсутствовать в некотором смысле (например, в производительности), либо чрезмерно сложным для пользователей (например, из-за сообщений об ошибках в тяжелом весе). Например, типизированные каналы для Akka можно было бы реализовать с чистыми имплицитами, но скорость компиляции и понятность пострадали бы. Или scala/async может быть реализована как плагин компилятора, но тогда он должен будет зависеть от внутренних API-интерфейсов компилятора и будет сложнее распространять.

Конечно, макросы не являются серебряной пулей. Там, очевидно, используются случаи, когда они не лучший выбор, и это то, что описано в http://scalamacros.org/paperstalks/2014-03-01-MacrosVsTypes.pdf. Однако любопытно, что в ряде ситуаций ни лучшие, ни макро-решения, а скорее тщательно сконструированные гибриды становятся лучшими.

+0

Я отредактировал вопрос –

+0

В первой презентации есть несколько примеров. Я не думаю, что 1, 2, 5, 7 и 8 могут быть реализованы без макросов. 3 и 4 могут быть выполнены с расширенным программированием на уровне уровня, но результат будет медленнее как во время компиляции, так и во время выполнения и гораздо сложнее поддерживать. 6 могут быть аппроксимированы, но пострадает пользовательский интерфейс (сообщения об ошибках, непоследовательный словарь). –

2

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

Например, как схема и CL имеют if, cond и case, но только if примитивный синтаксис.

Нет ничего особенного в макросах, определенных стандартом, и тех, которые вы можете сделать сами. Их можно заставить вести себя и работать так же хорошо, как примитивы.

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

+0

Я отредактировал вопрос –

1

Есть три основных целей, которые макросы используются для в Лиспе (не знают о Scala):

  • Определение: что-то создается и непосредственно зарегистрированные в соответствующем месте. Примеры: defun, defgeneric, defclass (со стандарта), deftable (from postmodern).
  • Unwind-protect обертки: состояние временно изменено и может быть изменено после завершения задачи. Это может быть громоздким, чтобы писать многократно, поэтому мы создаем стенографию. Пример: with-open-file (стандарт), with-transaction (многие библиотеки баз данных).
  • Создание других языков: например, CL-WHO (HTML), Parenscript (JavaScript). Создавая код других языков в формах Lisp, мы можем использовать макросы для этих других языков, даже если у них нет поддержки для них самих.

Конкретный пример: Java 7 ввел сокращение для обеспечения закрытия Closable с в try -блоков:

try (SomeClosable foo = openFoo()) { 
    foo.doSomething(); 
} 

, который может в Java 6 быть выражены только примерно так:

SomeClosable foo; 
try { 
    foo = openFoo(); 
    foo.doSomething(); 
} finally { 
    if (foo != null && foo.isOpen()) { 
     foo.close(); 
    } 
} 

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

(defmacro with-open-foo ((var &rest options) &body body) 
    `(let ((,var (open-foo ,@options))) 
    (unwind-protect 
     (progn ,@body) 
     (when ,var (close ,var))))) 

так, что он может написать

(with-open-foo (f :bar baz) 
    (do-some-foo f) 
    (and-something-else)) 

вместо

(let ((f (open-foo :bar baz))) 
    (unwind-protect 
     (progn 
     (do-some-foo f) 
     (and-something-else)) 
    (when f (close f)))) 
+0

Я отредактировал вопрос –

+0

@ElectricCoffee: Я отредактировал ответ. – Svante

+0

не могли бы вы просто написать с помощью функции open-foo, используя функцию 'defun'? –

Смежные вопросы