Hoy veremos...
• Conceptos generales
• Quasiquotation
• Macros en Scheme
• Ejemplos de macros
miércoles 23 de marzo de 2011
Referencias
• Capítulo 3.7 Programming Language Pragmatics: Macro Expansion
miércoles 23 de marzo de 2011
Definición de macro
• Una macro consiste en una plantilla o meta-expresión que define un patrón de sustitución formado por unas variables libres y unas expresiones textuales.
• Es una técnica de generación de código
• Se realiza en la fase de preprocesamiento (en lenguajes compilados como C o C++)
• Previamente a la evaluación de la expresión (en lenguajes interpretados)
• Las macros son un meta-lenguaje, en el sentido de que permiten controlar y definir expresiones del propio lenguaje
• No están sometidas a la sintaxis del lenguaje
miércoles 23 de marzo de 2011
Evolución histórica de las macros
• Orígen de las macros: ensamblador
• Se incorporan en lenguajes más próximos al ensamblador como C y en lenguajes avanzados como LISP o Scheme como una posibilidad de extender el lenguaje
• En la actualidad no se usan demasiado, aunque su característica de meta-programación ha dejado una huella muy importante en los lenguajes de programación:
• Anotaciones en Java
• Scaffolding en Ruby & Rails
• Herramientas de MDA de generación automática de código
miércoles 23 de marzo de 2011
Macros en C
• Ejemplos de Macros:
• Una llamada a la macro:
• Se sustituirá (expansión de la macro) por:
#define LINE_LEN 80#define MAX(a,b) ((a) > (b) ? (a) : (b))#define SWAP(a,b) {int t = (a); (a) = (b); (b) = t;}
x = MAX(p+q, r+s);
x = ((p+q) > (r+s) ? (p+q) : (r+s))
miércoles 23 de marzo de 2011
Las macros permiten definir nuevos lenguajes
• Ejemplo en C:
• Lo probamos:
• Esta posibilidad es mucho más potente en las macros de Scheme
• Lenguajes de dominio: las universidades y departamentos de investigación inventan lenguajes adaptados especificamente a dominios específicos como robótica. Es muy fácil diseñar prototipos de estos lenguajes con las macros de Scheme
#define then#define begin {#define end ;}
if (i > 0) then begin a = 1; b = 2 end
miércoles 23 de marzo de 2011
Problemas de la expansión en C
• El preprocesador de C extiende la macro de forma ciega sin tener ninguna relación con el proceso de compilación posterior
• Esto puede producir errores. Por ejemplo, si llamamos a MAX(x++, y++) la expansión de la macro produce el siguiente resultado:
• LISP y Scheme utilizan las llamadas macros higiénicas que encapsulan implícitamente sus argumentos y evitan los errores de las macros de C
((a++) > (b++) ? (a++) : (b++))
miércoles 23 de marzo de 2011
Quasiquotation
• La forma especial quasiquote junto con unquote permite evaluar de forma arbitraria las expresiones que nos interesan en una lista:
• Se utiliza el símbolo backquote y la coma:
(define bar 2)(quasiquote (foo (unquote bar) baz)) --> (foo 2 baz)
`(foo ,bar baz) --> (foo 2 baz)
(define a 2)(define b 'hola)
'(1 a b)(quasiquote (1 ,a ,b))`(1 ,a ,b)`(1 ,a ,b ,c)`(1 ,+ ,-)
miércoles 23 de marzo de 2011
Macros en Scheme
• Se basan en las formas especiales define-syntax y syntax-rules
• Sintaxis de una macro:
• Ejemplo: mi-or
(define-syntax <keyword> (syntax-rules (<literales>) ((<patron-1> <plantilla-1>) ... (<patron-n> <plantilla-n>))))
(define-syntax mi-or (syntax-rules () ((mi-or) #t) ((mi-or e) e) ((mi-or e1 e2 e3 ...) (if e1 #t (mi-or e2 e3 ...)))))
miércoles 23 de marzo de 2011
Reglas de evaluación de una macro
• Para evaluar una llamada a una macro (op exp_1 ... exp_n) debemos seguir las siguientes reglas:
• Buscar la definición de la macro. Buscar la forma especial define-syntax en la que aparece op como clave.
• Emparejar. Buscar en la definición de la macro la regla sintáctica con la que es posible emparejar la expresión (op exp_1 ... exp_n) que estamos evaluando. Si hay más de una regla con la que se puede emparejar la expresión, escogemos la primera de ellas.
• Transformar. Aplicar la regla para transformar la expresión.
• Evaluar. Evaluar la expresión resultante. En el caso en que la expresión resultante contenga una llamada a una macro se evaluará siguiendo estas mismas reglas.
miércoles 23 de marzo de 2011
Expansión de una macro
• Expansión de la llamada a la macro:
(mi-or (equal? x 2) #f #t (equal? y 3))
miércoles 23 de marzo de 2011
Sintaxis alternativas válidas
(define-syntax mi-or (syntax-rules () ((_) #t) ((_ e) e) ((_ e1 e2 e3 ...) (if e1 #t (mi-or e2 e3 ...)))))
(define-syntax mi-or (syntax-rules () ((op) #t) ((op e) e) ((op e1 e2 e3 ...) (if e1 #t (mi-or e2 e3 ...)))))
miércoles 23 de marzo de 2011
Depuración de macros
(define-syntax mi-or (syntax-rules () ((op) ‘#t) ((op e) ‘e) ((op e1 e2 e3 ...) ‘(if e1 #t (mi-or e2 e3 ...)))))
miércoles 23 de marzo de 2011
Macro make-procedure
(define-syntax make-procedure (syntax-rules () ((make-procedure (x ...) expr ...) (lambda (x ...) expr ...))))
miércoles 23 de marzo de 2011
Macro mi-let
(define-syntax mi-let (syntax-rules () ((mi-let ((x v) ...) e ...) ((lambda (x ...) e ...) v ...))))
miércoles 23 de marzo de 2011
Macro mi-cond
(define-syntax mi-cond (syntax-rules (=> else) ((mi-cond (else => expr)) expr) ((mi-cond (test1 => expr1)) (if test1 expr1)) ((mi-cond (test1 => expr1) (test2 => expr2) ...) (if test1 expr1 (mi-cond (test2 => expr2) ...)))))
miércoles 23 de marzo de 2011
Macro multi-print (paradigma procedural)
(define-syntax multi-print (syntax-rules () ((multi-print arg1 arg2 ...) (begin (print arg1) (newline) (multi-print arg2 ...))) ((multi-print) #t)))
miércoles 23 de marzo de 2011
Top Related