Common Lisp

De Wikipedia, la enciclopedia libre
Saltar a: navegación, búsqueda

Common Lisp es un lenguaje de programación que pertenece a la familia de lenguajes Lisp. Se encuentra descrito en el documento estándar ANSI INCITS 226-1994 (R2004) del ANSI, (antes X3.226-1994 (R1999)).[1] Desarrollado 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. Están disponibles varias implementaciones del estándar de Common Lisp, incluyendo la de software libre y de código abierto y productos propietarios.

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.

Common Lisp incluye al CLOS, un sistema de objetos que soporta multimétodos y combinaciones de métodos. Es extensible a través de del MetaObject Protocol. Common Lisp es extensible usando las 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).

Sintaxis[editar]

Common Lisp es un dialecto de Lisp; usa expresiones S para denotar tanto el código como la estructura de datos. Las funciones y la llamadas a macros son escritas como listas, con el nombre de la función primero, como en estos ejemplos:

 (+ 2 2)           ; suma 2 más 2, dando como resultado 4.
 (defvar *x*)      ; Se asegura de que exista una variable *x*,
                   ; sin darle un valor. El enlace (binding) se
                   ; establece en un ámbito dinámico en vez de léxico.
 (setf *x* 42.1)   ; Fija la variable *x* al valor 42.1 de punto flotante
 ;; Define la función que calcula el cuadrado de un número:
 (defun cuadrado (x) 
   (* x x))
 ;; Ejecuta la función:
 (cuadrado 3)        ; Retorna 9
 (cuadrado *x*)      ; Retorna 1772.4099
 ;; El constructor del 'let' crea un ámbito para variables locales.
 ;; Aquí la variable 'a' está enlazada (bound) a 6 y la variable 'b' está enlazada a 4.
 ;; Dentro de 'let' hay un 'cuerpo' donde el último valor computado es retornado.
 ;; Aquí, el resultado de sumar a y b es retornado desde la expresión 'let'.
 ;; Las variables a y b tienen ámbitos léxicos a menos que los símbolos hayan sido
 ;; marcados como variables especiales (por ejemplo por un DEFVAR anterior). 
 (let ((a 6)
       (b 4)) 
   (+ a b))        ; retorna 10

Tipos de datos[editar]

Common Lisp tiene muchos tipos de datos, por ejemplo: Integers, Ratios, Complex Numbers, Stings, Arrays, Vectors, Hash Tables, Funciones, Streams... más que muchos otros lenguajes.

Tipos escalares[editar]

Los tipos numéricos incluyen números enteros, cocientes, números de punto flotante, y números complejos.[2] Common Lisp usa bignums para representar valores numéricos de tamaño y precisión arbitrarios. El tipo cociente representa fracciones exactamente, una facilidad no disponible en muchos lenguajes. Common Lisp fuerza automáticamente a los valores numéricos entre estos tipos a medida que sean apropiados.

El tipo carácter de Common Lisp no se limita a los caracteres ASCII. La mayoría de las implementaciones modernas permiten los caracteres de Unicode.[3]

El tipo símbolo es común a los lenguajes Common Lisp, pero largamente desconocido fuera de ellos. Un símbolo es un único, objeto de datos con nombre que tiene varias partes: nombre, valor, función, lista y paquete. De éstos, la celda del valor y la celda de la función son los más importantes. Los símbolos en Lisp son frecuente usados similarmente a los identificadores en otros lenguajes: para contener el valor de una variable; sin embargo, hay muchas otros usos. Normalmente, cuando un símbolo es evaluado, su valor es retornado. Algunos símbolos se evalúan a sí mismos, por ejemplo todos los símbolos en un paquete de palabra clave son autoevaluados. Los valores boleano en Common Lisp son representados por los símbolos autoevaluantes T y NIL. Common Lisp tiene espacios de nombres para símbolos, llamados "paquetes”.

Estructuras de datos[editar]

Los tipos de secuencia en Common Lisp incluye listas, vectores, vectores-bit, y strings. Hay muchas operaciones que pueden trabajar en cualquier tipo de secuencia.

Como en casi todos los otros dialectos Lisp, las listas en Common Lisp están compuestas de conses, a veces llamados celdas cons o pares. Una celda cons es una estructura de datos con dos slots, llamados sus car y cdr. Una lista es bien formada una cadena enlazada de celdas cons. Cada car del cons refiere a un miembro de la lista (posiblemente otra lista). Cada cdr del cons refiere al cons siguiente -- a excepción del último cons, cuyo cdr refiere al valor nil. Nil también representa una lista vacia. Los conses también pueden fácilmente usarse para implementar árboles y otras estructuras de datos complejas; aunque generalmente es aconsejado usar instancias de clases y estructuras. También es posible crear estructuras de datos circulares con los conses.

Common Lisp soporta arreglos multidimensionales, y puede redimensionar los arreglos dinámicamente si fuera necesario. Los arreglos multidimensionales pueden ser usados para metemática de matrices. Un vector es un arreglo unidimensional. Los arreglos pueden tener cualquier tipo como miembros (incluso tipos mezclados en el mismo arreglo) o pueden estar especializados para contener un tipo específico de miembros, como en un vector de enteros. Muchas implementaciones pueden optimizar funciones de arreglo cuando el arreglo usado es de un tipo específico. Dos tipos de arreglo están estandarizados: un string es un vector de caracteres, mientras que un vector-bit es un vector de bits.

Las tablas hash almacenan asociaciones entre objetos de datos. Cualquier objeto puede ser usado como clave o valor. Las tablas de hash, al igual que los arreglos, son redimensionadas automáticamente a medida que se necesite.

Los paquetes son colecciones de símbolos, usados principalmente para separar las partes de un programa en espacios de nombres. Un paquete puede exportar algunos símbolos, marcándolos como parte de una interface pública. Los paquetes pueden usar otros paquetes.

Las estructuras, similares en uso a los structs de C y a los records de Pascal, representan estructuras de datos arbitrariamente complejas con cualquier número y tipo de campos (llamados slots). Las estructuras permiten herencia simple.

Las clases son similares a las estructuras, pero ofrecen características más dinámicas y herencia múltiple. (Ver CLOS). Las clases han sido agregadas tarde al Common Lisp y hay un cierto solapamiento conceptual con las estructuras. Los objetos creados de clases son llamados instancias. Un caso especial son las funciones genéricas. Las funciones genéricas son tanto funciones como instancias.

Funciones[editar]

Common Lisp soporta las funciones de primera clase. Por ejemplo, es posible escribir funciones que toman otras funciones como argumentos o también retornen funciones. Esto hace posible describir operaciones muy generales.

La biblioteca de Common Lisp confía fuertemente en tales funciones del alto orden. Por ejemplo, la función función sort toma un operador relacional como un argumento y una función clave como un argumento opcional de palabra clave. Esto puede ser usado no sólo para clasificar cualquier tipo de datos, pero también para clasificar las estructuras de datos de acuerdo a una clave.

 (sort (list 5 2 6 3 1 4) #'>)
 ; Ordena la lista usando la función > como el operador relacional.
 ; Returns (6 5 4 3 2 1).
 (sort (list '(9 A) '(3 B) '(4 C)) #'< :key #'first)
 ; Ordena la lista de acuerdo al primer elemento de cada sublista.
 ; Returns ((3 B) (4 C) (9 A)).

El modelo de evaluación para las funciones es muy simple. Cuando el evaluador encuentra una forma (F A1 A2…) entonces se asume que el símbolo nombrado F es uno de los siguientes:

  1. Un operador especial (fácilmente comprobado contra una lista fija)
  2. Un macro operador (debe haber sido definido previamente)
  3. El nombre de una función (por defecto), que puede ser un símbolo, o un principio de subforma con el símbolo lambda.

Si F es el nombre de una función, después las argumentos A1, A2,…, son evaluados en orden de izquierda a derecha, y la función es encontrada e invocada con esos valores suministrados como parámetros.

Ámbito[editar]

Como en los programas en muchos otros lenguajes de programación, Los programas Common Lisp hacen uso de nombres para referirse a las variables, funciones, y a muchas otras clases de entidades. Las referencias de nombres están conforme a un ámbito.

La asociación entre un nombre y la entidad a la que el nombre se refiere se llama binding (enlace, enlazamiento).

El ámbito se refiere al conjunto de las circunstancias en las cuales un nombre es determinado para tener un enlace particular.

Determinantes del ámbito[editar]

Las circunstancias que determinan el ámbito en Common Lisp incluyen:

  • La localización de una referencia dentro de una expresión. Si es la posición extrema izquierda de una composición, se refiere a un enlace (binding) de un operador especial o un macro o una función, si no a un enlace de variable o alguna otra cosa.
  • La clase de expresión en la cual la referencia ocurre. Por ejemplo, (GO X) significa transferir el control a la etiqueta X, mientras que (PRINT X) se refiere a la variable X. Ambos ámbitos de X pueden estar activos en la misma región del texto del programa, puesto que las etiquetas tagbody están en un espacio de nombre separado de los nombres de variables. Una forma especial o la forma de macro tiene completo control sobre los significados de todos los símbolos en su sintaxis. Por ejemplo en (defclass x (a b) ()), una definición de clase, el (a b) es una lista de clases base, así que estos nombres son buscados en el espacio de nombres de clases, y x no es una referencia a un binding (enlace) existente, sino el nombre de una nueva clase que es derivada de a y b. Estos hechos emergen puramente de la semántica de defclass. El único hecho genérico sobre esta expresión es que los defclass se refieren a un enlace (binding) de macro; todo lo demás es dejado a defclass.
  • La localización de la referencia dentro del texto del programa. Por ejemplo, si una referencia a la variable X es envuelta en una construcción binding como un LET que define un binding para X, entonces la referencia está en el ámbito creado por ese binding.
  • Para una referencia de variable, independientemente de si el símbolo de variable ha sido local o globalmente declarado como especial. Esto determina si la referencia está resuelta dentro de un ambiente léxico, o dentro de un ambiente dinámico.
  • La instancia específica del ambiente en el cual la referencia es resuelta. Un ambiente es un diccionario de tiempo de ejecución (run-time) que mapea los símbolos con los enlaces (bindings). Cada tipo de referencia usa sus propio tipo de ambiente. Las referencias a las variables léxicas son resueltas en un ambiente léxico, etcétera. Más de un ambiente puede estar asociado con la misma referencia. Por ejemplo, gracias a la recursión o al uso de múltiples hilos (multithreads), pueden existir al mismo tiempo múltiples activaciones de la misma función. Estas activaciones comparten el mismo texto del programa, pero cada una tiene su propia instancia de ambiente léxico.

Para entender a lo que hace referencia un símbolo, el programador de Common Lisp debe saber que tipo de referencia está siendo expresada, que tipo de ámbito es usado en caso de ser una referencia variable (ámbito dinámico versus léxico), y también la situación en tiempo de ejecución: en qué ambiente es resuelta la referencia, donde estaba el binding introducido en el ambiente, etcétera.

Macros[editar]

En Lisp un macro se asemeja superficialmente a una función en uso. Sin embargo, en vez de representar una expresión que es evaluada, representa una transformación del código fuente del programa.

A continuación un ejemplo de un macro que proporciona la forma de iteración until, que puede ser familiar para lenguajes como Perl:

 (defmacro until (test &body body)
   `(do ()
        (,test)
      ,@body))
 
 ;; ejemplo
 (until (= (random 10) 0) 
   (write-line "Hola"))

Todos los macros deben ser expandidos antes de que el código fuente que los contiene pueda ser evaluado o compilado normalmente. Las macros pueden ser considerados como funciones que aceptan y retornan árboles de sintaxis abstracta (expresiones-S de Lisp). Estas funciones son invocadas antes del evaluador o del compilador para producir el código fuente final. Los macros son escritos en Common Lisp normal, y pueden usar cualquier operador disponible en Common Lisp (o de terceros). La notación de backquote usada arriba es proporcionada por Common Lisp específicamente para simplificar el caso común de la substitución en una plantilla de código.

Sistema de objetos del Common Lisp[editar]

Common Lisp soporta el paradigma de programación orientada a objetos al través del CLOS (Common Lisp Object System), que es uno de los sistemas de objetos más poderosos disponible en cualquier lenguaje[cita requerida]. Originalmente propuesto como un add-on[cita requerida], el CLOS fue adoptado como parte del estándar ANSI de 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 a través del envió de mensajes encontradas en lenguajes.como Smalltalk, 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 objeto de primera clase. Cada clase del CLOS está integrada en el sistema de tipos de Common Lisp. Mucho tipos de Common Lisp tienen una clase correspondiente. Hay más uso potencial del CLOS para 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 de 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.

Implementaciones[editar]

  • CLISP
  • SBCL
  • Clozure
  • LispWorks
  • EBCL
  • AllegroCL

Aplicaciones[editar]

Common Lisp es usado para desarrollar aplicaciones de investigación, frecuentemente en inteligencia artificial, en el desarrollo rápido de prototipos o para desplegar aplicaciones.

Common Lisp es usado en muchas aplicaciones comerciales, incluyendo el sitio de comercio web Yahoo! Store, que originalmente implicó a Paul Graham y fue posteriormente reescrito en C++ y el Perl.[4] Otros ejemplos notables incluyen:

También existen aplicaciones de fuente abierta escritas en Common Lisp, como por ejemplo:

Véase también[editar]

Referencias[editar]

  1. Document page at ANSI website
  2. Reddy, Abhishek (22 de agosto de 2008). «Features of Common Lisp».
  3. «Unicode support». The Common Lisp Wiki. Consultado el 21 de agosto de 2008.
  4. "In January 2003, Yahoo released a new version of the editor written in C++ and Perl. It's hard to say whether the program is no longer written in Lisp, though, because to translate this program into C++ they literally had to write a Lisp interpreter: the source files of all the page-generating templates are still, as far as I know, Lisp code." Paul Graham, Beating the Averages
  5. «Stumpwm».

Enlaces externos[editar]

Wikilibros