Для каких целей вы использовали макросы Scheme?[закрыто]

StackOverflow https://stackoverflow.com/questions/245677

  •  05-07-2019
  •  | 
  •  

Вопрос

Многие примеры макросов, по-видимому, связаны с сокрытием лямбда-выражений, например.с открытым файлом в 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; и >.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top