Pergunta

Muitos exemplos de macros parecem ser sobre lambdas esconderijos, por exemplo, -com-arquivo aberto em CL. Eu estou olhando para alguns usos mais exóticos de macros, particularmente em PLT Scheme. Eu gostaria de ter uma idéia de quando considerar o uso de uma vs. macro usando funções.

Foi útil?

Solução

Eu só uso macros Esquema (define-syntax) para pequenas coisas como melhor sintaxe lambda:

(define-syntax [: x]
  (syntax-case x ()
    ([src-: e es ...]
     (syntax-case (datum->syntax-object #'src-: '_) ()
       (_ #'(lambda (_) (e es ...)))))))

O que permite que você escreva

[: / _ 2]  ; <-- much better than (lambda (x) (/ x 2))

Dan Friedman tem uma implementação alucinante de OO usando macros: http: // www.cs.indiana.edu/~dfried/ooo.pdf

Mas, honestamente, todos os úteis macros eu definidos são roubados de Paul Graham On Lisp e são geralmente mais fácil escrever com defmacro (define-macro no Esquema PLT). Por exemplo, aif é muito feio com 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 é estranho em que é apenas fácil de usar para macros muito simples, onde você está contente com a incapacidade de variáveis ??de captura; e muito complicado DSLs macro, onde você está contente com a incapacidade de variáveis ??de captura facilmente . No primeiro caso, você quer escrever o código sem pensar nisso, e no segundo caso você tenha pensado o suficiente sobre o DSL que você está disposto a escrever parte dela na língua syntax-rules / syntax-case que não é Esquema de modo a evitar mistificando bugs.


Mas eu não utilizar macros que muito no esquema. Esquema idiomática é tão funcional que muitas vezes você só quer escrever um programa funcional e, em seguida, esconder algumas lambdas. Peguei o trem funcional e agora acredito que se você tem uma língua preguiçoso ou uma boa sintaxe lambda, mesmo que não é necessário, para macros não são tão úteis em um estilo puramente funcional.

Então, eu recomendo Practical Common Lisp e Em Lisp . Se você quiser usar PLT Scheme, eu acho que a maioria de seus macros defmacro irá trabalhar com define-macro. Ou simplesmente usar Lisp Comum.

Outras dicas

Macros são necessários, a fim de implementar novas estruturas de controle e novas construções de ligação.

Assim, olhar para estes tipos de construções em http://planet.plt-scheme.org . No planeta que você tanto procura a documentação eo código.

Exemplos para novas estruturas de controle:

http://planet.plt-scheme.org/package-source/soegaard/control.plt/2/0/planet-docs/manual/index.html

Para encontrar exemplos de novas formas de ligação, procure macros que começam com "com-". Um exemplo útil é encontrado em math.plt também do planeta.

  ; 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 ...)))]))

Eu vou começar a responder a última pergunta. Quando usar uma macro em vez de uma função. As macros fazer coisas as funções não podem, e as funções de fazer coisa que as macros não pode, por isso vai ser difícil misturá-los, mas vamos ir mais fundo.

Você usa funções quando quiser os argumentos avaliados e macros quando você quer os argumentos avaliou-un. Isso não é muito útil, não é? Você usa macros quando você quer escrever alguma coisa de uma maneira diferente, quando você ver um padrão e você quer abstrato. Por exemplo: Eu definir três funções chamadas foo-criar, foo-processo e foo-destruir para diferentes valores de foo e com organismos similares, onde a única mudança é foo. Há um padrão, mas um muito alto nível para uma função, para que criar uma macro.

Na minha humilde experiência, macros no Esquema são usados ??tanto como em outras Lisps, como Lisp comum ou Clojure . Acho que é uma prova de que talvez macros de higiene não são uma idéia tão boa, e aqui eu discordaria de Paul Graham sobre o porquê. Não é porque às vezes você quer estar sujo (un-higiênico), mas porque macros higiene acabar por ser complexo ou complicado.

Practical Common Lisp, de Peter Seibel, tem uma boa introdução a macros. Em Lisp, por Paul Graham, pode ser uma boa fonte de exemplos mais complicados. Além disso, ter olhar para o built-in macros em, digamos, Lisp Comum.

O Automata via Macros artigo apresenta uma pérola programação funcional na implementação de máquinas de estados finitos através de macros no esquema.

O livro extremidades O fundamentado Schemer com um implementação baseada em macro cheio de miniKanren, a linguagem de programação lógica utilizada no livro. Este papel apresenta miniKanren e sua implementação mais formalmente e concisa do que no livro.

Um exemplo de uma macro mais avançado que não é uma forma lambda disfarçado é macro do Common Lisp com-ranhuras , o que torna o acesso ranhura objeto parecido com acesso variável comum:

(with-slots (state door) car
  (when (eq state :stopped)
    (setq state :driving-around)
    (setq door :closed)))

Note que este não é o mesmo como obrigatórios os valores de slot para variáveis ??locais e acessar aqueles, como com-ranhuras permite ranhuras alter por meio de SETQ e ver mudanças externas imediatamente.

Eu tive uma macro curry quando eu costumava fazer um monte de regime na palma da minha mão. Foi muito útil.

macros Esquema permitem adicionar recursos que os autores de língua originais não incluíam a si mesmos; que é toda a filosofia por trás macros.

Aqui está um pequeno exemplo: PLT Scheme fornece uma linguagem para apresentações de escrita chamado Slideshow. Eu usei macros para associar um número de slide com um slide para que eu pudesse mais facilmente controlá-los.

Eu escrevi uma macro que fornece sintaxe infix. Nada muito extravagante; sem precedência. Enquanto eu sou geralmente muito bem com prefixo sintaxe, eu prefiro infix para .

Eu usá-los quando os procedimentos não são suficientes.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top