1 title: Programar macros en Lisp es como reprogramar Matrix
5 <a href="images/pyfry.jpg"><img src="images/pyfry.jpg" alt="pyfry" width="300" height="225" class="alignright size-medium wp-image-581" /></a>
7 <p>Si algo echo de menos cuando programo con Python, Ruby u otro lenguaje similar son las macros de Lisp. Programar con macros (no tienen nada que ver con las macros del preprocesador de C como piensan algunos) es como ser Neo y cambiar todo lo que quieras en Matrix.</p>
9 <p>Además, ahora que se ponen de moda otra vez los <a href="http://en.wikipedia.org/wiki/Domain-specific_language">Domain Specific Languages (DSL)</a>, lo cierto es que tener el poder de las macros de tu parte te soluciona muchos problemas.</p>
11 <p>Vamos a probar con un problema fácil que resulta imposible de resolver en Python: implementar un <b>if-then-else</b> usando <b>if</b> y <b>else</b>. ¿Ein? :-D La respuesta rápida es:</p>
13 <pre>def if_then_else(cond, if_true, if_false):
19 <p>¡Vamos a probarlo!</p>
21 <pre>>>> if_then_else(True, "si", "no")
23 >>> if_then_else(False, "si", "no")
25 >>> if_then_else(True, "si", 1/0)
26 ZeroDivisionError: integer division or modulo by zero</pre>
28 <p>Y aquí nos encontramos el principal problema de esta implementación. ¿Por qué se evalua la división por 0 si se encuentra en la parte <b>else</b> y nuestra condición es <b>True</b>? La respuesta es que Python, al no tener macros ni nada parecido, solamente nos proporciona funciones para este tipo de cosas y las funciones evaluan todos sus parámetros.</p>
30 <p>Por lo tanto, resulta imposible crear estructuras tipo <b>if-then-else</b>. Y lo mismo ocurre con operadores como <b>and</b> (si el primer parámetro es falso no evaluamos el resto), <b>or</b> (si el primer parámetro es cierto no evaluamos el resto), etc.</p>
32 <p>Algunos me han sugerido soluciones usando los decoradores de Python para capturar los errores de la evaluación, pero el verdadero problema reside en la evaluación en si misma.</p>
34 <p>La solución en Lisp utiliza macros. Si usaramos funciones obtendríamos el mismo resultado que con Python.</p>
36 <pre>(defmacro if-then-else (cond if-true if-false)
37 `(if ,cond ,if-true ,if-false))</pre>
39 <p>Esta expresión es bastante legible incluso para los profanos. Se define una macro de nombre if-then-else que recibe tres parametros. La gran diferencia es que los parámetros no se evaluan cuando se evalua la macro y la evaluación de la macro nos desvuelve lo que especificamos en el cuerpo.</p>
41 <p>Para que nos entendamos, una macro es un generador de código. Si ahora ejecuto <pre>(if-then-else 'True "si" "no")</pre>, el intérprete evaluará la macro, que devolverá el resultado <pre>(if 'True "si" "no")</pre>, y ese resultado será evaluado a su vez proporcionando el resultado adecuado. Vamos a verlo.</p>
43 <pre>> (if-then-else 1 "si" "no")
45 > (if-then-else nil "si" "no")
47 > (if-then-else 1 "si" (/ 1 0))
50 <p>Ahora la división por cero ya no da error porque no llega a evaluarse</p>
52 <p>Las macros nos dan el poder de crear programas que a su vez crean programas, ya que nos permiten jugar en el núcleo mismo del lenguaje, algo que no nos permiten los lenguajes convencionales.</p>
54 <p>A pesar de su potencia, las macros tienen los llamados "problemas de higiene", algo que se ha solucionado en Scheme y que explicaré en el próximo artículo.</p>