Для чего вы использовали макросы Scheme? [закрытый]
многие примеры макросов, похоже, касаются скрытия лямбд, например, с-open-file в CL. Я ищу более экзотическое использование макросов, особенно в схеме PLT. Я хотел бы почувствовать, когда следует использовать макрос против использования функций.
10 ответов
я использую только макросы схемы (define-syntax
) для крошечных вещей, таких как лучший синтаксис лямбда:
(define-syntax [: x]
(syntax-case x ()
([src-: e es ...]
(syntax-case (datum->syntax-object #'src-: '_) ()
(_ #'(lambda (_) (e es ...)))))))
, который позволяет писать
[: / _ 2] ; <-- much better than (lambda (x) (/ x 2))
Дэн Фридман имеет умопомрачительную реализацию OO с использованием макросов:http://www.cs.indiana.edu~dfried / ooo.pdf
но, честно говоря, все полезное макросы я определил похищены из Пол Грэм шепелявит и, как правило, легче писать defmacro
(define-macro
in Plt Scheme). Например, aif
очень некрасиво с define-syntax
.
(define-syntax (aif x)
(syntax-case x ()
[(src-aif test then else)
(syntax-case (datum->syntax-object (syntax src-aif) '_) ()
[_ (syntax (let ([_ test]) (if (and _ (not (null? _))) then else)))])]))
define-syntax
странно, что он прост в использовании только для очень простых макросов, где вы рады невозможности захвата переменных; и очень сложный макрос DSLs, где вы рады невозможности захвата переменных легко. В первом случае вы хотите написать код, не думая об этом, а во втором случае вы достаточно подумали о DSL, что вы готовы напишите часть этого в syntax-rules
/syntax-case
язык, который не является схемой, чтобы избежать мистификации ошибок.
но я не использую макросы так много в схеме. Идиоматическая схема настолько функциональна, что много раз вы просто хотите написать функциональную программу, а затем скрыть несколько лямбд. Я сел на функциональный поезд и теперь считаю, что если у вас есть ленивый язык или хороший синтаксис для лямбда, даже это не обязательно, поэтому макросы не так полезны в чисто функциональном стиль.
поэтому я бы рекомендовал Практический Общий Lisp и На Лиспе. Если вы хотите использовать схему PLT, я думаю, что большинство их defmacro
макросы будут работать с define-macro
. Или просто используйте Common Lisp.
макросы необходимы для реализации новых структур управления и новых конструкций привязки.
таким образом, ищите эти виды конструкций в http://planet.plt-scheme.org. В PLaneT вы просматриваете документацию и код.
примеры новых структур управления:
http://planet.plt-scheme.org/package-source/soegaard/control.plt/2/0/planet-docs/manual/index.html
найти примеры новых привязка формы, искать макросы, которые начинаются с "с -". Один из полезных примеров - математика.plt также с планеты.
; Within a (with-modulus n form1 ...) the return values of
; the arithmetival operations +, -, * and ^ are automatically
; reduced modulo n. Furthermore (mod x)=(modulo x n) and
; (inv x)=(inverse x n).
; Example: (with-modulus 3 (^ 2 4)) ==> 1
(define-syntax (with-modulus stx)
(syntax-case stx ()
[(with-modulus e form ...)
(with-syntax ([+ (datum->syntax-object (syntax with-modulus) '+)]
[- (datum->syntax-object (syntax with-modulus) '-)]
[* (datum->syntax-object (syntax with-modulus) '*)]
[^ (datum->syntax-object (syntax with-modulus) '^)]
[mod (datum->syntax-object (syntax with-modulus) 'mod)]
[inv (datum->syntax-object (syntax with-modulus) 'inv)])
(syntax (let* ([n e]
[mod (lambda (x) (modulo x n))]
[inv (lambda (x) (inverse x n))]
[+ (compose mod +)]
[- (compose mod -)]
[* (compose mod *)]
[square (lambda (x) (* x x))]
[^ (rec ^ (lambda (a b)
(cond
[(= b 0) 1]
[(even? b) (square (^ a (/ b 2)))]
[else (* a (^ a (sub1 b)))])))])
form ...)))]))
Я начну отвечать на последний вопрос. Если использовать макрос вместо функции. Макросы делают то, что не могут функции, а функции делают то, что не могут макросы, поэтому будет трудно смешать их, но давайте углубимся.
вы используете функции, когда хотите, чтобы аргументы оценивались, и макросы, когда вы хотите, чтобы аргументы не оценивались. Это не очень полезно, не так ли? Вы используете макросы, когда хотите написать что-то по-другому, когда вы видите шаблон и хотите абстрактный. Например: я определяю три функции, называемые foo-create, foo-process и foo-destroy для разных значений foo и с аналогичными телами, где единственным изменением является foo. Существует шаблон, но слишком высокий уровень для функции, поэтому вы создаете макрос.
по моему скромному опыту, макросы в схеме используются так же, как и в других Lisps, таких как Common Lisp или Clojure. Я полагаю, это доказательство того, что, возможно, гигиенические макросы не такая хорошая идея, и здесь я бы не согласился с Полом Грэмом о том, почему. Это не потому, что иногда вы хотите быть грязным (негигиеничным), а потому, что гигиенические макросы оказываются сложными или запутанными.
Practical Common Lisp, Peter Seibel, имеет хорошее введение в макросы. На Lisp, Paul Graham, может быть хорошим источником более сложных примеров. Кроме того, посмотрите на встроенные макросы, скажем, в Common Lisp.
на автоматы через макрос в статье представлен функциональный программный жемчуг по реализации конечных автоматов через макросы в схеме.
книги Рассудительный Интриган заканчивается полной макро-реализацией miniKanren, языка логического программирования, используемого в книге. этой статье представляет миниканрен и его реализацию более формально и лаконично, чем в книге.
пример более продвинутый макрос это не лямда форма в маскировка общий Лисп макрос С-слоты, что делает доступ к объектному слоту похожим на обычный переменный доступ:
(with-slots (state door) car
(when (eq state :stopped)
(setq state :driving-around)
(setq door :closed)))
обратите внимание, что это не то же самое, что привязка значений слота к локальным переменным и доступ к ним, как С-слоты позволяет изменять слоты с помощью SETQ и немедленно видеть внешние изменения.
макросы схемы позволяют добавлять функции, которые авторы исходного языка не включили сами; это вся философия макросов.
вот крошечный пример: plt Scheme предоставляет язык для написания презентаций, называемых слайд-шоу. Я использовал макросы, чтобы связать номер слайда с слайдом, чтобы мне было легче управлять ими.
Я написал макрос, который предоставляет синтаксис infix. Ничто не слишком фантазии, не приоритет. Хотя я обычно в порядке с синтаксисом префикса, я предпочитаю infix Для .