Common Lisp

Common Lisp
Información sobre la plantilla
Common Lisp.jpeg
El lenguaje Common Lisp es un dialecto de lenguaje de programacio Lisp.

Common Lisp, abreviado a “CL”, es un dialecto del lenguaje de programación Lisp, publicado en estándar ANSI X3.226-1994. Desarrollado para estandarizar los variantes divergentes de Lisp anteriores, no es una implementación, sino más bien una especificación. Varias implementaciones del estándar Common Lisp están disponibles, incluyendo productos comerciales y software se código abierto.

lenguaje Common Lisp

El lenguaje Common Lisp es un dialecto de lenguaje de programacio Lisp. El Common Lisp es un leguaje muy usado en la robotica y en la ingenieria e inteligencia aritificial. Este fue hecho para estandardizar las variantes divergentes del Lisp (aunque principalmente las variantes de MacLisp) que lo precedió, no es una implementación sino una especificación del lenguaje. El Common Lisp tiene varias implementaciones como las de codigo abierto y software libre y productos propietarios. El Common Lisp es un lenguaje multi paradigma de propósitos generales. Soporta una combinación de paradigmas de programación como procedimental (imperativo), funcional, y orientada al objeto. Como un lenguaje de programación dinámica, facilita el desarrollo de software de una manera evolutiva e incremental, con la compilación iterativa en programas eficientes en tiempo de ejecución. El Common Lisp incluye al CLOS, un sistema de objetos que soporta multimétodos y combinaciones de métodos. Es extensible a través de características estándar tales como macros de Lisp (rearreglo del código en tiempo de compilación logrado por el programa en sí mismo) y macros de lectura (extensión de la sintaxis para dar un significado especial a los caracteres reservados para los usuarios con este propósito). El Common Lisp incluye un juego de herramientas (toolkit) para la programación orientada a objetos, el Common Lisp Object System o CLOS, que es uno de los sistemas de objetos más poderosos disponible en cualquier lenguaje. Originalmente propuesto como un add-on, el CLOS fue adoptado como parte del estándar ANSI del Common Lisp. CLOS es un sistema de objetos dinámico con despacho múltiple y herencia múltiple, y se diferencia radicalmente de las facilidades de programación orientada a objetos (OOP) encontradas en lenguajes estáticos como C++o Java. Como sistema de objetos dinámico, CLOS permite cambios en tiempo de ejecución a las funciones y clases genéricas. Los métodos pueden ser agregados y removidos, las clases pueden ser agregadas y redefinidas, los objetos pueden ser actualizados para los cambios de la clase y la clase de objetos puede ser cambiada. El CLOS se ha integrado en el ANSI Common Lisp. Las funciones genéricas pueden ser usadas como las funciones normales y son un tipo de datos de primera clase. Cada clase del CLOS está integrada en el sistema de tipos del Common Lisp. Mucho tipos del Common Lisp tienen una clase correspondiente. Hay más uso potencial del CLOS para el Common Lisp. La especificación no dice si las condiciones son implementadas con el CLOS. Los pathnames (nombres de ruta) y los streams (flujos) pueden ser implementados con el CLOS. Estas futuras posibilidades del uso de CLOS para el ANSI Common Lisp no son parte del estándar. Las implementaciones reales del Common Lisp están usando el CLOS para los pathnames, streams, condiciones de entrada/salida, la implementación del CLOS en sí mismo y más.

Historia

Todo comenzó en Abril de 1981, tras una reunión patrocinado por DARPA de todos los comunidades Lisp: Symbolics, el proyecto SPICE, el proyecto NIL, el proyeco S-1~ Lisp. Todas las comunidades se unieron y crearon Common Lisp. Inicialmente liderado por Jonl White y Richard P. Gabriel (que también ayudó a crear CLOS), con un gran apoyo de Scot Fahlman, Daniel Weinreb, David Moon y Guy L. Steele. Common Lisp fue diseñado como una descripción de una familia de lenguajes. Las influencias más grandes sobre Common Lisp fueron Lisp Machine Lisp, MacLisp, NIL, S-1~ Lisp, Spice Lisp y Scheme. Sus semánticas fueron poco especificados, a propósito, en algunos sitios donde se pensó que un sobre-especificación podría restringir el uso e investigación de Common Lisp. En 1986 se formó “X3J13”, un grupo de trabajo técnico para producir un borrador de un estándar ANSI de Common Lisp. Por la aceptación del público de Common Lisp, las metas de este grupo difirieron de las metas de los diseñadores originales. Estas metas incluían una estandarización más estricta para incrementar portabilidad, un sistema orientado a objetos, un sistema de condiciones, facilidades de iteración y una forma de manejar conjuntos de caracteres grandes.

Características

Common Lisp es un lenguaje de programación de propósito general con las siguientes

Características: Soporta una combinación de programación imperativa, funcional y orientada a objetos. Es un lenguaje dinámico que facilita un rápido desarrollo, con compilación iterativa a programas eficientes en tiempo de ejecución. Incluye CLOS, un sistema de objetos que soporta multimétodos y combinación de métodos. Es extensible por características estándares como macros de Lisp (ordenación de código en tiempo de compilación lo hace el programa en sí).

Tipos de Datos

Tipo Escalar: Tipos numéricos incluyen enteros, ratios, números en coma flotante y números complejos. Common Lisp usa “bignums” para representar valores de tamaño y precisión arbitraria. El tipo ratio representa las fracciones exactamente, una característica que no tienen muchos lenguajes de programación. El tipo carácter en Common Lisp no está limitado a caracteres ASCII, que no es de sorprender dado que se diseñó antes de que existiera el código ASCII. La mayoría de las implementaciones modernas permiten caracteres “Unicode”. El tipo símbolo es común a todos los lenguajes Lisp, pero poco conocido fuera del ámbito de Lisp. Un símbolo es un objeto de data único y nombrado, con varias partes: nombre, valor, función, lista de propiedades y paquete. De estos campos, “valor” y “función” son los más importantes. Símbolos en Lisp son usados de manera similar a identificadores en otros lenguajes: para guardar un valor de una variable; aunque existen muchos otros usos. Normalmente cuando se evalúa un símbolo, su valor es devuelto. Algunos símbolos se evalúan a ellos mismos, por ejemplo todos los símbolos en paquetes “keyword” se evalúan a ellos mismos. Valores booleanos en Common Lisp son representados por símbolos que se evalúan a ellos mismos: “T” y “NIL”. Estructuras de Datos: Tipos secuenciales en Common Lisp incluyen lista, vectores, vectores de bits, y cadenas. Existen muchas operaciones que se pueden hacer a cualquier tipo secuencial. En casi todos los dialectos de Lisp las listas están compuestas por “conses”, a veces llamados “cons cells” o “parejas”. Un “cons” es una estructura de datos con dos slots, llamados su “car” y “cdr”. Una lista es una cadena enlazada de “conses”. Cada “cons car” hace referencia a un miembro de la lista (posiblemente otra lista). Cada “cons cdr” hace referencia a la siguiente “cons”, excepto el último “cons” cuyo valor “cdr” será nil. “Conses” también se pueden emplear para implementar árboles y otras estructuras de datos complejos. También es posible crear estructuras de datos circulares. Common Lisp soporta arrays multidimensionales, y pueden variar su tamaño dinámicamente si es necesario. Arrays multidimensionales se pueden usar para formar matrices matemáticas. Un vector es un array de una sola dimensión. Los arrays pueden contener cualquier tipo (incluso distintos tipos en un mismo array) o pueden ser especializados para contener un solo tipo de dato. Muchas implementaciones pueden optimizar funciones de arrays cuando el array que se usa contiene un solo tipo de dato. Hay dos tipos especializados de arrays estándares: un “string” (cadena) es un vector de caracteres, y un “bit vector” es un vector de bits. Las tablas hash guardan asociaciones entres objetos de datos. Cualquier objeto se puede usar como clave o valor. Tablas hash, como los arrays, automáticamente ajustan su tamaño. Los paquetes son colecciones de símbolos. Un paquete puede exportar algunos símbolos, marcándolos como que forman parte de una interfaz pública. Los paquetes pueden usar otros paquetes. Estructuras, parecido al uso de los “structs” en C, o los “registros” en Pascal, representan estructuras de datos complejos arbitrarios con cualquier cantidad y tipo de campos (llamados “slots”). Estructuras permiten herencia singular. Clases son similares a estructuras, pero ofrecen características más dinámicas y herenica CLOS múltiple. Clases se han añadido tarde a Common Lisp y pueden dar lugar a confusiones conceptuales con las estrcuturas. Objetos compuestos por clases se llaman “instancias”. Un cao especial son las funciones genéricas. Funciones genéricas son funciones e instancias. Funciones: Common Lisp soporta funciones de primera clase. Por ejemplo, es posible crear funciones que toman otras funciones como argumento o devuelven una función. Esto permite definir operaciones muy generales. Las librerías de Common Lisp dependen mucho de estas funciones de órden superior. El modelo de evaluación para funciones es muy simple. Cuando el evaluador de encuentra con la forma “(F A1 A2...)” entonces asume que el símbolo “F” es uno de los siguiente: Un operador especial (que se comprueba fácil con un “fixed list”) Un macro operador (debería de haber sido definido previamente) El nombre de una función (default), que puede ser o un símbolo, o alguna sub-forma que comience con el símbolo lambda. Si “F” es el nombre de una función, entonces los argumentos “A1, A2, …,An” son evaluados en orden izquierda-derecha, se encuentra la función y se llama con esos valores como parámetros.

Otros tipos:

Pathnames: representan archivos o directorios en el sistema de archivos. El “pathname” de Common Lisp es más general que el nombramiento de archivos en la mayoría de los sistemas operativos, así los programas Lisp son más portables a otros sistemas. Input y Output “streams”: representan fuentes binarias o data de texto, como el terminal o archivos abiertos. Common Lisp tiene incluido un “pseudo-random number generator(PRNG)” (generador de números pseudo-aleatorios). Condiciones: son un tipo que se usan para representar errores, excepciones, y otros eventos “interesantes” a la que puede responder un programa. Classes son un objeto de primera-clase, y son en sí mismos instancias de clases llamadas “metaclases”.

COMPILADO/INTERPRETADO

Hay muchos compiladores disponibles para Common Lisp, entre los más usados e importantes:

  • KCL (Kyoto Common Lisp): es una implementación de Lisp. Está escrito en C para ejecutarse bajo sistemas operativos del estilo de Unix.
  • AKCL (Austin Kyoto Common Lisp): es una colección de puertos, arreglos de fallos y mejoras de rendimientos de “KCL”.
  • CLiCC: Compila de Common Lisp a C. Intencionado para ser un suplemento a los sistemas CLISP para generar aplicaciones portables. Para producir un ejecutable el código traducido en C debe de ser enlazado con la librería CLiCC de tiempo de ejecución.
  • CLISP: este paquete incluye un intérprete, compilador a bytecode, librería de tiempo de ejecución y editor.
  • CMU Common Lisp: es un entorno de programación de Common Lisp de “potencia industrial” y de dominio público. Muchos de los cambios de X3j13 han sido incorporados a CMU CL.
  • Garnet: es un entorno de desarrollo de interfaz para Common Lisp y X11. Ayuda a crear interfaces gráficos e interactivos para tu software.
  • WCL: una implementación de Common Lisp como una librería compartida. WCL no es 100% completo, pero si tiene un entorno completamente desarrollado incluyendo cargado de ficheros dinámicos y “debugging”.

Funciones

Arriba se vio un ejemplo de función. Aquí hay algunos más:

    >gt; (+ 3 4 5 6)                   ;this function takes any number of arguments
    18
    >gt; (+ (+ 3 4) (+ (+ 4 5) 6))     ;isn't prefix notation fun?
    22
    >gt; (defun foo (x y) (+ x y 5))   ;defining a function
    FOO
    >gt; (foo 5 0)                     ;calling a function
    10
    >gt; (defun fact (x)               ;a recursive function
    (if (> x 0)
    (* x (fact (- x 1)))
    1))
    FACT
    >gt; (fact 5)
    120
    >gt; (defun a (x) (if (= x 0) t (b (- x))))        ;mutually recursive functions
    A
    >gt; (defun b (x) (if (> x 0) (a (- x 1)) (a (+ x 1))))
    B
    >gt; (a 5)
    T
    >gt; (defun bar (x)                ;a function with multiple statements in
    (setq x (* x 3))            ;its body -- it will return the value
    (setq x (/ x 2))            ;returned by its final statement
    (+ x 4))
    BAR
    >gt; (bar 6)
    13
  

Cuando definimos foo le dimos dos argumentos, x e y. Ahora, cuando llamemos a foo, se nos exige que proporcionemos exactamente dos argumentos: el primero se convertirá en el valor de x por el periodo de duración de la llamada a foo, y el segundo se convertirá en el valor de y durante la llamada. En LISP [NdT: en Common Lisp; en el Lisp original, no], la mayoría de las variables tienen ámbito léxico; esto es, si foo llama a bar y bar intenta referenciar a x, no obtendrá el valor de foo para x. El proceso de asignar un valor a un símbolo para la duración de cierto ámbito léxico se llama asociación [NdT: tampoco es del todo cierto. Ese nombre lo tiene incluso si la “asignación” fuera dinámica. Los comunlisperos están continuamente empleando trucos desinformativos de este tipo para justificar sus deserciones frente a la tradición Lisp y para crear la sensación de que no hay otra cosa en el mundo Lisp]. Se pueden especificar argumentos optativos para las funciones. Cualquier argumento despuñes del símbolo &optional es optativo:

    >gt; (defun bar (x &optional y) (if y x 0))
    BAR
    >gt; (defun baaz (&optional (x 3) (z 10)) (+ x z))
    BAAZ
    >gt; (bar 5)
    0
    >gt; (bar 5 t)
    5
    >gt; (baaz 5)
    15
    >gt; (baaz 5 6)
    11
    >gt; (baaz)
    13
  

Es válido llamar a la función bar ya sea con uno o con dos argumentos. Si se la llama con uno, x quedará asociada al valor de ese argumento e y lo será a nil; si se la llama con dos argumentos, x e y serán asociadas a los valores del primer y segundo argumentos, respectivamente. La función baaz tiene dos argumentos optativos. Especifica un valor predeterminado para cada uno de ellos: si la llamante especifica sólo un argumento, z será asociada a 10 en vez de a nil, y si la llamante no especifica argumentos, x será asociada a 3 y z a 10. Se puede hacer que la función acepte cualquier cantidad de argumentos mediante la finalización de su lista de argumentos con el parámetro &rest. LISP recogerá en una lista todos los argumentos no contabilizados de otro modo y asociará el parámetro &rest a esa lista. Así:

    >gt; (defun foo (x &rest y) y)
    FOO
    >gt; (foo 3)
    NIL
    >gt; (foo 4 5 6)
    (5 6)
  

Finalmente, se le puede dar a la función otro tipo de argumento optativo llamado argumento de palabra clave. La llamadora puede dar estos argumentos en cualquier orden, porque están etiquetados con palabras clave.

    >gt; (defun foo (&key x y) (cons x y))
    FOO
    >gt; (foo :x 5 :y 3)
    (5 . 3)
    >gt; (foo :y 3 :x 5)
    (5 . 3)
    >gt; (foo :y 3)
    (NIL . 3)
    >gt; (foo)
    (NIL)
  

Los parámetros &key también pueden tener valores predeterminados:

    >gt; (defun foo (&key (x 5)) x)
    FOO
    >gt; (foo :x 7)
    7
    >gt; (foo)
    5

Fuentes