Для чего вы использовали макросы 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 и немедленно видеть внешние изменения.


Я curry макрос, когда я использовал много схемы на моей ладони. Это было очень удобно.


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

вот крошечный пример: plt Scheme предоставляет язык для написания презентаций, называемых слайд-шоу. Я использовал макросы, чтобы связать номер слайда с слайдом, чтобы мне было легче управлять ими.


Я написал макрос, который предоставляет синтаксис infix. Ничто не слишком фантазии, не приоритет. Хотя я обычно в порядке с синтаксисом префикса, я предпочитаю infix Для .


Я использую их, когда процедур не хватает.