X-Git-Url: https://git.jsancho.org/?p=blog.git;a=blobdiff_plain;f=posts%2F150.html;fp=posts%2F150.html;h=0000000000000000000000000000000000000000;hp=595c42720f06894c2ad9c706e671ec405bea20bc;hb=e7b6ce04fe8fee9ae651f50b29f6c37fef87b41d;hpb=3e096e3d39e9924369271dade89f029c40c799b5 diff --git a/posts/150.html b/posts/150.html deleted file mode 100644 index 595c427..0000000 --- a/posts/150.html +++ /dev/null @@ -1,55 +0,0 @@ -title: Programar macros en Lisp es como reprogramar Matrix -date: 2013-10-09 18:02 ---- -
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.
- -Además, ahora que se ponen de moda otra vez los Domain Specific Languages (DSL), lo cierto es que tener el poder de las macros de tu parte te soluciona muchos problemas.
- -Vamos a probar con un problema fácil que resulta imposible de resolver en Python: implementar un if-then-else usando if y else. ¿Ein? :-D La respuesta rápida es:
- -def if_then_else(cond, if_true, if_false): - if cond: - return if_true - else: - return if_false- -
¡Vamos a probarlo!
- ->>> if_then_else(True, "si", "no") -'si' ->>> if_then_else(False, "si", "no") -'no' ->>> if_then_else(True, "si", 1/0) -ZeroDivisionError: integer division or modulo by zero- -
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 else y nuestra condición es True? 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.
- -Por lo tanto, resulta imposible crear estructuras tipo if-then-else. Y lo mismo ocurre con operadores como and (si el primer parámetro es falso no evaluamos el resto), or (si el primer parámetro es cierto no evaluamos el resto), etc.
- -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.
- -La solución en Lisp utiliza macros. Si usaramos funciones obtendrÃamos el mismo resultado que con Python.
- -(defmacro if-then-else (cond if-true if-false) - `(if ,cond ,if-true ,if-false))- -
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.
- -Para que nos entendamos, una macro es un generador de código. Si ahora ejecuto
(if-then-else 'True "si" "no"), el intérprete evaluará la macro, que devolverá el resultado
(if 'True "si" "no"), y ese resultado será evaluado a su vez proporcionando el resultado adecuado. Vamos a verlo. - -
> (if-then-else 1 "si" "no") -"si" -> (if-then-else nil "si" "no") -"no" -> (if-then-else 1 "si" (/ 1 0)) -"si"- -
Ahora la división por cero ya no da error porque no llega a evaluarse
- -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.
- -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.
-