2.2. Funciones

Una vez conocidos los tipos de datos pasaremos a estudiar cómo utilizarlos. LISP es un lenguaje de programación funcional, es decir que suministra funciones para la manipulación de los datos.

Los programas LISP se estructuran como formas y funciones. Según Cortés y Sierra*,

una FORMA es "una expresión simbólica en posición de ser evaluada. El cómputo de valores, en LISP, se realiza simplemente mediante la evaluación de una FORMA. Todas las FORMAS tienen valor, sean estas constantes numéricas, átomos literales o expresiones simbólicas. Uno de los errores más típicos al programar en LISP es el de tratar de evaluar una FORMA que no tiene valor. El valor de una FORMA es el resultado de evaluarla...
Hay que remarcar que los términos expresión simbólica y FORMA pueden aplicarse a la misma entidad; su aplicación dependerá del contexto. Una LISTA puede considerarse como un dato, como una expresión simbólica o considerarse como parte de un procedimiento; la misma LISTA puede ser considerada como una FORMA" .

Las formas se evalúan (en relación con determinado contexto) para producir valores y efectos colaterales. Las funciones se invocan aplicándolas a argumentos. (Guy L. Steele Jr., Common Lisp the Language, capítulo 5). En el entorno Visual LISP se identifican como FORMAS las funciones de usuario definidas dentro de un fichero fuente LSP. Al cargar un programa se recibe la confirmación de la carga exitosa del mismo mediante el siguiente mensaje:

Las funciones son conocidas en matemáticas. Mediante ellas se describe algún tipo de relación entre un grupo de valores. La adición y la multiplicación son funciones simples. Una función más compleja sería: f(x)=3x2+2x-15
Esta última función también describe una regla de cálculo o algoritmo. Las funciones realizan los cálculos (en términos LISP, evaluación) utilizando para ello sus argumentos y devuelven un resultado. A iguales argumentos corresponderán iguales resultados.
Según Cortés y Sierra**:

En LISP, los programas se construyen a partir de la composición de funciones. Esto permite que tales programas expresen sus propósitos más claramente que los programas convencioneles, y que resulten más fáciles de entender y de mantener, además de ser más fáciles de construir.

AutoCAD identifica sus funciones LISP primitivas como el tipo de dato SUBR, mientras que las formas definidas a partir de ellas pertenecen al tipo de dato USUBR o "sub-rutina de usuario" La función typedevuelve los tipos correspondientes. La llamada a una función toma la forma de una lista cuyo primer elemento es un átomo simbólico que representa a la función llamada. El resto de los elementos de esa lista pueden ser átomos y otras listas. Estas sublistas se consideran también llamadas a funciones y se evalúan para que su valor resultante pueda ser pasado como argumento a la función que las contiene.

FUNCIONES PRIMITIVAS

Describimos una serie de funciones como ‘primitivas’ en el sentido de que están definidas en la norma del lenguaje, para distinguirlas de las funciones creadas por el usuario a partir de aquéllas. En LISP se llama a una función mediante la siguiente sintaxis:
(NOMBREFUNCION <Argumento_1> ... <Argumento_n>)
La suma de dos números sería (+ 5 1)
Para evaluarla LISP procede de la siguiente manera:
a. Lee la expresión completa (+ 5 1)
b. La interpreta como una llamada a una función y la identifica como SUMAR <+>
c. Interpreta 5 como primer argumento y 1 como segundo. El paréntesis de cierre le indica que no hay más argumentos.
d. La función <+> se evalúa para 5 y 1, devolviendo 6 como resultado, que a falta de otro destino es impreso en pantalla.
Programar LISP significa llamar a funciones. Básicamente esto se hace usando el tipo de dato LISTA. Cualquier lista que no tenga otra interpretación como forma especial se considerará una llamada a una función, donde el primer término se tomará como el nombre de la función y el resto como sus argumentos. Las listas de llamadas a función pueden estar anidadas, es decir, que una llamada a función se puede estar utilizando como argumento en otra lista que corresponda a una llamada a otra función. El resultado de la evaluación de cada nivel de anidación es devuelto al nivel de superior, hasta llegar al nivel más alto, cuyo valor devuelto se imprimiría en la pantalla de texto o la línea de comandos.

ARGUMENTOS FUNCIONALES

De lo expuesto más arriba se concluye que en LISP una función es además un objeto de datos que puede ser suministrado a otra función como argumento. Esta posibilidad contribuye a la facilidad con que LISP se puede adaptar a las necesidades de cualquier programa mediante la incorporación de nuevas funciones que en su comportamiento resultan idénticas a las primitivas.

Un programa que admite funciones como datos debe también suministrar alguna manera de invocarlas. Esto se logra en Visual LISP mediante la función APPLY.

APPLY

(apply función lista-args)

APPLY, como su nombre en inglés indica, aplica una función (que recibe como primer argumento) a una lista de argumentos. La función puede ser un objeto de código compilado, una expresión-lambda, o un símbolo. En este último caso se utiliza el valor funcional global de dicho símbolo, aunque éste no puede ser una forma especial.

_$ (apply '+ '(2 4 6))
12
_$ (apply '(lambda (x y z)(+ x y z)) '(2 4 6))
12
_$ (apply 'quote '(2 4 6))
; error: bad QUOTE syntax: ((QUOTE 2) (QUOTE 4) (QUOTE 6))
_1$
; reset after error

Obsérvese el error provocado por utilizar la forma especial QUOTE.

Otras muchas funciones LISP requieren argumentos funcionales. Entre las de uso más frecuente están las funciones de mapeado. MAPCAR, por ejemplo toma dos o más argumentos: una función y una o más listas (tantas como parámetros requiera la función) y aplica la función sucesivamente a los elementos de cada lista, devolviendo una lista con los resultados.

_$ (mapcar '+ '(1 2 3) '(10 100 1000))
(11 102 1003)

Otras muchas funciones admiten funciones como argumentos. Entre las más utilizadas tenemos VL-SORT y VL-REMOVE-IF. La primera es una función de ordenación de uso general. Requiere una lista y un predicado, y devuelve una lista ordenada pasando sus elementos dos a dos al predicado.

_$ (vl-sort '(3 2 1 3) '<)
(1 2 3)

VL-REMOVE-IF acepta una función y una lista, y devuelve todos los elementos de la lista para los cuales la función devuelva NIL (falso).

_$ (vl-remove-if 'numberp '("a" 3 4 "c" 5 "d" "e"))
("a" "c" "d" "e")

El programar nuevas funciones utilitarias que aceptan argumentos funcionales es una parte importante del estilo de programación funcional que caracteriza a LISP.

FUNCIONES ARITMÉTICAS BÁSICAS

Las funciones aritméticas que tienen como argumento un número devuelven distintos valores dependiendo de que el argumento proporcionado sea un número entero o real. Si todos los argumentos son enteros, el valor devuelto será entero. Por el contrario, si alguno o todos los argumentos son reales, el valor devuelto será un número real. Por ejemplo:
(/ 12 5) devuelve 2, mientras que (/ 12.0 5) devuelve 2.4
Los argumentos de una función aritmética no son necesariamente números. Cualquier otra función que devuelva un número como resultado es admisible como argumento de una función aritmética. Ejemplo (* (+ 1 5)(- 20 10))

FUNCIONES BÁSICAS DE TRATAMIENTO DE CADENAS

Para el tratamiento de cadenas tenemos funciones que permiten unificar cadenas diferentes, extraer subcadenas de una cadena mayor, determinar cuántos caracteres hay en una cadena y transformar los caracteres a mayúsculas o minúsculas. El predicado WCMATCH permite determinar la semejanza de cadenas utiliando comodines.

FUNCIONES BÁSICAS DE ACCESO A LISTAS

Una lista es una manera de representar un conjunto de átomos y de otras listas. Una lista tiene la forma de un paréntesis de apertura "(" seguido de una serie de átomos o listas, seguido por otro paréntesis de cierre ")". De manera que cualquier cosa encerrada entre paréntesis será considerada una lista. Una lista pasada al evaluador LISP será tratada como una expresión simbólica (S-expresión), es decir, una llamada a función y se considerará el primer término de la lista como el nombre de la función. Para que una lista sea tratada como dato y no como una expresión simbólica debe estar contenida en la forma especial QUOTE. Las funciones básicas cuya comprensión es imprescindible para el acceso a la información contenida en listas se pueden reducir a cuatro: QUOTE, CAR, CDR, y NTH.

FUNCIONES DE CONSTRUCCIÓN DE LISTAS

Con las funciones del epígrafe anterior podemos descomponer listas, accediendo a suscomponentes a distintos niveles de anidación. Existen otras funciones que podemos utilizar para componer nuevas listas a base de elementos individuales, ya sean átomos u otras listas. CONS, LIST y APPEND son funciones que construyen listas por distintos procedimientos y con resultados diversos, por lo que es necesario distinguirlas bien.


* Cortés, Ulises y Sierra, Carlos. LISP. Editorial Marcombo, Barcelona-Máxico, 1987. pág. 44
** ibid. pág. 43