Translate

sábado, 11 de junio de 2016

Macros

Se utilizan para generar código en lugar de realizar necesariamente algo.

Antes de comenzar con la macro voy a explicar algunas consideraciones sobre la sintaxis.

Una comilla hacia la izquierda (`) antes de cualquier expresión detiene la evaluación de la lista que le sigue del mismo modo que la comilla simple (')

> `(1 2 3)
(1 2 3)
> '(1 2 3)
(1 2 3)

Sin embargo, en la expresión que tiene la comilla hacia la izquierda, cualquier sublista precedida por una coma (,) será evaluada. Vea los efectos de la coma en la siguiente expresión:

> `(1 2 (+ 1 2))  
(1 2 (+ 1 2))

> `(1 2 ,(+ 1 2))  
(1 2 3)

Existe una variante de la coma (,) que es la coma con arroba (,@). Lo que hace ,@ es devolver los valores que se encuentran dentro de la lista que se devuelve, es decir la misma lista pero sin los parentesis. De esta manera se pueden "agregar" los valores devueltos a una lista que la contiene. Puedes ver la diferencia entre , y ,@ en las siguientes expresiones:

> `(and ,(list 1 2 3)) 
(AND (1 2 3))
> `(and ,@(list 1 2 3)) 
(AND 1 2 3)

También puedes usar ,@ para agregar valores en el medio de una lista:

> `(and ,@(list 1 2 3) 4) 
(AND 1 2 3 4)

Bien ;-) comencemos con la macro. Para crear una macro utilizamos defmacro.

(defmacro si-ocurre (condicion &rest cuerpo)

Si se verifica que "condicion" es verdad, la macro ejecuta las sentencias de "cuerpo".
Falta colocar que va a hacer la macro.

(defmacro si-ocurre (condicion &rest cuerpo)
    `(if ,condicion (progn ,@cuerpo) (format t "No puede conducir ~%")))

La coma (,) antes de "condicion" significa que la lista que se pasa como condicion será evaluada. La ,@ antes de "cuerpo" indica que se agregan las sentencias a la lista que la contiene, es decir, la lista con (progn s1 s2 ... sn), pues el argumento que se pasa a cuerpo es una lista de listas (s1 s2 ... sn)

Recordemos que &rest permite pasar un numero arbitrario de argumentos a la función o macro, y estos quedan dentro de una lista que los contiene. Por lo tanto "cuerpo" contendrá una lista de listas. 

Con esto se genera una nueva macro que recibe condiciones y ejecuta un cuerpo de sentencias. Bien, el poder de las macros permite que se escriba muy poco código para realizar un programa. Ademas hace mas claro el programa, evitando el uso de progn.
Probemos nuestra macro:

> (setf *edad* 16)
> (si-ocurre (>= *edad* 16) 
     (print "Ya tienes 16 años o mas")
     (print "Estas listo para conducir")
     (terpri))

"Ya tienes 16 años o mas")
"Estas listo para conducir"

Otra vez...

> (setf *edad* 15)
> (si-ocurre (>= *edad* 16) 
     (print "Ya tienes 16 años")
     (print "Estas listo para conducir")
     (terpri))

"No puede conducir"

Ok! .-) Saludos

sábado, 4 de junio de 2016

Crear un ejecutable (portable)

Bien, esto es muy fácil. Vamos a usar SBCL (disponible en http://sbcl.org/platform-table.html) y LTK. Necesitamos primero crear la aplicación:

(defpackage :mi-programa
      (:use :common-lisp :ltk)
      (:export #:main))

(in-package :mi-programa)

(defun main ()
     (setf *debug-tk* nil)
     (with-ltk ()
          (let ((b (make-instance 'button
                                                 :text "Hola mundo!"
                                                  :command (lambda ()
                                                                                 (do-msg "Adios!")
                                                                                 (setf *exit-mainloop* t)))))
                 (place b 100 100))))

Hay que guardarlo, obviamente en un archivo de texto, yo lo guarde como: ventanita.lisp. (use el emacs para escribirlo). Correcto!, ahora hay que construir la aplicación, se puede usar un script, yo sin embargo prefiero hacerlo directamente en forma manual desde el intérprete del SCBL (aclaro que coloco la carpeta donde yo guarde mis archivos: "mis-programas")

> (compile-file "c:/mis-programas/ltk.lisp") ;hay que esperar que termine el proceso! :-) luego...
> (load "c:/mis-programas/ltk.fasl")
> (compile-file "c:/mis-programas/ventanita.lisp")
> (load "c:/mis-programas/ventanita.fasl")
> (save-lisp-and-die "c:/mis-programas/ventanita.core")

Si todo sale bien, el SCBL se cierra y se genera ventanita.core.

Hay que copiar el archivo sbcl.exe que se encuentra en la carpeta de instalación del programa en la carpeta donde esta "ventanita.core". Yo lo tengo en "C:\Program Files\Steel Bank Common Lisp\1.3.6>". Ahora hay que crear un archivo de proceso de lotes que invoca a nuestro pequeño programa de ejemplo. En el caso de Windows se crea un archivo de texto: ventanita.bat y se escribe en éste la siguiente línea:

sbcl --core ventanita.core --noinform --eval "(progn (mi-programa:main) (quit))"

Genial!!! Ahora solo hay que hacer doble click en nuestro archivo ventanita.bat para ejecutar el programa. También se puede crear un acceso directo a ventanita.bat!!! 




Para llevarlo a otra PC y ejecutarlo, solo necesitas tres archivos:

sbcl.exe
ventanita.core
ventanita.bat

Que podrían estar comprimidos en un solo .zip. 
Gracias por mirar y compartir este blog. Saludos y ojalá les guste la publicación.


Aclaración: Si tenemos alguna distribución linux, tenemos que crear un script con la extensión .sh y en las propiedades del archivo hay que activarlo como "archivo ejecutable". En la primera del script va: #! /bin/bash. Aquí hay una guía para generar scrpits en linux: http://www.escomposlinux.org/fserrano/index_163.html 
El archivo que necesitas en el caso de contar con linux se llama sbcl (a secas) para encontrarlo abre una terminal y tipea: which sbcl