Translate

miércoles, 16 de enero de 2013

Estructura de Control de Programa (Tercera parte)


Progn y Let

Son estructuras que sirven para organizar los programas. Antes de comenzar veamos la manera de organizar un programa lisp (archivo de texto con la extensión .lisp o .lsp) , sería asi:

;;;; -----------------------------------------------------------------------------------------------------------------------

;;;; Cargo los archivos que tengan funciones externas con load

(load "archivo-a-cargar.fas")

;;;; Ingreso en el paquete a utilizar

(use-package :paquete-a-utilizar

;;;; Defino e inicializo las variables globales:

(defvar *valor* 8)

(defvar *cadena* "holaaaa")

(defvar *variable* nil)

;;;; Por convención, las variables globales van entre asteriscos
;;;; Defino ahora las funciones internas

(defun mi-funcion (argumentos) (cuerpo-expresiones))
(defun otra-funcion (argumentos (cuerpo-expresiones))


;;;; Ahora comienza el cuerpo del programa:

(expresión-1)
(expresión-2)
     ...........

(expresión-n)

;;;; -----------------------------------------------------------------------------------------------------------------------------

Prog1, Prog 2, Progn


Sirven para agrupar varias expresiones, dentro de un if por ejemplo o dentro de un when. Su sintaxis es la siguiente:

(prog1
       (exprexion-1)
       (expresion-2)
             ..........
       (expresion-n))

Las prog evaluaran cada una de las expresiones, a menos que se desactive la evaluación con comilla simple ('). Prog1 evaluará todas las expresiones y devolverá (expresion-1) evaluada cuando termina. Prog2 hará lo mismo y devolverá la evaluación de (expresion-2) cuando acaba. De la misma manera Progn irá evaluando las expresiones y devolverá la evaluación de la última.
Veamos unos ejemplos de prog:


> (prog1 (set 'x 4) (set 'y 9) (set 'z (* x y)) (format t "~s * ~s  = ~s" x y z))
4 * 9 = 36
4

> (prog2 (set 'x 4) (set 'y 9) (set 'z (* x y)) (format t "~s * ~s  = ~s" x y z))
4 * 9 = 36
9

> (progn (set 'x 4) (set 'y 9) (set 'z (* x y)) (format t "~s * ~s  = ~s" x y z))
4 * 9 = 36
NIL

 let

 Let sirve para organizar el programa, se puede vivir sin let, pero es mas cómodo usarlo, lo mismo sucede con una almohada :-D. Consta de dos partes, una de asignación de valores a símbolos y un cuerpo de expresiones.
Su sintaxis es:

(let ((simbolo-1 valor-1)
     (simbolo-2 valor-2)
                ...............
     (simbolo-n valor-n))

    (expresion-1)
    (expresion-2)
       ...............
    (expresion-m))

Es simple lo que hace let, cuando comienza asigna a cada símbolo el valor que se escribe al lado. Es decir, a simbolo-1 asignará el valor-1, a símbolo-2 el valor-2, y así sucesivamente, hasta simbolo-n. Luego evaluará el cuerpo de expresiones: (expresion-1) (expresion-2) .... (expresion-n).

Ejemplo:

(let ((x 76)
      (y 423)
      (z (* x y)))

   (format t "~s * ~s = ~s" x y z))


76 * 423 = 36
NIL

Algo que hay que tener en cuenta es que las variables usadas dentro de let tienen un alcance local. Es decir los valores dados dentro del mismo let no afectarán a las variables x, y, z del mismo nombre que estén afuera y que seguirán teniendo los mismos valores. Si lo hemos hecho todo desde el interprete, podemos consultar los valores de esas variables:

> x
4

> y
9

> z
36

lunes, 14 de enero de 2013

Estructuras de Control de Programa (Segunda parte)


Iteraciones o bucles de programa



dolist

Sintaxis

(dolist (lista-inicializacion) (cuerpo))

dolist toma una lista de inicialización y un cuerpo.La lista de inicialización contendrá una variable que tomara los elementos de una lista para cada iteración, la lista de elementos, y una variable que se devolverá como resultado.

(elemento lista-elementos resultado)

En el cuerpo se iterará para cada elemento de la lista, y se irá almacenando cada uno de esos valores en la variable elemento.

Un ejemplo:

> (set 'resultado 1)
1

> (set 'lista-elementos '(2 3 5 7 11 13 17 19 23))

> (dolist (elemento lista-elementos resultado)
            (set 'resultado (* elemento resultado))) ;multiplica cada elemento de la lista y acumula en resultado

Hay que tener en cuenta que "resultado", contendrá el valor devuelto al finalizar el bucle. Si se omite el argumento "resultado" se devolverá NIL al terminar el proceso.

dotimes


Es similar a dolist, solo que la variable iteradora sera siempre un numero natural, comenzando por cero (naturales incluido el cero).
La sintaxis es:

(dotimes (lista-inicializacion) (cuerpo))

Donde (lista-inicializacion) tiene la forma:

(variable-iteradora valor-maximo resultado)

El cuerpo se evaluara sucesivamente, comenzando la variable iteradora con un valor de 0 (cero), hasta alcanzar a valor-maximo menos uno. Como en el caso anterior, si se omite el argumento "resultado" se devolverá NIL al finalizar el bucle.

Ejemplo:

> (dotimes (i 10) (format t "~s" i))
0123456789
NIL

Format imprime el valor de la variable cada vez que se evalúa el cuerpo: "~s" toma el valor de la variable y lo imprime en pantalla.
Para que quede mas lindo, imprimimos uno debajo del otro y con tabulación:

> (dotimes (i 10) (format t "~% ~14t ~s" i))

"~%" equivale a "enter"
"~14t" es la tabulacion
"~s" es la variable que se imprime

Supongamos que deseamos obtener la sumatoria de (2 * i) desde 6 hasta 23 inclusive,
hacemos asi:

> (set 'sumatoria 0)

> (dotimes (i 18 sumatoria) (set 'sumatoria (+ sumatoria (* 2 (+ i 6)))))
522

loop


La forma mas facil de hacer un bucle es haciendo un loop. Para poder salir del bucle es necesario usar un (return). (return) me sirve para salir de cualquier iteraccion, obviamente hay que usarlo siempre y cuando se cumpla una determinada condicion, usando un "if" o "when", por ejemplo.

(set 'x 2)

(loop
   (set 'funcion (expt (+ 1 (/ 1 x)) x))                                ;aplica la funcion
   (format t "~8t x: ~s ~% ~8t y: ~s" x funcion)                ;muestra el valor de funcion
   (set 'x (+ x 1))                                                            ;incrementa x en uno
   (when (not (y-or-n-p "¿Desea calcular un nuevo valor?")) (return)))

La función "y-or-n-p" devuelve T (verdadero) cuando se presiona la tecla "y" y NIL (falso) cuando se presiona "n". En nuestro caso, sale del bucle, aplicando "return" cuando se presiona "n", pues esta precedido de la funcion "not" que niega el valor lógico.

do


Es la iteración mas complicada. Sirve para poder utilizar varias variables iteradoras a la vez, cada una con su propio incremento.
Su sintaxis es:

(do ((lista-inicializacion-1)
     (lista-inicializacion-2)
         ...........
     (lista-inicializacion-n))

    (condicion (expresiones-verdad))

    (expresiones-falso))

Cada lista-inicializacion-i contiene una variable-iteradora, el valor-inicial para esta variable y una funcion que incrementará ese valor:

    (variable-iteradora-i  valor-inicial  funcion-incremento)

Ejemplos de lista-inicializacion-i:

(i 1 (+ i 1))                          ;i comienza en 1 y se va incrementando en 1
(valor 7 (+ valor 4))             ;valor comienza en 7 y se va incrementando en 4
(colores '("azul" "verde" "rojo" "amarillo" "marron" "naranja") (rest colores))
                                              ;mi-lista comienza con una lista de colores
                                              ;rest va eliminando con cada iteración el primer elemento de la lista

En la primera iteracion las variables-iteradoras toman el valor-inicial. Luego se evalúa la "condicion". Si la condicion es T (verdadera) evalua las "expresiones-verdad" y termina el bucle. Si la condicion es NIL (falso), evalua las "expresiones-falso" e incrementa cada una de las variables-iteradoras, y se vuelve a evaluar "condicion".

Ejemplo de do:

(do
 ((i 1 (+ i 1))
  (colores '("azul" "verde" "rojo" "amarillo" "marron" "naranja") (rest colores)))

 ((null colores) (format t "~% ~%¡Listo, barrilete cósmico!"))

 (format t "~% ~10t El color ~s es ~10t ~s" i (first colores)))

Si la lista aun no esta vacía, se imprime el primer elemento de la lista que aun queda. :-)