Subprogramas y bibliotecas en LISP





Cada implementación del LISP contiene una extensa biblioteca de funciones predefinidas, para el procesamiento de listas y cadenas. Los siguientes son ejemplos encontrados en la mayoría de las implementaciones. x, xl, .., xn son expresiones numéricas.

FUNCION       SIGNIFICADO
 

(ABS x)

   

Valor absoluto de x.

 

(MAX x1 x2

 

..

 

xn)

   

Valor máximo de x1, x2, .. , xn.

 

(MIN x1 x2

 

..

 

xn)

   

Valor mínimo de x1, x2, .. , xn.

 

(EXPT x)

   

Función exponencial de x, ex .

 

Además, LISP contiene poderosas facilidades para que el programador extienda el lenguaje definiendo funciones adicionales. Esta característica tiene la siguiente forma general:

 

(defun nombre (parámetros) e1 e2 … en)

 

«Nombre» identifica a la función, «parámetros» es una lista de símbolos atómicos que son los parámetros de la función y e1, e2, …, en son las expresiones que definen la función. Tres de tales funciones, llamadas «sum», «cont» y «media», se han definido en el programa anterior. Las primeras dos tienen el parámetro x, mientras que la tercera no tiene parámetros y sirve como el programa principal.

Las diferentes implementaciones del LISP contienen algunas diferencias sintácticas para la definición de funciones. Algunas de estas variaciones respecto a la forma dada son las siguientes:

 

  • (def nombre) (lambda (parámetros) e, e2 … en))

 

  • (de nombre (parámetros) e, e2 … en)

 

  • nombre: (lambda (parámetros) el e2 … en)

 

La palabra «lambda» proviene de las primeras versiones del LISP, las cuales tenían una sintaxis más parecida a la notación de Church, de la que proviene el LISP. Pero todas estas versiones sirven al mismo propósito y ninguna es intrínsecamente superior a las otras. Usamos la forma original a lo largo de este manual, suponiendo que el lector podrá asimilar las otras variaciones si es necesario.

En el corazón de la definición de función está la idea de la recursividad. Esto es al LISP como la «sentencia WHILE» al C. La definición de funciones recursivas proviene directamente de las matemáticas, como se ilustra en la siguiente definición de la función factorial.

 

factorial (n) = 1 si n <= 1

= n * factorial(n-1) si n>1

 

 

Como es evidente, la definición del factorial se basa en si misma para poder calcular el factorial de cualquier  valor particular de n > 1.

Por  ejemplo,  el  factorial  de  4  depende  de  los anteriores cálculos del factorial de 3, y así sucesivamente. El proceso termina cuando se llega al factorial de 1, que es cuando  puede completarse cada uno de los otros cálculos dependientes de los anteriores. Esta definición de función puede escribirse directamente en LISP, aprovechándose del hecho de que una función puede llamarse a si misma.

 

(defun fact (n)





(cond ((lessp n 2) 1)

(t (* n (fact (sub I n)]

 

Hemos identificado al parámetro n y definido «fact» mediante  una expresión condicional que es equivalente a la siguiente expresión en un lenguaje tipo Pascal:

 

if n<2then 1

else n * fact (n – 1)

 

En un caso, el resultado devuelto será 1, mientras que en los otros el resultado será el cálculo (* n (fact (subl n))), el cual llamará a la propia función.

Para llamar así a una función, se utiliza la misma

forma que para las funciones dadas par el LISP:

 

(nombre argl arg2…)

 

«Nombre» identifica a la función y «argl arg2…» es una serie de expresiones, correspondiente a los parámetros de la definición de la función.

Por tanto, para calcular el factorial de 4 escribimos

 

«(fact 4)»

 

El resultado de la evaluación dará la siguiente expresión

 

(* 4 (fact 3))

 

que, una vez evaluada, dará lugar a la expresión

 

(* 3 (fact 2))

 

y finalmente se llegará a lo siguiente:

 

(* 2 (fact 1))

 

Ahora, cuatro llamadas diferentes de «fact» están activas y la última devuelve finalmente el valor 1. Esto permite que se evalúe la expresión (*2 1) y que el resultado 2 se pose a la expresión (*3 2), y así sucesivamente hasta que se completan todas las activaciones.

 

 

Otras dos formas sencillas de definiciones recursivas aparecen en el programa del comienzo, una para la función «sum» y la otra para la función «cont». Cada una de ellas combina las  funciones primitivas de procesamiento de listas «car» y «cdr» con los cálculos numéricos, para llegar al resultado deseado. Aquí la recursividad es esencial porque las longitudes de las listas varían normalmente de una ejecución a la siguiente.

Un examen de la función sum con el argumento (87.5,89.5, 91.5, 93.5) muestra que, puesto que este argumento ni es «nulo» ni

es un átomo, la llamada recursiva

 

(+ (car x) (sum (cdr x)))

 

se evalúa a continuación.

 

Funciones, Variables Locales Y La Característica Program

Aunque la recursividad es el dispositivo primario para definir funciones en LISP, en algunas ocasiones es necesaria la iteración. Además, la mayoría de las funciones requieren el uso de variables locales para disponer de un almacenamiento temporal mientras realizan sus tareas. Cualquiera de estos dos requerimientos fuerzan al uso de la «característica prog» dentro de la definición de una función como sigue:

 

(defun nombre (parámetros) (prog locales) e1 e2 … en ))

 

La secuencia de expresiones e1, e2, …, en puede incluir ahora a la función go, mientras que «parámetros» y «locales» tienen el mismo significado que se dio originalmente.

En muchos casos, la naturaleza de la función fuerza la denotación explícita del resultado que ha de devolverse en la llamada. Esto se activa mediante la función «return», la cual tiene la siguiente forma dentro de una definición de función:

 

(return expresión)

 

«Expresión» es el valor que ha de devolverse a la expresión llamadora y la devolución del control se produce en cuanto se encuentra esta función. Para ilustrar esto, se muestra a continuación una interpretación iterativa de la función factorial:

 

(defun fact (n) (prog (i f) (setq f 1)

(setq i 1)

bucle (cond ((greaterp i n) (return f)) (t ((setq f (* f i))

(setq i (addl i)) (go bucle)]

 

 

Aquí tenemos las variables locales f e i inicializadas ambas a 1. La sentencia condicional etiquetada con «bucle» se repite hasta que i > n, devolviéndose en ese momento el valor resultante de f.

Si no, se realizan los cálculos

 

f:=f*i yi:=i+ I

 

y se repite el test para i > n.

 

Aunque este ejemplo ilustra el uso de la función «return», la característica prog y la iteración sirve también para subrayar la superioridad expresiva de la recursividad como dispositivo descriptivo del LISP.





También te podría gustar...

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *