Для каких целей вы использовали макросы Scheme?[закрыто]
Вопрос
Многие примеры макросов, по-видимому, связаны с сокрытием лямбда-выражений, например.с открытым файлом в CL.Я ищу более экзотические варианты использования макросов, особенно в схеме PLT.Я хотел бы понять, когда следует рассмотреть возможность использования макроса, а когда нет.с помощью функций.
Решение
Я использую макросы Scheme (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))
Дэн Фридман имеет потрясающую реализацию ОО с использованием макросов: http: // www.cs.indiana.edu/~dfried/ooo.pdf р>
Но, честно говоря, все полезные макросы, которые я определил, украдены из работы Пола Грэма Lisp и, как правило, легче писать с помощью defmacro
(define-macro
в схеме PLT). Например, aif
довольно уродливо с syntax-rules
.
(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)))])]))
syntax-case
странно тем, что его легко использовать только для очень простых макросов, где вы рады невозможности захвата переменных; и очень сложные макро-DSL, где вы рады невозможности захвата переменных легко . В первом случае вы хотите написать код, не думая об этом, а во втором случае вы достаточно задумывались о DSL, и вы готовы написать его часть на языке <=> / <=>, который не является схемой чтобы избежать загадочных ошибок.
Но я не так часто использую макросы в Scheme. Идиоматическая схема настолько функциональна, что много раз вы просто хотите написать функциональную программу, а затем спрятать несколько лямбд. Я сел на функциональный поезд и теперь считаю, что если у вас есть ленивый язык или хороший синтаксис для лямбды, даже в этом нет необходимости, поэтому макросы не так уж полезны в чисто функциональном стиле.
Поэтому я бы порекомендовал Практический Common Lisp и На Лиспе . Если вы хотите использовать схему PLT, я думаю, что большинство их макросов <=> будут работать с <=>. Или просто используйте 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 р>
Чтобы найти примеры новых форм привязки, найдите макросы, которые начинаются с " с - " ;. Один полезный пример можно найти в math.plt также из PLaneT.
; 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. Есть шаблон, но слишком высокий уровень для функции, поэтому вы создаете макрос.
По моему скромному опыту, макросы в Scheme должны использоваться так же часто, как и в других Лиспах, таких как Common Lisp или Clojure . Я полагаю, это доказательство того, что, возможно, гигиенические макросы не очень хорошая идея, и здесь я не согласен с Полом Грэмом по поводу почему. Это не потому, что иногда вы хотите быть грязным (не гигиеническим), а потому, что гигиенические макросы оказываются сложными или запутанными.
Практический Common Lisp Питера Сейбела (Peter Seibel) хорошо знаком с макросами. На Лиспе, Пол Грэм, может быть хорошим источником более сложных примеров. Также обратите внимание на встроенные макросы, скажем, в Common Lisp.
А Автоматы через макросы В статье представлена жемчужина функционального программирования по реализации конечных автоматов с помощью макросов в Scheme.
Книга Разумный интриган заканчивается полной реализацией miniKanren, языка логического программирования, используемого в книге, на основе макросов. Эта бумага MiniKanren и его реализация представлены более формально и лаконично, чем в книге.
Примером более продвинутого макроса, который не является замаскированной лямбда-формой, является макрос with-slots Common Lisp, который делает доступ к объектным слотам похожим на доступ к обычной переменной:
(with-slots (state door) car
(when (eq state :stopped)
(setq state :driving-around)
(setq door :closed)))
Обратите внимание, что это не то же самое, что привязка значений слотов к локальным переменным и доступ к ним, так как with-slots позволяет изменять слоты с помощью SETQ и сразу же видеть внешние изменения. р>
У меня был макрос curry
, когда я использовал много схем на моей ладони. Это было очень удобно.
Макросы схемы позволяют добавлять функции, которые авторы исходного языка не включали сами; в этом вся философия, лежащая в основе макросов.
Вот небольшой пример: PLT Scheme предоставляет язык для написания презентаций, который называется Slideshow. Я использовал макросы, чтобы связать номер слайда со слайдом, чтобы мне было легче управлять ими.
Я & # 8217; написал макрос, обеспечивающий синтаксис инфикса. Ничего особенного; нет приоритета. В то время как я & # 8217; m, как правило, хорошо с префиксным синтаксисом, я предпочитаю infix для & Lt; и >.
Я использую их, когда процедур недостаточно. Р>