0. Introducción


LISP se encuentra entre los más antiguos lenguajes deprogramación de alto nivel aún en uso generalizado. Fuedesarrollado alrededor de 1958 por John McCarthy. La idea de LISP surgióa partir de un sistema lógico llamado "lambda calculus''desarrollado por Alonzo Church. Existen diversas variantes (o dialectos) deLISP, entre las cuales se encuentran Scheme, T, etc. LISP llegó a serfundamental como lenguaje de programación para las investigaciones deInteligencia Artificial, y sigue aún hoy siendo uno de los másutilizados en este campo. En la década de los '80 se intentóestandardizar el lenguaje. Como resultado surgió el Common LISP cyasespecificaciones se recogen en Common LISP: TheLanguage, 2nd Edition (CLTL2). Common LISP es actualmente el dialectomás difundido y la base para el desarrollo de numerosasimplementaciones.

Las razones para ello se encuentran en el hecho de poseer una de las formasde sintaxis menos restrictivas entre los lenguajes de alto nivel. Esto facilitasu aprendizaje, al ser muy corto el número de estructuras y funcionesque el estudiante debe conocer para llegar a dominar las técnicas deprogramación en este lenguaje. De hecho, este curso se propone lautilización de un subconjunto de las muchas funciones disponibles paracon ellas examinar las técnicas que hacen de LISP un lenguaje tanespecial.

LISP: PARADIGMA DEL ESTILO DE PROGRAMACIÓNFUNCIONAL

Una de Las características de LISP es la posibilidad de tratar laspropias funciones como datos. En LISP, funciones e incluso programas enterospueden ser utilizados directamente como entrada a otros programas o subrutinas.En esto el prototipo para la concepción del lenguaje ha sido laestructura de las funciones matemáticas. Todos sabemos cómoresolver una expresión del tipo (8 * ((17 + 3) / 4)). Primerohallaríamos el resultado de 17 + 3, que entonces dividiríamosentre 4, para el resultado multiplicarlo por 8. Es decir, que iríamosresolviendo los paréntesis más interiores y pasando losresultados a las operaciones descritas en los paréntesis que loscontienen.

(* 8 (/ (+ 3 17) 4)) sería la función LISP equivalente.

*, / y + son nombres de funciones LISP. Los números en (+ 3 17) sonlos argumentos que se pasan a la función '+'. Pero en (/ (+ 3 17) 4) ala función '/' se le está pasando un argumento numérico 4,pero también (+ 3 17), otra función con dos argumentosnuméricos. Esta es la esencia de un lenguaje de programaciónfuncional y por eso decimos que LISP lo es. "Programación funcionalsignifica, segú Graham (On Lisp, pág. 28), escribir programas queoperan a base de devolver valores en lugar de producir efectos colaterales.Estos efectos colaterales incluyen cambios destructivos en los objetos y laasignación de variables (con setq, por ejemplo)." Sigue explicandoGraham (pág. 31) que "una función destructiva es una quepuede alterar los argumentos que se le pasan. Sólo unos pocos operadoresLISP están pensados para producir efectos colaterales. En general, losoperadores propios del lenguaje están pensados de manera tal que seinvoquen para obtener los valores que devuelven. Nombres como sort (vl-sort),remove (vl-remove) o substitute (subst) no deben llamarnos a engaño. Siusted quiere efectos colaterales, utilice setq sobre el valor devuelto. Estamisma regla sugiere" -sigue explicando Graham- "que algunos efectoscolaterales son inevitables. Tener la programación funcional como idealno implica que los programas nunca debieran tener efectos colaterales.Sólo quiere decir que no deben tener más de los necesarios."

Esta característica de la programación funcional no esarbitraria. Citando de nuevo a Graham:

Los programadores LISP no adoptaron el estilo funcional porrazones meramente estéticas. Lo usan porque facilita su trabajo. En elentorno dinámico de LISP, los programas funcionales pueden ser escritosa una velocidad poco usual, y a la vez, pueden ser inusualmente confiables.
En LISP es comparativamente fácil el depurar los programas. Una grancantidad de información se encuentra disponible en tiempo deejecución, lo que ayuda en el rastreo de los errores. Pero aúnmás importante es la facilidad con la que pueden probarse losprogramas. No es necesario el compilar el programa para probar sufuncionamiento como un todo. Podemos probar las funciones individualmente,llamándolas desde el nivel superior del evaluador.
Esta comprobación de carácter incremental es tan valiosa que elestilo de programación LISP ha evolucionado para aprovecharla. Losprogramas escritos en un estilo funcional pueden ser comprendidos unafunción a la vez, y desde el punto de vista del lector, esta es suprincipal ventaja. Sin embargo, el estilo funcional se adapta perfectamente ala comprobación incremental: los programas escritos en este estilopueden ser también probados una función a la vez. Cuandouna función ni examina ni altera el estado exterior, los errores seharán aparentes de inmediato. Una función asídiseñada sólo puede afectar el mundo exterior a través delos valores que devuelve. En la medida que estos valores sean los esperados,podemos confiar en el código que los produjo.
Los programadores LISP experimentados de hecho diseñan sus programas demanera que puedan ser fácilmente probados:

  1. Tratan de aislar los efectos colaterales en unas pocas funciones, de manera que la mayor parte del programa pueda ser escrito en un estilo puramente funcional.
  2. Si una función debe producir efectos colaterales, tratan de que al menos posea una interfaz funcional.
  3. Le dan a cada función un propósito único y biendefinido

Cuando acaba de escribirse una función, pueden probarla sobre unaselección de casos representativos, y una vez hecho esto pasar a lapróxima función.

En LISP, como en cualquier otro lenguaje, el desarrollo se lleva a cabo enciclos de escritura y comprobación. Pero en LISP el ciclo es muy corto:funciones aisladas, e incluso partes de funciones. Y si comprobamos todo amedida que lo escribimos, sabremos dónde buscar cuando se produzca unerror: en lo último que se escribió.

Graham, On Lisp, pág. 37 y 38.

Lisp mas allá de AutoCAD

Hay implementaciones de LISP para uso en el desarrollo de aplicaciones de todo tipo. El lenguaje se ha normalizado con el nombre de Common LISP (norma ANSI).
Existen entornos de desarrollo disponibles muchas veces como software gratuito a través de internet. Para más información se recomienda acceder a los siguientes sitios WEB:

Compiladores y entornos de desarrollo Common LISP para WINDOWS:

Los tres primeros son productos comerciales, pero todos ofrecen versiones gratuitas de evaluación perfectamente adecuadas para el aprendizaje del lenguaje.
CLISP es totalmente gratis (GPL).

LispWorks es especialmente recomendable por su claro entorno de desarrollo (IDE), la capacidad de construir fácilmente aplicaciones con una interfaz gráfica de usuario (GUI) y la licencia de evaluación que permite el utilizar el producto por tanto tiempo como se desee, con sólo unas limitaciones de menor entidad. Le acompaña una muy completa referencia en formato HTML y PDF.

Allegro CL posee herramientas para el desarrollo de interfaces gráficas mucho más completas, pero la licencia de evaluación debe ser renovada cada mes.

Corman LISP sólo brinda la posibilidad de utilizar el IDE como evaluación durante un mes, aunque el compilador en sí es gratuito y posee una consola LISP también gratuita. Para Corman Common Lisp el profesor Reini Urban ha implementado la posibilidad de su ejecución desde el entorno AutoCAD lo que que pudiera señalar un camino de desarrollo interesante para el futuro.

Tutoriales en la Red:

El libro de David Touretzky "Common Lisp: A Gentle Introduction to Symbolic Computation", que está disponible en formato PDF.
El libro de David Lamkins "Successful Lisp: How to Understand and Use Common Lisp" en formato html.
La Common LISP HyperSpec, de Kent Pitman, que no es un tutorial, sino la referencia definitiva del lenguaje. Cortesía de la casa que comercializa LispWorks.
El libro de Guy Steele "Common LISP, the language. 2nd Edition", más conocido como  CLTL2, aunque anterior a la norma ANSI, aún merece ser leído.

Si se trata de comprar un libro, lo recomendable sería comenzar, ya sea con el de Paul Graham "ANSI Common Lisp" o con el de Stephen Slade "Object-Oriented Common LISP".
Después, el PAIP ("Paradigms of Artificial Intelligence Programming") de Peter Norvig es una lectura obligada.

En la Web sería necesario visitar el CLiki y la página de ALU (Association of LISP Users) para más enlaces de interés.

Un caso particular es el del Corman Common Lisp, para el que Reini Urban ha implementado la posibilidad de su ejecución desde el entorno AutoCAD y que pudiera señalar un camino de desarrollo interesante para el futuro. También existen utilidades para la transferencia de programas AutoLISP-XLISP desarrolladas por Tony Tanzillo.

* Fuente: Dr. Edmund Weitz (edi@agharta.de) posting al newsgroup comp.lang.lisp Fecha: 2001-09-28 03:38:20 PST

PARA MUESTRA...

Como una muestra de la capacidad de síntesis y abstracción ala que podemos acceder con LISP (y una buena cuota de ingenio) reproducimoseste pequeño problema planteado a manera de acertijo hace unosdías por Vladimir Nesterovski en el grupo de noticiasautodesk.autocad.customization,y la solución propuesta otro maestro, Tony Tanzillo:

Hola todos, os propongo algo:
crear una función que para una lista de puntos
devuelva un par de puntos con los valores mínimos
y máximos (una suerte de "caja de abarque"), que
funcione para puntos n-dimensionales y que no
emplee LAMBDA o SETQ.
Debe ser simple también. :)
Por ejemplo, para '( (1 2 2) (2 5 4) (3 1 2) )
devolvería '( (1 1 2) (3 5 4) ).
Pasadlo bien, :-)
--
Vlad

Y la respuesta de Tony Tanzillo:

(defun extents (plist)
(list (apply 'mapcar (cons 'min plist))
(apply 'mapcar (cons 'max plist))))

En dos líneas de código resuelta una función queexplicada en términos de programación más convencionales,recibirá dos matrices de dimensiones variables n x m y devolveráuna matriz conteniendo los máximos y mínimos para cada uno de lostérminos de las matrices recibidas. La función EXTENTS recibecomo argumento una lista de listas y devuelve otra, sin recurrir enningún momento a la creación de variables como almacenajeintermedio. Por otra parte el argumento original permanece inalterado, es decirque se trata de una función no destructiva.

Esto a manera de muestra de lo que trataremos de exponer de aquí enadelante.