lisp - que - ¿Para qué has utilizado las macros de Scheme?
racket online (10)
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.
Muchos ejemplos de macros parecen ser sobre la ocultación de lambdas, por ejemplo, con open-file 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.
Practical Common Lisp, de 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.
Un ejemplo de una macro más avanzada que no es una forma lambda enmascarada es la macro de Common Lisp con ranuras , lo que hace que el acceso a la ranura del objeto se vea como el acceso variable ordinario:
(with-slots (state door) car
(when (eq state :stopped)
(setq state :driving-around)
(setq door :closed)))
Tenga en cuenta que esto no es lo mismo que vincular los valores de las ranuras a las variables locales y acceder a ellas, ya que with-slots le permite modificar las ranuras a través de SETQ y ver los cambios externos de inmediato.
Solo uso Scheme macros ( 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 ...)))))))
Lo cual te permite escribir
[: / _ 2] ; <-- much better than (lambda (x) (/ x 2))
Dan Friedman tiene una implementación alucinante de OO usando macros: http://www.cs.indiana.edu/~dfried/ooo.pdf
Pero, sinceramente, todas las macros útiles que he definido son robadas de Paul defmacro
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, ya que solo es fácil de usar para macros muy simples, donde te alegra la imposibilidad de capturar variables; y macro DSL muy complicadas, donde te alegra la imposibilidad de capturar variables fácilmente . En el primer caso, quiere 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 mucho las 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.
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
Para encontrar ejemplos de nuevas formas de enlace, busque macros que comiencen 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 ...)))]))
El documento Automata via Macros presenta una perla de programación funcional en la implementación de máquinas de estados finitos a través de macros en Scheme.
El libro The Reasoned Schemer finaliza con una implementación completa basada en macro de miniKanren, el lenguaje de programación lógica utilizado en el libro. Este documento presenta miniKanren y su implementación más formal y concisa que en el libro.
Los uso cuando los procedimientos no son suficientes.
Tenía una macro de curry
cuando solía hacer muchos esquemas en mi palma. Fue muy útil.
Las macros de esquema le permiten agregar características que los autores del idioma original no incluyeron; 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.
He escrito una macro que proporciona sintaxis infija. Nada demasiado sofisticado; sin precedencia Aunque generalmente estoy de acuerdo con la sintaxis de prefijo, prefiero infix para <y>.