2011-10-12 4 views
8

Estoy desconcertado al tratar de crear el equivalente de esta macro trivial (en Common Lisp) en el MIT Esquema:¿Cómo se escribe una macro Scheme MIT para devolver un formulario lambda?

(defmacro funcify (exp) 
    `(lambda (x) ,exp)) 

Se trata de un simple proyecto personal, una ecuación numérica solucionador basa en las funciones incorporadas en la segunda conferencia SICP. No me importa que esta macro no sea "segura" o "higiénica" o capturará una variable si el exp hace referencia a cualquier símbolo que no sea 'x'. Me gustaría ser capaz de escribir

(solv '(* 60 x) '(* 90 (- x 1))) 

donde solv es:

(define (solv lh-exp rh-exp) 
    (solve (funcify lh-exp) (funcify rh-exp))) 

en lugar de tener que escribir

(solve (lambda (x) (* 60 x)) (lambda (x) (* 90 (- x 1)))) 

Pero no puede encontrar la manera de hacer esto utilizando Reglas de sintaxis del esquema MIT.

He intentado esto pero no funciona:

(define-syntax funcify 
    (syntax-rules() 
    ((funcify y) (lambda (x) y)))) 
;Value: funcify 

(funcify x) 
;Value 17: #[compound-procedure 17] 

((funcify x) 10) 
;Unbound variable: x 

He intentado otras cosas probablemente no vale la pena mencionar que implica eval pero fue en vano.

Además, referencias a buenos tutoriales (no referencias) en el sistema macro de Scheme que comienzan con pequeños ejemplos simples y compilación, con amplios comentarios, y en particular muestran cómo convertir macros LISP estilo comas de comilla inversa (que a mí altamente intuitivo) al sistema de macros de sintaxis de Scheme sería genial.

Respuesta

4

Usted puede hacer básicamente lo mismo que con defmacro utilizando explicit-renaming macros . La única diferencia significativa es que tendrá que desestructurar el formulario de entrada usted mismo:

(define-syntax funcify 
    (er-macro-transformer 
    (lambda (form rename cmp) 
     (let ((exp (cadr form))) 
     `(,(rename 'lambda) (x) ,exp))))) 
+0

+1 para la implementación de ER (que es compatible con el Esquema MIT). :-) –

+1

@ ChrisJester-Young Gracias por la corrección de errores. :) –

+0

+1. Gracias un montón. define-sintaxis es completamente desconcertante, pero sospecho que es muy poderoso, me gustaría aprenderlo mejor, ¿alguna referencia para acelerarlo? Estoy aceptando tu respuesta porque da una función que funciona en el Esquema MIT, ojalá pudiera aceptar la respuesta de Chris porque también señala que solv también debe ser una macro de reglas de sintaxis. – Bogatyr

7

No se puede hacer en syntax-rules. Fin de la historia.

Inyectar un identificador arbitrario (x, en su caso) en la expresión de salida requiere romper la higiene, y syntax-rules no proporciona ningún medio para romper la higiene. Tendrá que usar un sistema macro de nivel inferior para hacer esto. MIT Esquema utiliza el cambio de nombre explícito (véase la respuesta de Matthias Benkard), pero para otras implementaciones esquema que utilizan syntax-case, se puede hacer así:

(define-syntax funcify 
    (lambda (stx) 
    (syntax-case stx() 
     ((_ body) 
     (with-syntax ((x (datum->syntax stx 'x))) 
     #'(lambda (x) 
      body)))))) 

La clave es el bit (datum->syntax stx 'x), que inyecta el símbolo x como si fuera en el contexto sintáctico de la invocación funcify.

Por cierto, su solv también debe haber una macro, no un procedimiento, pero al menos puede ser un syntax-rules macro:

(define-syntax solv 
    (syntax-rules() 
    ((_ lhs rhs) (solve (funcify lhs) (funcify rhs))))) 
+0

+1 Muchas gracias por su respuesta, y por señalar que solv también debe ser una macro. Para empezar, las macros son complicadas, pero las macros de sintaxis * de Scheme son probablemente lo más difícil que he visto hasta ahora en un lenguaje, y he estado programando (principalmente blubs, pero hice mi tesis de MS en CL) por más de 30 años. años. – Bogatyr

+0

@Bogatyr: Espera a que llegues a las continuaciones. ;-) (En serio, sin embargo, Scheme es un lenguaje bastante grande, conceptualmente, a pesar de que la especificación R5RS se ajusta dentro de "50 páginas".) –

Cuestiones relacionadas