Articulo de referencia

Ceceo común

Common Lisp ( CL ) es un dialecto del lenguaje de programación Lisp , publicado en el documento estándar ANSI INCITS 226-1994 (S2018) [1] (anteriormente X3.226-1994 (R1999) del ...

Common Lisp ( CL ) es un dialecto del lenguaje de programación Lisp , publicado en el documento estándar ANSI INCITS 226-1994 (S2018) [1] (anteriormente X3.226-1994 (R1999) del American National Standards Institute (ANSI) . [2] Common Lisp HyperSpec , una versión HTML con hipervínculos , se ha derivado del estándar ANSI Common Lisp. [3]

El lenguaje Common Lisp fue desarrollado como un sucesor estandarizado y mejorado de MacLisp . A principios de la década de 1980, varios grupos ya estaban trabajando en diversos sucesores de MacLisp: Lisp Machine Lisp (también conocido como ZetaLisp), Spice Lisp , NIL y S-1 Lisp . Common Lisp buscó unificar, estandarizar y extender las características de estos dialectos de MacLisp. Common Lisp no es una implementación, sino más bien una especificación de lenguaje . [4] Hay disponibles varias implementaciones del estándar Common Lisp, incluido software libre y de código abierto y productos propietarios. [5] Common Lisp es un lenguaje de programación multiparadigma de propósito general . Admite una combinación de paradigmas de programación procedimental , funcional y orientada a objetos . Como lenguaje de programación dinámico , facilita el desarrollo de software evolutivo e incremental , con compilación iterativa en programas eficientes en tiempo de ejecución. Este desarrollo incremental a menudo se realiza de forma interactiva sin interrumpir la aplicación en ejecución.

También admite la anotación y conversión de tipos opcionales, que se pueden agregar según sea necesario en las etapas posteriores de creación de perfiles y optimización, para permitir que el compilador genere un código más eficiente. Por ejemplo, fixnumpuede contener un entero sin encapsular en un rango compatible con el hardware y la implementación, lo que permite una aritmética más eficiente que con enteros grandes o tipos de precisión arbitraria. De manera similar, se le puede indicar al compilador, por módulo o por función, qué tipo de nivel de seguridad se desea, mediante declaraciones de optimización .

Common Lisp incluye CLOS , un sistema de objetos que admite métodos múltiples y combinaciones de métodos. Suele implementarse con un protocolo de metaobjetos .

Common Lisp es extensible a través de características estándar como macros Lisp (transformaciones de código) y macros de lectura (analizadores de entrada para caracteres).

Common Lisp ofrece compatibilidad parcial con versiones anteriores de Maclisp y del Lisp original de John McCarthy . Esto permite que el software Lisp más antiguo se pueda trasladar a Common Lisp. [6]

Historia

El trabajo sobre Common Lisp comenzó en 1981 tras una iniciativa del director de ARPA, Bob Engelmore, para desarrollar un dialecto Lisp estándar para la comunidad. [7] Gran parte del diseño inicial del lenguaje se realizó mediante correo electrónico. [8] [9] En 1982, Guy L. Steele Jr. presentó la primera descripción general de Common Lisp en el Simposio ACM de 1982 sobre LISP y programación funcional. [10]

La primera documentación del lenguaje se publicó en 1984 como Common Lisp the Language (conocido como CLtL1), primera edición. Una segunda edición (conocida como CLtL2), publicada en 1990, incorporó muchos cambios al lenguaje, realizados durante el proceso de estandarización ANSI Common Lisp: sintaxis LOOP extendida, el Common Lisp Object System, el Condition System para el manejo de errores, una interfaz para la impresora bonita y mucho más. Pero CLtL2 no describe el estándar ANSI Common Lisp final y, por lo tanto, no es una documentación de ANSI Common Lisp. El estándar ANSI Common Lisp final se publicó en 1994. Desde entonces, no se ha publicado ninguna actualización del estándar. Varias extensiones y mejoras a Common Lisp (por ejemplo, Unicode, Concurrency, IO basado en CLOS) han sido proporcionadas por implementaciones y bibliotecas .

Sintaxis

Common Lisp es un dialecto de Lisp. Utiliza expresiones S para indicar tanto el código como la estructura de datos. Las llamadas a funciones, los formularios de macros y los formularios especiales se escriben como listas, con el nombre del operador primero, como en estos ejemplos:

 ( + 2 2 ) ; suma 2 y 2, lo que da como resultado 4. El nombre de la función es '+'. Lisp no tiene operadores como tales.             
 ( defvar *x* ) ; Asegura que existe una variable *x*, ; sin darle un valor. Los asteriscos son parte del ; nombre, que por convención denota una variable especial (global). ; El símbolo *x* también está dotado con la propiedad de que ; las vinculaciones subsiguientes son dinámicas, en lugar de léxicas. ( setf *x* 42.1 ) ; Establece la variable *x* en el valor de punto flotante 42.1       
                   
                   
                   
                   
      
 ;; Define una función que eleva al cuadrado un número: 
( defun square ( x ) ( * x x ))   
     
 ;; Ejecuta la función: 
( cuadrado 3 ) ; Devuelve 9          
 ;; La construcción 'let' crea un ámbito para las variables locales. Aquí 
;; la variable 'a' está asociada a 6 y la variable 'b' está asociada ;; a 4. Dentro de 'let' hay un 'cuerpo', donde se devuelve el último valor calculado. ;; Aquí se devuelve el resultado de sumar a y b desde la expresión 'let'. ;; Las variables a y b tienen ámbito léxico, a menos que los símbolos hayan sido ;; marcados como variables especiales (por ejemplo, mediante un DEFVAR anterior). ( let (( a 6 ) ( b 4 )) ( + a b )) ; devuelve 10 
 
 
 
 
   
        
             

Tipos de datos

Common Lisp tiene muchos tipos de datos .

Tipos escalares

Los tipos de números incluyen números enteros , proporciones , números de punto flotante y números complejos . [11] Common Lisp utiliza números grandes para representar valores numéricos de tamaño y precisión arbitrarios. El tipo de proporción representa fracciones de manera exacta, una función que no está disponible en muchos lenguajes. Common Lisp convierte automáticamente los valores numéricos entre estos tipos según corresponda.

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

El tipo de símbolo es común en los lenguajes Lisp, pero en gran medida desconocido fuera de ellos. Un símbolo es un objeto de datos único y nombrado con varias partes: nombre, valor, función, lista de propiedades y paquete. De estos, la celda de valor y la celda de función son las más importantes. Los símbolos en Lisp se utilizan a menudo de forma similar a los identificadores en otros lenguajes: para contener el valor de una variable; sin embargo, hay muchos otros usos. Normalmente, cuando se evalúa un símbolo, se devuelve su valor. Algunos símbolos se evalúan a sí mismos, por ejemplo, todos los símbolos en la palabra clave package son autoevaluables. Los valores booleanos en Common Lisp se representan mediante los símbolos autoevaluables T y NIL. Common Lisp tiene espacios de nombres para símbolos, llamados "paquetes".

Hay varias funciones disponibles para redondear valores numéricos escalares de varias maneras. La función roundredondea el argumento al entero más cercano, y los casos intermedios se redondean al entero par. Las funciones truncate, floory ceilingredondean hacia cero, hacia abajo o hacia arriba respectivamente. Todas estas funciones devuelven la parte fraccionaria descartada como un valor secundario. Por ejemplo, (floor -2.5)da como resultado −3, 0,5; (ceiling -2.5)da como resultado −2, −0,5; (round 2.5)da como resultado 2, 0,5; y (round 3.5)da como resultado 4, −0,5.

Estructuras de datos

Los tipos de secuencia en Common Lisp incluyen listas, vectores, vectores de bits y cadenas. Existen muchas operaciones que pueden funcionar con cualquier tipo de secuencia.

Como en casi todos los demás dialectos de Lisp, las listas en Common Lisp se componen de conses , a veces llamadas celdas o pares de cons . Un cons es una estructura de datos con dos ranuras, llamadas car y cdr . Una lista es una cadena enlazada de conses o la lista vacía. El car de cada cons hace referencia a un miembro de la lista (posiblemente otra lista). El cdr de cada cons hace referencia al siguiente cons, excepto el último cons de una lista, cuyo cdr hace referencia al nilvalor. Los conses también se pueden usar fácilmente para implementar árboles y otras estructuras de datos complejas; aunque normalmente se recomienda usar instancias de estructura o clase en su lugar. También es posible crear estructuras de datos circulares con conses.

Common Lisp admite matrices multidimensionales y puede redimensionar dinámicamente matrices ajustables si es necesario. Las matrices multidimensionales se pueden utilizar para matemáticas matriciales. Un vector es una matriz unidimensional. Las matrices pueden tener cualquier tipo como miembros (incluso tipos mixtos en la misma matriz) o pueden especializarse para contener un tipo específico de miembros, como en un vector de bits. Por lo general, solo se admiten unos pocos tipos. Muchas implementaciones pueden optimizar las funciones de matriz cuando la matriz utilizada está especializada en tipos. Dos tipos de matriz especializados en tipos son estándar: una cadena es un vector de caracteres, mientras que un vector de bits es un vector de bits .

Las tablas hash almacenan asociaciones entre objetos de datos. Cualquier objeto puede utilizarse como clave o valor. Las tablas hash se redimensionan automáticamente según sea necesario.

Los paquetes son colecciones de símbolos que se utilizan principalmente para separar las partes de un programa en espacios de nombres . Un paquete puede exportar algunos símbolos y marcarlos como parte de una interfaz pública. Los paquetes pueden utilizar otros paquetes.

Las estructuras , de uso similar a las estructuras de C y a los registros de Pascal , representan estructuras de datos complejas arbitrarias con cualquier cantidad y tipo de campos (llamados slots ). Las estructuras permiten la herencia única.

Las clases son similares a las estructuras, pero ofrecen características más dinámicas y herencia múltiple (consulte CLOS ). Las clases se agregaron tarde a Common Lisp y existe cierta superposición conceptual con las estructuras. Los objetos creados a partir de clases se denominan Instancias . Un caso especial son las Funciones genéricas. Las Funciones genéricas son tanto funciones como instancias.

Funciones

Common Lisp admite funciones de primera clase . Por ejemplo, es posible escribir funciones que tomen otras funciones como argumentos o que también devuelvan funciones. Esto permite describir operaciones muy generales.

La biblioteca Common Lisp depende en gran medida de estas funciones de orden superior. Por ejemplo, la sortfunción toma un operador relacional como argumento y la función clave como argumento de palabra clave opcional. Esto se puede utilizar no solo para ordenar cualquier tipo de datos, sino también para ordenar estructuras de datos según una clave.

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

El modelo de evaluación de funciones es muy simple. Cuando el evaluador encuentra una forma (f a1 a2...), supone que el símbolo denominado f es uno de los siguientes:

  1. Un operador especial (fácil de comprobar con una lista fija)
  2. Un operador macro (debe haber sido definido previamente)
  3. El nombre de una función (predeterminado), que puede ser un símbolo o una subforma que comienza con el símbolo lambda.

Si f es el nombre de una función, entonces los argumentos a1, a2, ..., an se evalúan en orden de izquierda a derecha y la función se encuentra y se invoca con esos valores suministrados como parámetros.

Definición de funciones

La macrodefun define funciones donde una definición de función proporciona el nombre de la función, los nombres de los argumentos y un cuerpo de la función:

 ( defun cuadrado ( x ) ( * x x ))  
     

Las definiciones de funciones pueden incluir directivas del compilador , conocidas como declaraciones , que proporcionan pistas al compilador sobre las configuraciones de optimización o los tipos de datos de los argumentos. También pueden incluir cadenas de documentación (docstrings), que el sistema Lisp puede utilizar para proporcionar documentación interactiva:

 ( defun square ( x ) "Calcula el cuadrado del punto flotante simple x." ( declare ( punto flotante simple x ) ( optimized ( speed 3 ) ( debug 0 ) ( safety 1 ))) ( el punto flotante simple ( * x x )))  
   
            
       

Las funciones anónimas ( literales de función ) se definen mediante lambdaexpresiones, por ejemplo, (lambda (x) (* x x))para una función que eleva al cuadrado su argumento. El estilo de programación Lisp utiliza con frecuencia funciones de orden superior para las que resulta útil proporcionar funciones anónimas como argumentos.

Las funciones locales se pueden definir con flety labels.

 ( flet (( cuadrado ( x ) ( * x x ))) ( cuadrado 3 ))  
            
    

Existen otros operadores relacionados con la definición y manipulación de funciones. Por ejemplo, una función puede compilarse con el compileoperador. (Algunos sistemas Lisp ejecutan funciones utilizando un intérprete de forma predeterminada, a menos que se les indique que las compilen; otros compilan todas las funciones).

Definición de funciones y métodos genéricos

La macro defgenericdefine funciones genéricas . Las funciones genéricas son una colección de métodos . La macro defmethoddefine métodos.

Los métodos pueden especializar sus parámetros en clases estándar de CLOS , clases de sistema , clases de estructura u objetos individuales. Para muchos tipos, existen clases de sistema correspondientes .

Cuando se llama a una función genérica, el envío múltiple determinará el método efectivo a utilizar.

 ( defgeneric añadir ( a b ))   
 ( defmethod add (( un número ) ( b número )) ( + a b ))     
     
 ( defmethod add (( a vector ) ( b número )) ( map 'vector ( lambda ( n ) ( + n b )) a ))     
          
 ( defmethod add (( a vector ) ( b vector )) ( map 'vector #' + a b ))     
       
( defmethod add (( una cadena ) ( b cadena )) ( concatenar 'cadena a b ))     
     
 ( suma 2 3 ) ; devuelve 5 ( suma #( 1 2 3 4 ) 7 ) ; devuelve #(8 9 10 11) ( suma #( 1 2 3 4 ) #( 4 3 2 1 )) ; devuelve #(5 5 5 5) ( suma "COMÚN " "LISP" ) ; devuelve "LISP COMÚN"                     
                
          
         

Las funciones genéricas también son un tipo de datos de primera clase . Las funciones y los métodos genéricos tienen muchas más características que las descritas anteriormente.

El espacio de nombres de la función

El espacio de nombres para los nombres de funciones es independiente del espacio de nombres para las variables de datos. Esta es una diferencia clave entre Common Lisp y Scheme . En Common Lisp, los operadores que definen nombres en el espacio de nombres de funciones incluyen defun, flet, labels, defmethody defgeneric.

Para pasar una función por su nombre como argumento a otra función, se debe utilizar el functionoperador especial, comúnmente abreviado como #'. El primer sortejemplo anterior se refiere a la función nombrada por el símbolo >en el espacio de nombres de la función, con el código #'>. Por el contrario, para llamar a una función pasada de esa manera, se utilizaría el funcalloperador en el argumento.

El modelo de evaluación de Scheme es más simple: solo hay un espacio de nombres y se evalúan todas las posiciones del formulario (en cualquier orden), no solo los argumentos. Por lo tanto, el código escrito en un dialecto a veces resulta confuso para los programadores con más experiencia en el otro. Por ejemplo, a muchos programadores de Common Lisp les gusta usar nombres de variables descriptivos, como lista o cadena , que podrían causar problemas en Scheme, ya que ocultarían localmente los nombres de las funciones.

En la comunidad Lisp, el debate sobre si un espacio de nombres independiente para las funciones es una ventaja o no es motivo de controversia. Suele hablarse de este debate como el debate Lisp-1 vs. Lisp-2 . Lisp-1 hace referencia al modelo de Scheme y Lisp-2 al modelo de Common Lisp. Estos nombres fueron acuñados en un artículo de 1988 de Richard P. Gabriel y Kent Pitman , que compara ampliamente los dos enfoques. [13]

Múltiples valores de retorno

Common Lisp admite el concepto de múltiples valores [14] , donde cualquier expresión siempre tiene un único valor primario , pero también puede tener cualquier número de valores secundarios , que pueden ser recibidos e inspeccionados por los llamadores interesados. Este concepto es distinto de devolver un valor de lista, ya que los valores secundarios son completamente opcionales y se pasan a través de un canal lateral dedicado. Esto significa que los llamadores pueden permanecer completamente inconscientes de la existencia de los valores secundarios si no los necesitan, y hace que sea conveniente utilizar el mecanismo para comunicar información que a veces es útil, pero no siempre necesaria. Por ejemplo,

  • La TRUNCATEfunción [15] redondea el número dado a un entero hacia cero. Sin embargo, también devuelve un resto como valor secundario, lo que hace que sea muy fácil determinar qué valor se truncó. También admite un parámetro divisor opcional, que se puede utilizar para realizar divisiones euclidianas de manera trivial:
( let (( x 1266778 ) ( y 458 )) ( enlace-de-valores-múltiples ( cociente resto ) ( truncar x y ) ( formato nil "~A dividido por ~A es ~A resto ~A" x y cociente resto )))  
       
    
        
          

;;;; => "1266778 dividido por 458 es 2765 resto 408"
  • GETHASH[16] devuelve el valor de una clave en un mapa asociativo , o el valor predeterminado en caso contrario, y un booleano secundario que indica si se encontró el valor. Por lo tanto, el código al que no le importa si el valor se encontró o se proporcionó como predeterminado puede simplemente usarlo tal como está, pero cuando dicha distinción es importante, puede inspeccionar el booleano secundario y reaccionar de manera apropiada. Ambos casos de uso son compatibles con la misma llamada y ninguno se ve innecesariamente sobrecargado o restringido por el otro. Tener esta característica a nivel de lenguaje elimina la necesidad de verificar la existencia de la clave o compararla con null como se haría en otros lenguajes.
( defun get-answer ( biblioteca ) ( gethash 'respuesta biblioteca 42 ))  
     

( defun the-answer-1 ( biblioteca ) ( formato nil "La respuesta es ~A" ( biblioteca get-answer ))) ;;;; Devuelve "La respuesta es 42" si RESPUESTA no está presente en BIBLIOTECA  
      


( defun the-answer-2 ( biblioteca ) ( enlace-de-valores-múltiples ( respuesta seguro-p ) ( obtener-respuesta biblioteca ) ( if ( no seguro-p ) "No sé" ( formato nil "La respuesta es ~A" respuesta )))) ;;;; Devuelve "No sé" si RESPUESTA no está presente en BIBLIOTECA  
    
       
      
        
        

Los valores múltiples son compatibles con un puñado de formularios estándar, los más comunes de los cuales son el MULTIPLE-VALUE-BINDformulario especial para acceder a valores secundarios y VALUESpara devolver valores múltiples:

( defun magic-eight-ball () "Devuelve una predicción de perspectiva, con la probabilidad como valor secundario" ( values ​​"Perspectiva buena" ( random 1.0 )))  
  
     

;;;; => "Perspectiva buena" 
;;;; => 0.3187

Otros tipos

Otros tipos de datos en Common Lisp incluyen:

  • Las rutas de acceso representan archivos y directorios en el sistema de archivos . La función de nombres de ruta de Common Lisp es más general que las convenciones de nombres de archivos de la mayoría de los sistemas operativos, lo que hace que el acceso a los archivos de los programas Lisp sea ampliamente portátil entre diversos sistemas.
  • Los flujos de entrada y salida representan fuentes y receptores de datos binarios o textuales, como la terminal o archivos abiertos.
  • Common Lisp tiene un generador de números pseudoaleatorios (PRNG) integrado . Los objetos de estado aleatorio representan fuentes reutilizables de números pseudoaleatorios, lo que permite al usuario inicializar el PRNG o hacer que reproduzca una secuencia.
  • Las condiciones son un tipo utilizado para representar errores, excepciones y otros eventos "interesantes" a los que un programa puede responder.
  • Las clases son objetos de primera clase y son, en sí mismas, instancias de clases llamadas clases de metaobjetos ( metaclases para abreviar).
  • Las tablas de lectura son un tipo de objeto que controla cómo el lector de Common Lisp analiza el texto del código fuente. Al controlar qué tabla de lectura se utiliza cuando se lee el código, el programador puede cambiar o ampliar la sintaxis del lenguaje.

Alcance

Al igual que los programas de muchos otros lenguajes de programación, los programas Common Lisp utilizan nombres para hacer referencia a variables, funciones y muchos otros tipos de entidades. Las referencias con nombre están sujetas a un alcance.

La asociación entre un nombre y la entidad a la que el nombre hace referencia se denomina enlace.

El alcance se refiere al conjunto de circunstancias en las que se determina que un nombre tiene un vínculo particular.

Determinantes del alcance

Las circunstancias que determinan el alcance en Common Lisp incluyen:

  • la ubicación de una referencia dentro de una expresión. Si es la posición más a la izquierda de un compuesto, se refiere a un operador especial o a una macro o a un enlace de función; de lo contrario, se refiere a un enlace de variable o a otra cosa.
  • el tipo de expresión en la que tiene lugar la referencia. 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 xpueden estar activos en la misma región del texto del programa, ya que las etiquetas del cuerpo de la etiqueta están en un espacio de nombres separado de los nombres de las variables. Una forma especial o forma de macro tiene control completo 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, por lo que estos nombres se buscan en el espacio de nombres de clase, y xno es una referencia a un enlace existente, sino el nombre de una nueva clase que se deriva de ay b. Estos hechos surgen puramente de la semántica de defclass. El único hecho genérico sobre esta expresión es que defclassse refiere a un enlace de macro; todo lo demás depende de defclass.
  • la ubicación de la referencia dentro del texto del programa. Por ejemplo, si una referencia a una variable xestá incluida en una construcción de enlace como una letque define un enlace para x, entonces la referencia está en el ámbito creado por ese enlace.
  • Para una referencia variable, si un símbolo de variable ha sido declarado especial, local o globalmente. Esto determina si la referencia se resuelve dentro de un entorno léxico o dentro de un entorno dinámico.
  • la instancia específica del entorno en el que se resuelve la referencia. Un entorno es un diccionario en tiempo de ejecución que asigna símbolos a enlaces. Cada tipo de referencia utiliza su propio tipo de entorno. Las referencias a variables léxicas se resuelven en un entorno léxico, etcétera. Se puede asociar más de un entorno a la misma referencia. Por ejemplo, gracias a la recursión o al uso de múltiples subprocesos, pueden existir múltiples activaciones de la misma función al mismo tiempo. Estas activaciones comparten el mismo texto de programa, pero cada una tiene su propia instancia de entorno léxico.

Para entender a qué se refiere un símbolo, el programador Common Lisp debe saber qué tipo de referencia se está expresando, qué tipo de ámbito utiliza si es una referencia de variable (ámbito dinámico versus léxico) y también la situación de tiempo de ejecución: en qué entorno se resuelve la referencia, dónde se introdujo el enlace en el entorno, etcétera.

Tipos de ambiente

Global

Algunos entornos de Lisp son de alcance global. Por ejemplo, si se define un nuevo tipo, se conocerá en todas partes a partir de entonces. Las referencias a ese tipo lo buscan en este entorno global.

Dinámica

Un tipo de entorno en Common Lisp es el entorno dinámico. Los enlaces establecidos en este entorno tienen una extensión dinámica, lo que significa que un enlace se establece al comienzo de la ejecución de algún constructo, como un letbloque, y desaparece cuando ese constructo termina de ejecutarse: su duración está ligada a la activación y desactivación dinámica de un bloque. Sin embargo, un enlace dinámico no solo es visible dentro de ese bloque; también es visible para todas las funciones invocadas desde ese bloque. Este tipo de visibilidad se conoce como alcance indefinido. Se dice que los enlaces que presentan una extensión dinámica (duración ligada a la activación y desactivación de un bloque) y un alcance indefinido (visible para todas las funciones que se invocan desde ese bloque) tienen alcance dinámico.

Common Lisp admite variables con alcance dinámico, también llamadas variables especiales. Algunos otros tipos de enlaces también tienen necesariamente un alcance dinámico, como las etiquetas de reinicio y de captura. Los enlaces de funciones no pueden tener un alcance dinámico usando flet(que solo proporciona enlaces de funciones con alcance léxico), pero los objetos de función (un objeto de primer nivel en Common Lisp) pueden asignarse a variables con alcance dinámico, vincularse usando leten el alcance dinámico y luego llamarse usando funcallo APPLY.

El alcance dinámico es extremadamente útil porque agrega claridad referencial y disciplina a las variables globales . Las variables globales están mal vistas en la informática como posibles fuentes de error, porque pueden dar lugar a canales de comunicación encubiertos y ad hoc entre módulos que conducen a interacciones no deseadas y sorprendentes.

En Common Lisp, una variable especial que solo tiene un enlace de nivel superior se comporta igual que una variable global en otros lenguajes de programación. Se puede almacenar un nuevo valor en ella y ese valor simplemente reemplaza lo que está en el enlace de nivel superior. El reemplazo descuidado del valor de una variable global es la causa principal de los errores causados ​​por el uso de variables globales. Sin embargo, otra forma de trabajar con una variable especial es darle un nuevo enlace local dentro de una expresión. Esto a veces se conoce como "reenlazar" la variable. La vinculación de una variable con ámbito dinámico crea temporalmente una nueva ubicación de memoria para esa variable y asocia el nombre con esa ubicación. Mientras ese enlace está en efecto, todas las referencias a esa variable se refieren al nuevo enlace; el enlace anterior se oculta. Cuando finaliza la ejecución de la expresión de enlace, la ubicación de memoria temporal desaparece y se revela el enlace anterior, con el valor original intacto. Por supuesto, se pueden anidar múltiples enlaces dinámicos para la misma variable.

En las implementaciones de Common Lisp que admiten subprocesos múltiples, los ámbitos dinámicos son específicos de cada subproceso de ejecución. Por lo tanto, las variables especiales sirven como una abstracción para el almacenamiento local de subprocesos. Si un subproceso vuelve a vincular una variable especial, esta revinculación no tiene efecto sobre esa variable en otros subprocesos. El valor almacenado en una vinculación solo puede ser recuperado por el subproceso que creó esa vinculación. Si cada subproceso vincula alguna variable especial *x*, entonces *x*se comporta como almacenamiento local de subprocesos. Entre los subprocesos que no vuelven a vincular *x*, se comporta como un global ordinario: todos estos subprocesos hacen referencia a la misma vinculación de nivel superior de *x*.

Las variables dinámicas se pueden utilizar para ampliar el contexto de ejecución con información de contexto adicional que se pasa implícitamente de una función a otra sin tener que aparecer como un parámetro de función adicional. Esto es especialmente útil cuando la transferencia de control tiene que pasar por capas de código no relacionado, que simplemente no se pueden ampliar con parámetros adicionales para pasar los datos adicionales. Una situación como esta suele requerir una variable global. Esa variable global se debe guardar y restaurar, de modo que el esquema no se rompa bajo la recursión: la revinculación de variables dinámicas se encarga de esto. Y esa variable debe hacerse local para el subproceso (o de lo contrario se debe utilizar un mutex grande) para que el esquema no se rompa bajo los subprocesos: las implementaciones de ámbito dinámico también pueden encargarse de esto.

En la biblioteca Common Lisp, hay muchas variables especiales estándar. Por ejemplo, todos los flujos de E/S estándar se almacenan en los enlaces de nivel superior de variables especiales conocidas. El flujo de salida estándar se almacena en *standard-output*.

Supongamos que una función foo escribe en la salida estándar:

  ( defun foo () ( formato t "Hola, mundo" )  
      

Para capturar su salida en una cadena de caracteres, *standard-output* se puede vincular a un flujo de cadena y llamar:

  ( con salida a cadena ( * salida estándar * ) ( foo )) 
    
-> "Hola, mundo"; la salida recopilada se devuelve como una cadena

Léxico

Common Lisp admite entornos léxicos. Formalmente, los enlaces en un entorno léxico tienen un alcance léxico y pueden tener una extensión indefinida o dinámica, según el tipo de espacio de nombres. El alcance léxico significa que la visibilidad está restringida físicamente al bloque en el que se establece el enlace. Las referencias que no están textualmente (es decir, léxicamente) incrustadas en ese bloque simplemente no ven ese enlace.

Las etiquetas de un TAGBODY tienen alcance léxico. La expresión (GO X) es errónea si no está incrustada en un TAGBODY que contiene una etiqueta X. Sin embargo, los enlaces de etiquetas desaparecen cuando el TAGBODY finaliza su ejecución, porque tienen alcance dinámico. Si ese bloque de código se vuelve a ingresar mediante la invocación de un cierre léxico , no es válido que el cuerpo de ese cierre intente transferir el control a una etiqueta a través de GO:

  ( defvar *stashed* ) ;; contendrá una función  

  ( tagbody 
( setf *stashed* ( lambda () ( go some-label ))) ( go end-label ) ;; omitir (imprimir "Hola") some-label ( imprimir "Hola" ) end-label ) -> NIL         
      
   
     
   
   

Cuando se ejecuta TAGBODY, primero evalúa la forma setf que almacena una función en la variable especial *stashed*. Luego (go end-label) transfiere el control a end-label, salteándose el código (print "Hello"). Dado que end-label está al final del cuerpo de la etiqueta, este termina, dando como resultado NIL. Supongamos que ahora se llama a la función recordada anteriormente:

  ( funcall *escondido* ) ;; ¡Error!  

Esta situación es errónea. La respuesta de una implementación es una condición de error que contiene el mensaje "GO: el cuerpo de etiqueta para la etiqueta SOME-LABEL ya se ha dejado". La función intentó evaluar (go some-label), que está léxicamente incrustado en el cuerpo de etiqueta, y se resuelve en la etiqueta. Sin embargo, el cuerpo de etiqueta no se está ejecutando (su extensión ha finalizado), por lo que la transferencia de control no puede tener lugar.

Los enlaces de funciones locales en Lisp tienen un alcance léxico , y los enlaces de variables también tienen un alcance léxico por defecto. A diferencia de las etiquetas GO, ambas tienen una extensión indefinida. Cuando se establece un enlace de función o variable léxica, ese enlace continúa existiendo mientras sean posibles las referencias a él, incluso después de que haya terminado la construcción que estableció ese enlace. Las referencias a variables y funciones léxicas después de la terminación de su construcción de establecimiento son posibles gracias a los cierres léxicos .

La vinculación léxica es el modo de vinculación predeterminado para las variables de Common Lisp. Para un símbolo individual, se puede cambiar a un ámbito dinámico, ya sea mediante una declaración local o mediante una declaración global. Esto último puede ocurrir implícitamente mediante el uso de una construcción como DEFVAR o DEFPARAMETER. Es una convención importante en la programación de Common Lisp que las variables especiales (es decir, de ámbito dinámico) tengan nombres que comiencen y terminen con un asterisco, en * lo que se denomina la " convención de las orejeras ". [17] Si se respeta, esta convención crea efectivamente un espacio de nombres separado para las variables especiales, de modo que las variables que se pretende que sean léxicas no se conviertan en especiales accidentalmente.

El alcance léxico es útil por varias razones.

En primer lugar, las referencias a variables y funciones se pueden compilar en código de máquina eficiente, porque la estructura del entorno de ejecución es relativamente simple. En muchos casos, se puede optimizar para el almacenamiento en pila, por lo que abrir y cerrar ámbitos léxicos tiene una sobrecarga mínima. Incluso en los casos en los que se deben generar cierres completos, el acceso al entorno del cierre sigue siendo eficiente; normalmente, cada variable se convierte en un desplazamiento en un vector de enlaces, y así una referencia de variable se convierte en una simple instrucción de carga o almacenamiento con un modo de direccionamiento de base más desplazamiento .

En segundo lugar, el alcance léxico (combinado con la extensión indefinida) da lugar al cierre léxico , que a su vez crea todo un paradigma de programación centrado en el uso de funciones que son objetos de primera clase, que es la raíz de la programación funcional.

En tercer lugar, y quizás lo más importante, incluso si no se explotan los cierres léxicos, el uso del ámbito léxico aísla los módulos del programa de interacciones no deseadas. Debido a su visibilidad restringida, las variables léxicas son privadas. Si un módulo A vincula una variable léxica X y llama a otro módulo B, las referencias a X en B no se resolverán accidentalmente en el límite de X en A. B simplemente no tiene acceso a X. Para situaciones en las que son deseables las interacciones disciplinadas a través de una variable, Common Lisp proporciona variables especiales. Las variables especiales permiten que un módulo A establezca un enlace para una variable X que sea visible para otro módulo B, llamado desde A. Poder hacer esto es una ventaja, y poder evitar que suceda también es una ventaja; en consecuencia, Common Lisp admite tanto el ámbito léxico como el dinámico .

Macros

En Lisp, una macro se parece superficialmente a una función. Sin embargo, en lugar de representar una expresión que se evalúa, representa una transformación del código fuente del programa. La macro obtiene el código fuente que rodea como argumentos, los vincula a sus parámetros y calcula una nueva forma de código fuente. Esta nueva forma también puede utilizar una macro. La expansión de la macro se repite hasta que la nueva forma de código fuente no utilice una macro. La forma calculada final es el código fuente que se ejecuta en tiempo de ejecución.

Usos típicos de macros en Lisp:

  • Nuevas estructuras de control (ejemplo: construcciones de bucle, construcciones de ramificación)
  • construcciones de alcance y vinculación
  • Sintaxis simplificada para código fuente complejo y repetido.
  • Formularios de definición de nivel superior con efectos secundarios en tiempo de compilación
  • programación basada en datos
  • Idiomas específicos del dominio integrados (ejemplos: SQL , HTML , Prolog )
  • formas de finalización implícita

También es necesario implementar como macros varias funciones estándar de Common Lisp, como:

  • La setfabstracción estándar, para permitir expansiones personalizadas en tiempo de compilación de operadores de asignación/acceso.
  • with-accessors, with-slots, y otras macros with-open-filesimilaresWITH
  • Dependiendo de la implementación, ifo condes una macro construida sobre la otra, el operador especial; wheny unlessconsisten en macros
  • El poderoso looplenguaje específico del dominio

Las macros se definen mediante la macro defmacro . El operador especial macrolet permite la definición de macros locales (con alcance léxico). También es posible definir macros para símbolos mediante define-symbol-macro y symbol-macrolet .

El libro de Paul Graham , On Lisp, describe en detalle el uso de macros en Common Lisp. El libro de Doug Hoyte, Let Over Lambda, amplía el debate sobre las macros, afirmando que "las macros son la mayor ventaja que tiene Lisp como lenguaje de programación y la mayor ventaja de cualquier lenguaje de programación". Hoyte proporciona varios ejemplos de desarrollo iterativo de macros.

Ejemplo de uso de una macro para definir una nueva estructura de control

Las macros permiten a los programadores de Lisp crear nuevas formas sintácticas en el lenguaje. Un uso típico es crear nuevas estructuras de control. La macro de ejemplo proporciona una untilconstrucción de bucle. La sintaxis es:

(hasta el formato de prueba*)

La definición de macro para hasta :

( defmacro hasta ( prueba & cuerpo cuerpo ) ( let (( etiqueta-inicio ( gensym "INICIO" )) ( etiqueta-fin ( gensym "FIN" ))) ` ( cuerpo-etiqueta , etiqueta-inicio ( cuando , prueba ( ir , etiqueta-fin )) ( progn , @ cuerpo ) ( ir , etiqueta-inicio ) , etiqueta-fin )))    
     
            
     
                 
               
               
              

tagbody es un operador especial primitivo de Common Lisp que proporciona la capacidad de nombrar etiquetas y usar la forma go para saltar a esas etiquetas. La comilla invertida ` proporciona una notación que proporciona plantillas de código, donde se completa el valor de las formas precedidas por una coma. Las formas precedidas por una coma y un signo arroba se insertan . La forma tagbody prueba la condición final. Si la condición es verdadera, salta a la etiqueta final. De lo contrario, se ejecuta el código del cuerpo proporcionado y luego salta a la etiqueta inicial.

Un ejemplo del uso de la macro hasta anterior :

( hasta ( = ( aleatorio 10 ) 0 ) ( línea de escritura "Hola" ))    
   

El código se puede expandir utilizando la función macroexpand-1 . La expansión del ejemplo anterior se ve así:

( TAGBODY 
#:START1136 ( CUANDO ( ZEROP ( ALEATORIO 10 )) ( GO #:END1137 )) ( PROGN ( WRITE-LINE "hola" )) ( GO #:START1136 ) #:END1137 ) 
    
    
   
  
 

Durante la expansión de la macro, el valor de la variable test es (= (random 10) 0) y el valor de la variable body es ((write-line "Hello")) . El cuerpo es una lista de formularios.

Los símbolos se convierten automáticamente en mayúsculas y minúsculas. La expansión utiliza TAGBODY con dos etiquetas. Los símbolos para estas etiquetas son calculados por GENSYM y no se almacenan en ningún paquete. Dos formas go utilizan estas etiquetas para saltar a ellas. Dado que tagbody es un operador primitivo en Common Lisp (y no una macro), no se expandirá a otra cosa. La forma expandida utiliza la macro when , que también se expandirá. La expansión completa de una forma fuente se denomina " code walking" .

En la forma completamente expandida ( walked ), la forma when se reemplaza por la primitiva if :

( TAGBODY 
#:START1136 ( IF ( ZEROP ( RANDOM 10 )) ( PROGN ( GO #:END1137 )) NIL ) ( PROGN ( WRITE-LINE "hola" )) ( GO #:START1136 )) #:END1137 ) 
    
       
   
   
  
 

Todas las macros deben expandirse antes de que el código fuente que las contiene pueda evaluarse o compilarse normalmente. Las macros pueden considerarse funciones que aceptan y devuelven expresiones S , similares a los árboles de sintaxis abstracta , pero no limitadas a ellos. Estas funciones se invocan antes que el evaluador o compilador para producir el código fuente final. Las macros se escriben en Common Lisp normal y pueden usar cualquier operador de Common Lisp (o de terceros) disponible.

Captura variable y sombreado

Las macros de Common Lisp son capaces de realizar lo que comúnmente se denomina captura de variables , donde los símbolos en el cuerpo de la expansión de la macro coinciden con los del contexto de llamada, lo que permite al programador crear macros en las que varios símbolos tienen un significado especial. El término captura de variables es un tanto engañoso, porque todos los espacios de nombres son vulnerables a la captura no deseada, incluidos los espacios de nombres de operadores y funciones, los espacios de nombres de etiquetas de cuerpo de etiqueta, etiquetas catch, manejadores de condiciones y espacios de nombres de reinicio.

La captura de variables puede introducir defectos en el software. Esto sucede de una de las dos maneras siguientes:

  • En el primer caso, una expansión de macro puede crear inadvertidamente una referencia simbólica que el autor de la macro supuso que se resolvería en un espacio de nombres global, pero el código en el que se expande la macro proporciona una definición local que roba esa referencia. A esto lo llamaremos captura de tipo 1.
  • La segunda forma, captura de tipo 2, es exactamente la opuesta: algunos de los argumentos de la macro son fragmentos de código suministrados por el llamador de la macro, y esos fragmentos de código están escritos de tal manera que hacen referencia a los enlaces circundantes. Sin embargo, la macro inserta estos fragmentos de código en una expansión que define sus propios enlaces que capturan accidentalmente algunas de estas referencias.

El dialecto Scheme de Lisp proporciona un sistema de escritura de macros que proporciona la transparencia referencial que elimina ambos tipos de problemas de captura. Este tipo de sistema de macros a veces se denomina "higiénico", en particular por sus defensores (que consideran que los sistemas de macros que no resuelven automáticamente este problema son antihigiénicos). [ cita requerida ]

En Common Lisp, la higiene macro se garantiza de dos maneras diferentes.

Un enfoque es utilizar gensyms : símbolos garantizados únicos que pueden utilizarse en una macroexpansión sin amenaza de captura. El uso de gensyms en una definición de macro es una tarea manual, pero se pueden escribir macros que simplifiquen la instanciación y el uso de gensyms. Los gensyms resuelven la captura de tipo 2 fácilmente, pero no son aplicables a la captura de tipo 1 de la misma manera, porque la macroexpansión no puede cambiar el nombre de los símbolos que interfieren en el código circundante que capturan sus referencias. Los gensyms se pueden utilizar para proporcionar alias estables para los símbolos globales que necesita la macroexpansión. La macroexpansión utilizaría estos alias secretos en lugar de los nombres conocidos, por lo que la redefinición de los nombres conocidos no tendría ningún efecto negativo en la macro.

Otro enfoque es el uso de paquetes. Una macro definida en su propio paquete puede simplemente usar símbolos internos de ese paquete en su expansión. El uso de paquetes se ocupa de la captura de tipo 1 y tipo 2.

Sin embargo, los paquetes no resuelven la captura de tipo 1 de referencias a funciones y operadores estándar de Common Lisp. La razón es que el uso de paquetes para resolver problemas de captura gira en torno al uso de símbolos privados (símbolos en un paquete, que no se importan ni se hacen visibles en otros paquetes). Mientras que los símbolos de la biblioteca Common Lisp son externos y con frecuencia se importan o se hacen visibles en paquetes definidos por el usuario.

El siguiente es un ejemplo de captura no deseada en el espacio de nombres del operador, que ocurre en la expansión de una macro:

 ;; la expansión de UNTIL hace un uso liberal de DO 
( defmacro hasta ( expresión &cuerpo cuerpo ) ` ( do ( ) ( , expresión ) ,@ cuerpo ))     
      

 ;; macrolet establece la vinculación del operador léxico para DO 
( macrolet (( do ( ... ) ... algo más ... )) ( hasta que ( = ( aleatorio 10 ) 0 ) ( línea de escritura "Hola" )))       
         

La untilmacro se expandirá a una forma que invoque dolo que pretende hacer referencia a la macro estándar de Common Lisp do. Sin embargo, en este contexto, dopuede tener un significado completamente diferente, por lo que untiles posible que no funcione correctamente.

Common Lisp resuelve el problema del sombreado de operadores y funciones estándar al prohibir su redefinición. Debido a que redefine el operador estándar do, lo anterior es en realidad un fragmento de Common Lisp no conforme, lo que permite que las implementaciones lo diagnostiquen y lo rechacen.

Sistema de condiciones

El sistema de condiciones es responsable del manejo de excepciones en Common Lisp. [18] Proporciona condiciones , manejadores y reinicios . Las condiciones son objetos que describen una situación excepcional (por ejemplo, un error). Si se señala una condición , el sistema Common Lisp busca un manejador para este tipo de condición y llama al manejador. El manejador ahora puede buscar reinicios y usar uno de estos reinicios para reparar automáticamente el problema actual, usando información como el tipo de condición y cualquier información relevante proporcionada como parte del objeto de condición, y llamar a la función de reinicio apropiada.

Estos reinicios, si no son controlados por código, pueden presentarse a los usuarios (como parte de una interfaz de usuario, la de un depurador, por ejemplo), de modo que el usuario pueda seleccionar e invocar uno de los reinicios disponibles. Dado que el controlador de condiciones se llama en el contexto del error (sin desenrollar la pila), la recuperación completa del error es posible en muchos casos, donde otros sistemas de manejo de excepciones ya habrían terminado la rutina actual. El depurador en sí también puede personalizarse o reemplazarse utilizando la *debugger-hook*variable dinámica. El código que se encuentra dentro de los formularios de protección de desenrollado, como los finalizadores, también se ejecutará según corresponda a pesar de la excepción.

En el siguiente ejemplo (utilizando Symbolics Genera ), el usuario intenta abrir un archivo en una prueba de función Lisp llamada desde Read-Eval-Print-LOOP ( REPL ), cuando el archivo no existe. El sistema Lisp presenta cuatro reinicios. El usuario selecciona Retry OPEN utilizando una ruta de reinicio diferente e ingresa una ruta de reinicio diferente (lispm-init.lisp en lugar de lispm-int.lisp). El código de usuario no contiene ningún código de manejo de errores. Todo el código de manejo de errores y reinicio lo proporciona el sistema Lisp, que puede manejar y reparar el error sin terminar el código de usuario.

Comando: (prueba ">zippy>lispm-int.lisp")

Error: No se encontró el archivo.
       Para lispm:>zippy>lispm-int.lisp.newest

LMFS:ABIERTO-LOCAL-LMFS-1
   Argumento 0: #P"lispm:>zippy>lispm-int.lisp.newest"

sA, <Reanudar>: Reintentar ABRIR lispm:>zippy>lispm-int.lisp.newest
sB: Vuelva a intentar ABRIR utilizando una ruta diferente
sC, <Abort>: Regresar al nivel superior de Lisp en un servidor TELNET
sD: Reiniciar proceso terminal TELNET

-> Reintentar ABRIR usando una ruta diferente
Utilice la ruta de acceso en su lugar [lispm predeterminado:>zippy>lispm-int.lisp.newest]:
   lispm:>zippy>lispm-init.lisp.más nuevo

...el programa continúa

Sistema de objetos Common Lisp (CLOS)

Common Lisp incluye un conjunto de herramientas para programación orientada a objetos , el Common Lisp Object System o CLOS . Peter Norvig explica cómo muchos patrones de diseño son más simples de implementar en un lenguaje dinámico con las características de CLOS (herencia múltiple, mixins, métodos múltiples, metaclases, combinaciones de métodos, etc.). [19] Se han propuesto varias extensiones de Common Lisp para programación orientada a objetos para incluirlas en el estándar ANSI Common Lisp, pero finalmente CLOS se adoptó como el sistema de objetos estándar para Common Lisp. CLOS es un sistema de objetos dinámico con envío múltiple y herencia múltiple , y difiere radicalmente de las facilidades OOP que se encuentran en lenguajes estáticos como C++ o Java . Como sistema de objetos dinámico, CLOS permite cambios en tiempo de ejecución en funciones y clases genéricas. Se pueden agregar y eliminar métodos, se pueden agregar y redefinir clases, se pueden actualizar objetos para cambios de clase y se puede cambiar la clase de objetos.

CLOS se ha integrado en ANSI Common Lisp. Las funciones genéricas se pueden utilizar como funciones normales y son un tipo de datos de primera clase. Cada clase CLOS está integrada en el sistema de tipos Common Lisp. Muchos tipos Common Lisp tienen una clase correspondiente. Hay más uso potencial de CLOS para Common Lisp. La especificación no dice si las condiciones se implementan con CLOS. Los nombres de ruta y los flujos se podrían implementar con CLOS. Estas posibilidades de uso adicionales de CLOS para ANSI Common Lisp no son parte del estándar. Las implementaciones reales de Common Lisp utilizan CLOS para nombres de ruta, flujos, entrada-salida, condiciones, la implementación de CLOS en sí y más.

Compilador e intérprete

Un intérprete de Lisp ejecuta directamente el código fuente de Lisp proporcionado como objetos de Lisp (listas, símbolos, números, etc.) leídos desde expresiones-s. Un compilador de Lisp genera código de bytes o código de máquina a partir del código fuente de Lisp. Common Lisp permite compilar funciones de Lisp individuales en memoria y compilar archivos completos en código compilado almacenado externamente ( archivos fasl ).

Varias implementaciones de dialectos Lisp anteriores proporcionaban tanto un intérprete como un compilador. Desafortunadamente, a menudo la semántica era diferente. Estos Lisp anteriores implementaban el alcance léxico en el compilador y el alcance dinámico en el intérprete. Common Lisp requiere que tanto el intérprete como el compilador utilicen el alcance léxico de forma predeterminada. El estándar Common Lisp describe tanto la semántica del intérprete como la de un compilador. El compilador puede ser llamado utilizando la función compile para funciones individuales y utilizando la función compile-file para archivos. Common Lisp permite declaraciones de tipos y proporciona formas de influir en la política de generación de código del compilador. Para este último, se pueden dar valores entre 0 (no importante) y 3 (el más importante) a varias cualidades de optimización: speed , space , safety , debug y compilation-speed .

También hay una función para evaluar código Lisp: eval. evaltoma el código como expresiones s preanalizadas y no, como en otros lenguajes, como cadenas de texto. De esta manera, el código se puede construir con las funciones Lisp habituales para construir listas y símbolos y luego este código se puede evaluar con la función eval. Varias implementaciones de Common Lisp (como Clozure CL y SBCL) se implementan evalutilizando su compilador. De esta manera, el código se compila, aunque se evalúe utilizando la función eval.

El compilador de archivos se invoca mediante la función compile-file . El archivo generado con el código compilado se denomina archivo fasl (de fast load ). Estos archivos fasl y también los archivos de código fuente se pueden cargar con la función load en un sistema Common Lisp en ejecución. Según la implementación, el compilador de archivos genera código de bytes (por ejemplo, para la máquina virtual de Java ), código en lenguaje C (que luego se compila con un compilador de C) o, directamente, código nativo.

Las implementaciones de Common Lisp se pueden utilizar de forma interactiva, aunque el código se compile por completo. Por lo tanto, la idea de un lenguaje interpretado no se aplica a Common Lisp interactivo.

El lenguaje hace una distinción entre tiempo de lectura, tiempo de compilación, tiempo de carga y tiempo de ejecución, y permite que el código de usuario también haga esta distinción para realizar el tipo de procesamiento deseado en el paso deseado.

Se proporcionan algunos operadores especiales para adaptarse especialmente al desarrollo interactivo; por ejemplo, defvarsolo asignará un valor a su variable proporcionada si no estaba ya vinculada, mientras que defparametersiempre realizará la asignación. Esta distinción es útil cuando se evalúa, compila y carga código de forma interactiva en una imagen en vivo.

También se proporcionan algunas funciones para ayudar a escribir compiladores e intérpretes. Los símbolos consisten en objetos de primer nivel y son manipulables directamente por el código del usuario. El progvoperador especial permite crear enlaces léxicos mediante programación, mientras que los paquetes también son manipulables. El compilador de Lisp está disponible en tiempo de ejecución para compilar archivos o funciones individuales. Esto facilita el uso de Lisp como compilador o intérprete intermedio para otro lenguaje.

Ejemplos de código

Paradoja del cumpleaños

El siguiente programa calcula el número más pequeño de personas en una sala para las cuales la probabilidad de cumpleaños únicos es menor del 50% (la paradoja del cumpleaños , donde para 1 persona la probabilidad es obviamente del 100%, para 2 es 364/365, etc.). La respuesta es 23.

En Common Lisp, por convención, las constantes se encierran entre caracteres +.

( defconstant + tamaño-año+ 365 )  

( defun paradoja-de-cumpleaños ( probabilidad numero-de-personas ) ( let (( nueva-probabilidad ( * ( / ( - +año-tamaño+ numero-de-personas ) +año-tamaño+ ) probabilidad ))) ( if ( < nueva-probabilidad 0.5 ) ( 1+ numero-de-personas ) ( paradoja-de-cumpleaños nueva-probabilidad ( 1+ numero-de-personas )))))   
        
                               
                            
       
         
           

Llamar a la función de ejemplo utilizando REPL (Read Eval Print Loop):

CL-USER > (cumpleaños-paradoja 1.0 1)
23

Ordenar una lista de objetos de persona

Definimos una clase persony un método para mostrar el nombre y la edad de una persona. A continuación, definimos un grupo de personas como una lista de personobjetos. Luego, iteramos sobre la lista ordenada.

( defclass person () (( name :initarg :name :accessor person-name ) ( age :initarg :age :accessor person-age )) ( :documentation "La clase PERSONA con los espacios NOMBRE y EDAD." ))  
      
         
   

( defmethod display (( object person ) stream ) "Mostrando un objeto PERSONA en un flujo de salida." ( with-slots ( name age ) object ( format stream "~a (~a)" name age )))    
  
     
        

( defparameter *group* ( list ( make-instance 'person :name "Bob" :age 33 ) ( make-instance 'person :name "Chris" :age 16 ) ( make-instance 'person :name "Ash" :age 23 )) "Una lista de objetos PERSONA." ) 
          
             
               
  

( dolist ( persona ( sort ( lista-de-copias *grupo* ) #' > :key #' edad-de-persona )) ( mostrar persona *salida-estándar* ) ( terpri ))    
                      
                       
    
  

Imprime los tres nombres con edad descendente.

Bob (33)
Ceniza (23)
Cristóbal (16)

Exponenciando por cuadrado

Se demuestra el uso de la macro LOOP:

( defun potencia ( x n ) ( bucle con resultado = 1 mientras ( plusp n ) cuando ( oddp n ) hacer ( setf resultado ( * resultado x )) hacer ( setf x ( * x x ) n ( truncar n 2 )) finalmente ( devolver resultado )))   
      
          
                
             
                    
          

Ejemplo de uso:

CL-USUARIO > ( potencia 2 200 ) 1606938044258990275541962092341162602522202993782792835301376    

Compárese con la exponenciación incorporada:

CL-USUARIO > ( = ( expt 2 200 ) ( potencia 2 200 )) T        

Encuentra la lista de conchas disponibles

WITH-OPEN-FILE es una macro que abre un archivo y proporciona un flujo de datos. Cuando se devuelve el formulario, el archivo se cierra automáticamente. FUNCALL llama a un objeto de función. LOOP recopila todas las líneas que coinciden con el predicado.

( defun list-matching-lines ( file predicate ) "Devuelve una lista de líneas en el archivo, para las cuales el predicado aplicado a la línea devuelve T." ( with-open-file ( stream file ) ( loop for line = ( read-line stream nil nil ) while line when ( funcall predicate line ) collect it )))   
  

    
           
           
             
           

La función AVAILABLE-SHELLS llama a la función LIST-MATCHING-LINES anterior con una ruta de acceso y una función anónima como predicado. El predicado devuelve la ruta de acceso de un shell o NIL (si la cadena no es el nombre de archivo de un shell).

( defun available-shells ( &optional ( file #p"/etc/shells" )) ( list-matching-lines file ( lambda ( line ) ( and ( plusp ( length line )) ( char= ( char line 0 ) #\/ ) ( pathname ( string-right-trim ' ( #\space #\tab ) line ))))))    
  
   
    
        
              
          
              

Resultados de ejemplo (en Mac OS X 10.6):

CL-USER > ( shells disponibles ) ( #P"/bin/bash" #P"/bin/csh" #P"/bin/ksh" #P"/bin/sh" #P"/bin/tcsh" #P"/bin/zsh" )  
     

Comparación con otros Lisp

Common Lisp se compara y contrasta con Scheme con mucha frecuencia , aunque sólo sea porque son los dos dialectos de Lisp más populares. Scheme es anterior a CL y no sólo proviene de la misma tradición de Lisp, sino también de algunos de los mismos ingenieros: Guy Steele , con quien Gerald Jay Sussman diseñó Scheme, presidió el comité de estándares de Common Lisp.

Common Lisp es un lenguaje de programación de propósito general, a diferencia de las variantes de Lisp como Emacs Lisp y AutoLISP , que son lenguajes de extensión integrados en productos específicos (GNU Emacs y AutoCAD, respectivamente). A diferencia de muchos Lisp anteriores, Common Lisp (como Scheme ) utiliza el alcance de la variable léxica de manera predeterminada tanto para el código interpretado como para el compilado.

La mayoría de los sistemas Lisp cuyos diseños contribuyeron a Common Lisp (como ZetaLisp y Franz Lisp) utilizaban variables con ámbito dinámico en sus intérpretes y variables con ámbito léxico en sus compiladores. Scheme introdujo el uso exclusivo de variables con ámbito léxico en Lisp; una inspiración de ALGOL 68. CL también admite variables con ámbito dinámico, pero deben declararse explícitamente como "especiales". No existen diferencias en el ámbito entre los intérpretes y compiladores ANSI CL.

A Common Lisp se le denomina a veces Lisp-2 y a Scheme Lisp-1 , en referencia al uso de CL de espacios de nombres separados para funciones y variables. (De hecho, CL tiene muchos espacios de nombres, como los de las etiquetas go, nombres de bloques y looppalabras clave). Existe una controversia de larga data entre los defensores de CL y Scheme sobre las compensaciones involucradas en múltiples espacios de nombres. En Scheme, es (ampliamente) necesario evitar dar nombres de variables que entren en conflicto con las funciones; las funciones de Scheme con frecuencia tienen argumentos llamados lis, lst, o lystpara no entrar en conflicto con la función del sistema list. Sin embargo, en CL es necesario hacer referencia explícita al espacio de nombres de la función cuando se pasa una función como argumento, lo que también es una ocurrencia común, como en el sortejemplo anterior.

CL también difiere de Scheme en su manejo de valores booleanos. Scheme usa los valores especiales #t y #f para representar la verdad y la falsedad. CL sigue la antigua convención de Lisp de usar los símbolos T y NIL, donde NIL también representa la lista vacía. En CL, cualquier valor que no sea NIL se trata como verdadero mediante condicionales, como if, mientras que en Scheme todos los valores que no sean #f se tratan como verdaderos. Estas convenciones permiten que algunos operadores en ambos lenguajes sirvan como predicados (respondiendo a una pregunta con valor booleano) y como retorno de un valor útil para cálculos posteriores, pero en Scheme el valor '() que es equivalente a NIL en Common Lisp se evalúa como verdadero en una expresión booleana.

Por último, los documentos de estándares de Scheme requieren optimización de llamadas de cola , algo que el estándar CL no hace. La mayoría de las implementaciones de CL ofrecen optimización de llamadas de cola, aunque a menudo solo cuando el programador usa una directiva de optimización. No obstante, el estilo de codificación CL común no favorece el uso ubicuo de la recursión que prefiere el estilo Scheme: lo que un programador de Scheme expresaría con recursión de cola, un usuario CL normalmente lo expresaría con una expresión iterativa en do, dolist, loopo (más recientemente) con el iteratepaquete.

Implementaciones

Consulte la categoría Implementaciones de Common Lisp .

Common Lisp se define mediante una especificación (como Ada y C ) en lugar de una implementación (como Perl ). Existen muchas implementaciones y el estándar detalla áreas en las que pueden diferir válidamente.

Además, las implementaciones tienden a venir con extensiones, que proporcionan funcionalidad no cubierta en el estándar:

  • Nivel superior interactivo (REPL)
  • Recolección de basura
  • Depurador, Stepper e Inspector
  • Estructuras de datos débiles (tablas hash)
  • Secuencias extensibles
  • LOOP extensible
  • Acceso al entorno
  • Protocolo de metaobjetos CLOS
  • Flujos extensibles basados ​​en CLOS
  • Sistema de condiciones basado en CLOS
  • Flujos de red
  • CLOS persistente
  • Compatibilidad con Unicode
  • Interfaz en idioma extranjero (a menudo en C)
  • Interfaz del sistema operativo
  • Interfaz Java
  • Subprocesos y multiprocesamiento
  • Entrega de aplicaciones (aplicaciones, bibliotecas dinámicas)
  • Guardado de imágenes

Se han creado bibliotecas de software libre y de código abierto para soportar extensiones de Common Lisp de manera portable, y se encuentran principalmente en los repositorios de los proyectos Common-Lisp.net [20] y CLOCC (Common Lisp Open Code Collection) [21] .

Las implementaciones de Common Lisp pueden usar cualquier combinación de compilación de código nativo, compilación de código de bytes o interpretación. Common Lisp ha sido diseñado para soportar compiladores incrementales , compiladores de archivos y compiladores de bloques. Las declaraciones estándar para optimizar la compilación (como la inserción de funciones en línea o la especialización de tipos) se proponen en la especificación del lenguaje. La mayoría de las implementaciones de Common Lisp compilan el código fuente a código de máquina nativo . Algunas implementaciones pueden crear aplicaciones independientes (optimizadas). Otras compilan a código de bytes interpretado , que es menos eficiente que el código nativo, pero facilita la portabilidad del código binario. Algunos compiladores compilan el código de Common Lisp a código C. La idea errónea de que Lisp es un lenguaje puramente interpretado es más probable porque los entornos Lisp proporcionan un mensaje interactivo y ese código se compila uno por uno, de forma incremental. Con Common Lisp, la compilación incremental se usa ampliamente.

Algunas implementaciones basadas en Unix ( CLISP , SBCL ) se pueden utilizar como lenguaje de script , es decir, el sistema las puede invocar de forma transparente, de la misma forma que lo hace un intérprete de shell de Perl o Unix . [22]

Lista de implementaciones

Implementaciones comerciales

Allegro Ceceo común
Para Microsoft Windows, FreeBSD, Linux, Apple macOS y varias variantes de UNIX. Allegro CL ofrece un entorno de desarrollo integrado (IDE) (para Windows y Linux) y amplias capacidades para la distribución de aplicaciones.
Lisp común líquido
Anteriormente se llamaba Lucid Common Lisp. Solo mantenimiento, no hay nuevas versiones.
LispWorks
Para Microsoft Windows, FreeBSD, Linux, Apple macOS, iOS, Android y varias variantes de UNIX. LispWorks ofrece un entorno de desarrollo integrado (IDE) (disponible para la mayoría de las plataformas, pero no para iOS y Android) y amplias capacidades para la distribución de aplicaciones.
moclobem
para iOS, Android y macOS.
Abrir géneros
para DEC Alpha.
Ciencia Common Lisp
que está diseñado para la computación científica de alto rendimiento.

Implementaciones libremente redistribuibles

Oso armado con ceceo común (ABCL)
Una implementación de CL que se ejecuta en la máquina virtual Java . [23] Incluye un compilador de código de bytes de Java y permite el acceso a bibliotecas de Java desde CL. Anteriormente era solo un componente del editor J de Armed Bear.
Corchete
Una implementación basada en LLVM que interopera sin problemas con bibliotecas C++. Se ejecuta en varios sistemas Unix y similares (incluido macOS ).
CLIP
Una implementación de compilación de código de bytes, portátil y que se ejecuta en varios sistemas Unix y similares a Unix (incluido macOS ), así como en Microsoft Windows y varios otros sistemas.
Clozure CL (CCL)
Originalmente era una bifurcación libre y de código abierto de Macintosh Common Lisp. Como lo indica la historia, CCL fue escrito para Macintosh, pero Clozure CL ahora se ejecuta en macOS , FreeBSD , Linux , Solaris y Windows . Se admiten puertos x86 de 32 y 64 bits en cada plataforma. Además, hay puertos Power PC para Mac OS y Linux. CCL se conocía anteriormente como OpenMCL, pero ese nombre ya no se usa para evitar confusiones con la versión de código abierto de Macintosh Common Lisp.
CMUCL
Originalmente creado por la Universidad Carnegie Mellon , ahora mantenido como software libre y de código abierto por un grupo de voluntarios. CMUCL utiliza un compilador de código nativo rápido. Está disponible en Linux y BSD para Intel x86; Linux para Alpha; macOS para Intel x86 y PowerPC; y Solaris, IRIX y HP-UX en sus plataformas nativas.
Corman Ceceo común
Para Microsoft Windows. En enero de 2015 se publicó Corman Lisp bajo licencia MIT. [24]
Common Lisp integrable (ECL)
ECL incluye un intérprete de bytecode y un compilador. También puede compilar código Lisp a código de máquina mediante un compilador de C. A continuación, ECL compila el código Lisp a C, compila el código C con un compilador de C y, a continuación, puede cargar el código de máquina resultante. También es posible incorporar ECL en programas C y código C en programas Common Lisp.
GNU Common Lisp (GCL)
El compilador Lisp del Proyecto GNU . Aunque aún no es totalmente compatible con ANSI, GCL es sin embargo la implementación preferida para varios proyectos grandes, incluidas las herramientas matemáticas Maxima , AXIOM y (históricamente) ACL2 . GCL se ejecuta en Linux bajo once arquitecturas diferentes, y también en Windows, Solaris y FreeBSD .
Lisp común de Macintosh (MCL)
La versión 5.2 para ordenadores Apple Macintosh con procesador PowerPC que ejecuten Mac OS X es de código abierto. RMCL (basado en MCL 5.2) se ejecuta en ordenadores Apple Macintosh con procesador Intel que utilizan el traductor binario Rosetta de Apple.
Lenguaje de programación Common Lisp (MKCL) de ManKai
Una rama de ECL . MKCL enfatiza la confiabilidad, la estabilidad y la calidad general del código a través de un sistema de ejecución multiproceso nativo y altamente rediseñado. En Linux, MKCL cuenta con un sistema de ejecución totalmente compatible con POSIX.
Movimentación
Implementa un entorno Lisp para computadoras x86 sin depender de ningún sistema operativo subyacente.
Poplog
Poplog implementa una versión de CL, con POP-11 y, opcionalmente, Prolog y Standard ML (SML), lo que permite la programación en lenguajes mixtos. Para todos, el lenguaje de implementación es POP-11, que se compila de forma incremental. También tiene un editor integrado similar a Emacs que se comunica con el compilador.
Banco de acero Common Lisp (SBCL)
Una rama de CMUCL . "En términos generales, SBCL se distingue de CMU CL por un mayor énfasis en la mantenibilidad". [25] SBCL se ejecuta en las plataformas que CMUCL, excepto HP/UX; además, se ejecuta en Linux para AMD64, PowerPC, SPARC, MIPS, Windows x86 y AMD64. [26] SBCL no utiliza un intérprete de forma predeterminada; todas las expresiones se compilan en código nativo a menos que el usuario active el intérprete. El compilador SBCL genera código nativo rápido de acuerdo con una versión anterior de The Computer Language Benchmarks Game . [27]
Lisp común de Ufasoft
Puerto de CLISP para la plataforma Windows con núcleo escrito en C++.

Otras implementaciones

Austin Kioto Lisp común
Una evolución de Kyoto Common Lisp por Bill Schelter
Mariposa ceceo común
una implementación escrita en Scheme para la computadora multiprocesador BBN Butterfly [28] [29]
CLIC
Un compilador de Common Lisp a C [30]
CLOÉ
Common Lisp para PC de Symbolics
Codemist Lisp común
utilizado para la versión comercial del sistema de álgebra computacional Axiom [31] [32]
Experto en Lisp común
Una implementación temprana para Apple Macintosh por ExperTelligence
Ceceo común dorado
Una implementación para PC de GoldHill Inc. [33] [34]
Ibuki Ceceo común
una versión comercializada de Kyoto Common Lisp
Lisp común de Kioto
el primer compilador Common Lisp que utilizó C como lenguaje de destino. GCL, ECL y MKCL se originaron a partir de esta implementación de Common Lisp.
yo
Una versión pequeña de Common Lisp para sistemas integrados desarrollada por IS Robotics, ahora iRobot [35]
Máquinas Lisp (de Symbolics , TI [36] [37] y Xerox [38] )
Se proporcionaron implementaciones de Common Lisp además de su dialecto nativo de Lisp (Lisp Machine Lisp o Interlisp). CLOS también estaba disponible. Symbolics proporciona una versión mejorada de Common Lisp. [39] [40] [41]
Procyon común lisp
Una implementación para Windows y Mac OS, utilizada por Franz para su puerto Windows de Allegro CL
Zafiro estrellado LISP común
Una implementación para la PC
SubL
una variante de Common Lisp utilizada para la implementación del sistema basado en conocimiento Cyc [42]
Lisp común de nivel superior
Una implementación temprana para ejecución concurrente [43]
CMT
una implementación de biblioteca compartida [44] [45]
VAX Lisp común
Implementación de Digital Equipment Corporation que se ejecutó en sistemas VAX que ejecutaban VMS o ULTRIX
XLIP
una implementación escrita por David Betz [46]

Aplicaciones

Common Lisp se utiliza para desarrollar aplicaciones de investigación (a menudo en Inteligencia Artificial ), para el desarrollo rápido de prototipos o para aplicaciones implementadas.

Common Lisp se utiliza en muchas aplicaciones comerciales, incluido el sitio de comercio web Yahoo! Store, que originalmente involucró a Paul Graham y luego fue reescrito en C++ y Perl . [47] Otros ejemplos notables incluyen:

También existen aplicaciones de código abierto escritas en Common Lisp, como:

Véase también

Referencias

  1. ^ "Acción de las normas ANSI - 28 de diciembre de 2018" (PDF) . ansi.org . Archivado (PDF) del original el 12 de abril de 2021.
  2. ^ Citado de la portada de la norma citada. ANSI INCITS 226-1994 [S2008], a la venta en la página del documento de la norma Archivado el 27 de septiembre de 2020 en Wayback Machine .
  3. ^ "CLHS: Acerca de Common Lisp HyperSpec (TM)". lispworks.com .
  4. ^ "CLHS: Sección 1.1.2". lispworks.com .
  5. ^ "Implementaciones de Common Lisp: una encuesta". Archivado desde el original el 21 de abril de 2012. Consultado el 22 de diciembre de 2007 .
  6. ^ "Los programas LISP antiguos todavía funcionan en Common Lisp" . Consultado el 13 de mayo de 2015 .
  7. ^ "Raíces de "Yu-Shiang Lisp", correo de Jon L White, 1982". cmu.edu .
  8. ^ "Índice de correo". cl-su-ai.lisp.se .
  9. ^ Anti-LOOPismo instintivo y otros fenómenos del correo electrónico: patrones orales, escritos y electrónicos en la comunicación mediada por computadora, JoAnne Yates y Wanda J. Orlikowski, 1993 Archivado el 8 de agosto de 2012 en Wayback Machine.
  10. ^ Steele, Guy L. Jr. (15 de agosto de 1982). "Una descripción general de COMMON LISP". Actas del simposio ACM de 1982 sobre LISP y programación funcional - LFP '82 . ACM. págs. 98-107. doi :10.1145/800068.802140. ISBN 9780897910828. Número de identificación del sujeto  14517358.
  11. ^ Reddy, Abhishek (22 de agosto de 2008). "Características de Common Lisp".
  12. ^ "Compatibilidad con Unicode". Wiki de Common Lisp . Consultado el 21 de agosto de 2008 .
  13. ^ Richard P. Gabriel; Kent M. Pitman (junio de 1988). "Cuestiones técnicas de separación en celdas de función y celdas de valor". LISP y computación simbólica . 1 (1): 81–101. doi :10.1007/bf01806178. S2CID  26716515.
  14. ^ "Hiperespecificación de Common Lisp: Sección 3.1.7".
  15. ^ "Hiperespecificación Common Lisp: Función FLOOR".
  16. ^ "Hiperespecificación Common Lisp: Accesor GETHASH".
  17. ^ "Deja pasar a Lambda". letoverlambda.com .
  18. ^ Peter Seibel (7 de abril de 2005). Practical Common Lisp. Apress. ISBN 978-1-59059-239-7.
  19. ^ "Patrones de diseño en programación dinámica". norvig.com .
  20. ^ "Lisp común.net".
  21. ^ "Colección de código abierto Common Lisp".
  22. ^ "32.6. Inicio rápido de la entrega con CLISP". clisp.cons.org .
  23. ^ "Oso armado ceceo común".
  24. ^ "Las fuentes de Corman Lisp ya están disponibles". 5 de enero de 2015.
  25. ^ "Historia y derechos de autor". Steel Bank Common Lisp .
  26. ^ "Mesa de plataforma". Steel Bank Common Lisp .
  27. ^ "¿Cuáles son los programas más rápidos? – Juego de evaluación comparativa de lenguajes informáticos". 20 de mayo de 2013. Archivado desde el original el 20 de mayo de 2013.
  28. ^ "Paquete: lang/lisp/impl/bbn/". cs.cmu.edu .
  29. ^ "Recent Developments in Butterfly Lisp, 1987, AAAI Proceedings" (PDF) . aaai.org . Archivado (PDF) del original el 11 de octubre de 2015.
  30. ^ Burkart, O.; Goerigk, W.; Knutzen, H. (22 de junio de 1992). "CLICC: Un nuevo enfoque para la compilación de programas Common Lisp en C". CiteSeerX 10.1.1.38.1282 .  {{cite journal}}: Requiere citar revista |journal=( ayuda )
  31. ^ "codemist.co.uk". lisp.codemist.co.uk .
  32. ^ "Axioma, el horizonte de 30 años, página 43" (PDF) .
  33. ^ "Desarrollador de Golden Common Lisp". goldhill-inc.com .
  34. ^ Golden Common LISP: un enfoque práctico, David J. Steele, junio de 2000, por Addison Wesley Publishing Company
  35. ^ Brooks, Rodney A.; al., et (22 de junio de 1995). "L – Un Lisp común para sistemas integrados". CiteSeerX 10.1.1.2.1953 .  {{cite journal}}: Requiere citar revista |journal=( ayuda )
  36. ^ "Conceptos de programación de TI Explorer" (PDF) .
  37. ^ "Referencia de TI Explorer Lisp" (PDF) .
  38. ^ "Notas de la versión de Medley Lisp" (PDF) .
  39. ^ "Diccionario de símbolos de Common Lisp" (PDF) . trailing-edge.com . Archivado (PDF) del original el 22 de abril de 2015.
  40. ^ "Conceptos simbólicos del lenguaje Common Lisp" (PDF) . trailing-edge.com . Archivado (PDF) del original el 22 de abril de 2015.
  41. ^ "Constructos simbólicos de programación en Common Lisp" (PDF) . trailing-edge.com . Archivado (PDF) del original el 22 de abril de 2015.
  42. ^ "Referencia SubL – Cycorp". cyc.com .
  43. ^ "Top Level Inc. – Grupo de preservación de software". softwarepreservation.org .
  44. ^ WCL: Cómo ofrecer aplicaciones Common Lisp eficientes en Unix, Actas de la conferencia ACM de 1992 sobre LISP y programación funcional, páginas 260-269
  45. ^ "commonlisp.net::WCL". pgc.com . Archivado desde el original el 5 de abril de 2016 . Consultado el 25 de marzo de 2016 .
  46. ^ "Paquete: lang/lisp/impl/xlisp/". cs.cmu.edu .
  47. ^ "Superando los promedios". paulgraham.com .
  48. ^ "Asistente del autor" (PDF) . aaai.org . Archivado (PDF) del original el 4 de junio de 2011.
  49. ^ Asistente del autorizador de American Express Archivado el 12 de diciembre de 2009 en Wayback Machine.
  50. ^ Desarrollo de aplicaciones en tiempo real Archivado el 2 de agosto de 2016 en Wayback Machine . Gensym. Consultado el 16 de agosto de 2016.
  51. ^ "Genworks GDL".
  52. ^ "Opusmodus – Inicio".
  53. ^ PWGL – Inicio Archivado el 3 de mayo de 2011 en Wayback Machine , consultado el 17 de julio de 2013.
  54. ^ ab "Aeroespacial – Common Lisp". lisp-lang.org .
  55. ^ "Usuarios de piano, recuperado de la página del fabricante".
  56. ^ "Grammarly.com, Ejecución de Lisp en producción". 26 de junio de 2015.
  57. ^ "Agente remoto". ti.arc.nasa.gov .
  58. ^ "Ceceo en el JPL".
  59. ^ "Aplicaciones para clientes de Franz Inc: NASA". franz.com .
  60. ^ Sistema de planificación y programación de Spike. Stsci.edu. Consultado el 17 de julio de 2013.
  61. ^ "Aplicaciones para clientes de Franz Inc: Instituto del Telescopio Espacial". franz.com .
  62. ^ "Cómo empezó todo... o sea, el nacimiento del CLR". microsoft.com . 28 de agosto de 2023.
  63. ^ Huffman, Steve. "on lisp". Votado a favor . Archivado desde el original el 17 de mayo de 2018. Consultado el 11 de mayo de 2019 .
  64. ^ "Cargador de páginas".
  65. ^ "¿Por qué pgloader es mucho más rápido?". 14 de mayo de 2014.

Bibliografía

Una lista cronológica de libros publicados (o a punto de publicarse) sobre Common Lisp (el lenguaje) o sobre programación con Common Lisp (especialmente programación de IA).

  • Guy L. Steele : Common Lisp, el lenguaje, 1.ª edición , Digital Press, 1984, ISBN 0-932376-41-X 
  • Rodney Allen Brooks : Programación en Common Lisp , John Wiley and Sons Inc, 1985, ISBN 0-471-81888-7 
  • Richard P. Gabriel : Rendimiento y evaluación de sistemas Lisp , The MIT Press, 1985, ISBN 0-262-57193-5 , PDF 
  • Robert Wilensky : Common LISPcraft , WW Norton & Co., 1986, ISBN 0-393-95544-3 
  • Eugene Charniak , Christopher K. Riesbeck, Drew V. McDermott, James R. Meehan: Programación de inteligencia artificial, 2.ª edición , Lawrence Erlbaum, 1987, ISBN 0-89859-609-2 
  • Wendy L. Milner: Common Lisp: un tutorial , Prentice Hall, 1987, ISBN 0-13-152844-0 
  • Deborah G. Tatar: Guía del programador para Common Lisp , Longman Higher Education, 1987, ISBN 0-13-728940-5 
  • Taiichi Yuasa, Masami Hagiya: Introducción a Common Lisp , Elsevier Ltd, 1987, ISBN 0-12-774860-1 
  • Christian Queinnec, Jerome Chailloux: Evolución y estandarización de Lisp , Ios Pr Inc., 1988, ISBN 90-5199-008-1 
  • Taiichi Yuasa, Richard Weyhrauch, Yasuko Kitajima: Ejercicios de Common Lisp , Academic Press Inc, 1988, ISBN 0-12-774861-X 
  • Wade L. Hennessey: Common Lisp , McGraw-Hill Inc., 1989, ISBN 0-07-028177-7 
  • Tony Hasemer, John Dominque: Programación Common Lisp para inteligencia artificial , Addison-Wesley Educational Publishers Inc, 1989, ISBN 0-201-17579-7 
  • Sonya E. Keene: Programación orientada a objetos en Common Lisp: Guía del programador para CLOS , Addison-Wesley, 1989, ISBN 0-201-17589-4 
  • David Jay Steele: Golden Common Lisp: un enfoque práctico , Addison Wesley, 1989, ISBN 0-201-41653-0 
  • David S. Touretzky : Common Lisp: una introducción sencilla a la computación simbólica , Benjamin-Cummings, 1989, ISBN 0-8053-0492-4 . Reimpresión de Dover en formato Web/PDF (2013) ISBN 978-0486498201  
  • Christopher K. Riesbeck, Roger C. Schank : Dentro del razonamiento basado en casos , Lawrence Erlbaum, 1989, ISBN 0-89859-767-6 
  • Patrick Winston , Berthold Horn : Lisp, 3.ª edición , Addison-Wesley, 1989, ISBN 0-201-08319-1 , Web 
  • Gerard Gazdar, Chris Mellish: Procesamiento del lenguaje natural en LISP: una introducción a la lingüística computacional , Addison-Wesley Longman Publishing Co., 1990, ISBN 0-201-17825-7 
  • Patrick R. Harrison: Common Lisp e inteligencia artificial , Prentice Hall PTR, 1990, ISBN 0-13-155243-0 
  • Timothy Koschmann: El compañero de Common Lisp , John Wiley & Sons, 1990, ISBN 0-471-50308-8 
  • W. Richard Stark: LISP, tradición y lógica , Springer Verlag New York Inc., 1990, ISBN 978-0-387-97072-1 , PDF 
  • Molly M. Miller, Eric Benson: Lisp Style & Design , Digital Press, 1990, ISBN 1-55558-044-0 
  • Guy L. Steele : Common Lisp the Language , 2.ª edición , Digital Press, 1990, ISBN 1-55558-041-6 , Web 
  • Robin Jones, Clive Maynard, Ian Stewart: El arte de la programación Lisp , Springer Verlag New York Inc., 1990, ISBN 978-3-540-19568-9 , PDF 
  • Steven L. Tanimoto: Los elementos de la inteligencia artificial utilizando Common Lisp , Computer Science Press, 1990, ISBN 0-7167-8230-8 
  • Peter Lee : Temas de implementación avanzada de lenguajes , The MIT Press, 1991, ISBN 0-262-12151-4 
  • John H. Riley : Un libro de ejercicios de Common Lisp , Prentice Hall, 1991, ISBN 0-13-155797-1 
  • Peter Norvig : Paradigmas de programación de inteligencia artificial: estudios de casos en Common Lisp , Morgan Kaufmann, 1991, ISBN 1-55860-191-0 , Web 
  • Gregor Kiczales , Jim des Rivieres, Daniel G. Bobrow : El arte del protocolo de metaobjetos , The MIT Press, 1991, ISBN 0-262-61074-4 
  • Jo A. Lawless, Molly M. Miller: Entendiendo CLOS: El sistema de objetos Common Lisp , Digital Press, 1991, ISBN 0-13-717232-X 
  • Mark Watson: Módulos Common Lisp: Inteligencia artificial en la era de las redes neuronales y la teoría del caos , Springer Verlag New York Inc., 1991, ISBN 0-387-97614-0 , PDF 
  • James L. Noyes: Inteligencia artificial con Common Lisp: fundamentos del procesamiento simbólico y numérico , Jones & Bartlett Pub, 1992, ISBN 0-669-19473-5 
  • Stuart C. Shapiro: COMMON LISP: un enfoque interactivo , Computer Science Press, 1992, ISBN 0-7167-8218-9 , Web/PDF 
  • Kenneth D. Forbus , Johan de Kleer : Creando solucionadores de problemas , The MIT Press, 1993, ISBN 0-262-06157-0 
  • Andreas Paepcke: Programación orientada a objetos: la perspectiva CLOS , The MIT Press, 1993, ISBN 0-262-16136-2 
  • Paul Graham : On Lisp , Prentice Hall, 1993, ISBN 0-13-030552-9 , Web/PDF 
  • Paul Graham : ANSI Common Lisp , Prentice Hall, 1995, ISBN 0-13-370875-6 
  • Otto Mayer: Programmieren in Common Lisp , alemán, Spektrum Akademischer Verlag, 1995, ISBN 3-86025-710-2 
  • Stephen Slade : Common Lisp orientado a objetos , Prentice Hall, 1997, ISBN 0-13-605940-6 
  • Richard P. Gabriel : Patrones de software: relatos de la comunidad del software , Oxford University Press, 1998, ISBN 0-19-512123-6 , PDF 
  • Taiichi Yuasa, Hiroshi G. Okuno: Tecnología Lisp avanzada , CRC, 2002, ISBN 0-415-29819-9 
  • David B. Lamkins: Lisp exitoso: cómo entender y usar Common Lisp , bookfix.com, 2004. ISBN 3-937526-00-5 , Web 
  • Peter Seibel: Common Lisp práctico , Apress, 2005. ISBN 1-59059-239-5 , Web 
  • Doug Hoyte: Let Over Lambda , Lulu.com, 2008, ISBN 1-4357-1275-7 , Web 
  • George F. Luger, William A. Stubblefield: Algoritmos de IA, estructuras de datos y expresiones idiomáticas en Prolog, Lisp y Java , Addison Wesley, 2008, ISBN 0-13-607047-7 , PDF 
  • Conrad Barski: Land of Lisp: ¡Aprenda a programar en Lisp, un juego a la vez! , No Starch Press, 2010, ISBN 1-59327-200-6 , Web 
  • Pavel Penev: Cuentos web de Lisp , Leanpub, 2013, Web
  • Edmund Weitz: Recetas de Common Lisp , Apress, 2015, ISBN 978-1-484211-77-9 , Web 
  • Patrick M. Krusenotto: Funktionale Programmierung und Metaprogrammierung, Interaktiv in Common Lisp , Springer Fachmedien Wiesbaden 2016, ISBN 978-3-658-13743-4 , Web 
  • Quicklisp: un administrador de bibliotecas muy popular y de alta calidad para Common Lisp
  • La lista Awesome CL, una lista seleccionada de bibliotecas y marcos de Common Lisp.
  • El libro de recetas de Common Lisp, un proyecto colaborativo.
  • The CLiki, a Wiki for free and open-source Common Lisp systems running on Unix-like systems.
  • One of the main repositories for free Common Lisp for software is Common-Lisp.net Archived September 27, 2009, at the Wayback Machine.
  • lisp-lang.org has documentation and a showcase of success stories.
  • An overview of the history of Common Lisp: "History". Common Lisp HyperSpec.
  • Common Lisp Quick Reference – a compact overview of the Common Lisp standard language.
  • Planet Lisp Articles about Common Lisp.
  • Quickdocs summarizes documentation and dependency information for many Quicklisp projects.
Retrieved from "https://en.wikipedia.org/w/index.php?title=Common_Lisp&oldid=1236270901"