2008-10-29 20 views
9

Muchos ejemplos de macros parecen ser sobre la ocultación de lambdas, p. con-abrir-archivo en CL. Estoy buscando usos más exóticos de macros, particularmente en PLT Scheme. Me gustaría tener una idea de cuándo considerar usar una macro vs. usar funciones.¿Para qué has usado las macros de Scheme?

+1

Esquema de PLT ahora llamado Racket. Ver http://www.racket-lang.org/ – Stephen

Respuesta

5

sólo utilizar macros de Scheme (define-syntax) para cosas pequeñas como mejor sintaxis lambda:

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

que le permite escribir

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

Dan Friedman tiene una aplicación endiablada de OO usando macros : http://www.cs.indiana.edu/~dfried/ooo.pdf

Pero, sinceramente, todos los útiles macros que he definido d son robadas de Paul Graham's On Lisp y generalmente son más fáciles de escribir con defmacro (define-macro en PLT Scheme). Por ejemplo, aif es bastante feo con 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 es extraño en que sólo es fácil de usar para las macros muy simples, en las que se alegran de la incapacidad para capturar las variables; y macro DSL muy complicadas, donde se alegra de la imposibilidad de capturar variables fácilmente. En el primer caso, usted desea escribir el código sin pensarlo, y en el segundo caso ha pensado lo suficiente sobre el DSL que está dispuesto a escribir parte del mismo en el lenguaje syntax-rules/syntax-case que no es Scheme para evitar errores desconcertantes.


Pero no uso macros en Scheme. Idiomatic Scheme es tan funcional que muchas veces solo quieres escribir un programa funcional y luego esconder algunas lambdas. Me subí al tren funcional y ahora creo que si tienes un lenguaje lento o una buena sintaxis para lambda, incluso eso no es necesario, por lo que las macros no son tan útiles en un estilo puramente funcional.

Así que recomendaría Practical Common Lisp y On Lisp. Si desea utilizar PLT Scheme, creo que la mayoría de sus macros defmacro funcionarán con define-macro. O simplemente usa Common Lisp.

+1

Si usa un parámetro de sintaxis, 'aif' se vuelve mucho más limpio para definir (y hygenic!):' (Define-sintaxis-parámetro it #f) (define-sintaxis aif (sintaxis-analizador [(_ prueba y luego else) # '(let ([resultado de la prueba]) (sintaxis-parametrizar ([it (make-rename-transformer result)]) (si result luego else)))])) – Jack

7

Comenzaré a responder la última pregunta. Cuándo usar una macro en lugar de una función. Las macros hacen cosas que las funciones no pueden hacer, y las funciones hacen lo que las macros no pueden hacer, por lo que será difícil mezclarlas, pero profundicemos.

Utiliza funciones cuando quiere los argumentos evaluados y macros cuando quiere que los argumentos no sean evaluados. Eso no es muy útil, ¿verdad? Utiliza macros cuando quiere escribir algo de forma diferente, cuando ve un patrón y desea abstraer. Por ejemplo: defino tres funciones llamadas foo-create, foo-process y foo-destroy para diferentes valores de foo y con cuerpos similares donde el único cambio es foo. Hay un patrón pero un nivel demasiado alto para una función, por lo que crea una macro.

En mi humilde experiencia, las macros en Scheme se usan tanto como en otros Lisp, como Common Lisp o Clojure. Supongo que es una prueba de que tal vez las macros higiénicas no son una buena idea, y aquí estaría en desacuerdo con Paul Graham acerca de por qué. No es porque a veces quieras estar sucio (no higiénico) sino porque las macros higiénicas terminan siendo complejas o intrincadas.

+0

"porque las macros higiénicas terminan siendo complejas o intrincadas" - No creo que esto se deba a la propia higiene; es más probable porque las macros higiénicas de Scheme son de "alto nivel" y deben escribirse en un lenguaje distinto de Scheme (que, en lo que a mí respecta, ¡es mucho menos conveniente que Scheme!) Es por eso que amo Common Lisp y todavía utilizo define-macro en Scheme, aunque R5RS tiene este truco de reglas de sintaxis ...:-) – Jay

3

Practical Common Lisp, por Peter Seibel, tiene una buena introducción a las macros. On Lisp, de Paul Graham, podría ser una buena fuente de ejemplos más complicados. Además, tenga en cuenta las macros integradas en, por ejemplo, Common Lisp.

+1

Scheme macros! = Common Lisp macros –

1

Un ejemplo de una macro más avanzada que no es una forma de lambda en el encubrimiento es de Common Lisp macro con ranuras, lo que hace ranura objeto mirada acceso como ordinaria acceso a variables:

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

Tenga en cuenta que este no es lo mismo que vincular los valores de las ranuras a las variables locales y acceder a ellas, ya que con las ranuras le permite modificar las ranuras a través de SETQ y ver los cambios externos de inmediato.

+0

The el uso de setq realmente está en desuso en favor de setf. Es menos confuso para los lectores nuevos (comunes) si ejemplos como este usan setf. – simon

8

Se necesitan macros para implementar nuevas estructuras de control y nuevas construcciones de enlace.

Por lo tanto, busque este tipo de construcciones en http://planet.plt-scheme.org. En PLaneT ambos navegan por la documentación y el código.

Ejemplos de nuevas estructuras de control:

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

encontrar ejemplos de nuevas formas de unión, busque macros que comienzan con "con-". Un ejemplo útil se encuentra en math.plt también de 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 ...)))])) 
3

El documento Automata via Macros presenta una perla programación funcional en la implementación de máquinas de estados finitos a través de macros en el esquema.

El libro The Reasoned Schemer finaliza con una implementación completa en macro de miniKanren, el lenguaje de programación lógica utilizado en el libro. This paper presenta miniKanren y su implementación más formal y concisa que en el libro.

+0

Ese enlace de Automata vía Macros es oro puro. ¡Tuve un gran aha! momento de leerlo. +1 de mi parte –

0

Los uso cuando los procedimientos no son suficientes.

1

Tuve una macro curry cuando solía hacer muchos esquemas en mi palma. Fue muy útil.

1

Las macros de esquema le permiten agregar características que los autores del idioma original no incluían; esa es toda la filosofía detrás de las macros.

Aquí hay un pequeño ejemplo: PLT Scheme proporciona un lenguaje para escribir presentaciones llamadas Diapositivas. Usé macros para asociar un número de diapositiva con una diapositiva para poder administrarlos más fácilmente.

1

He escrito una macro que proporciona la sintaxis de infijo. Nada demasiado sofisticado; sin precedencia Aunque generalmente estoy de acuerdo con la sintaxis de prefijo, prefiero infix para < y>.

Cuestiones relacionadas