Articulo de referencia

Lisp 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) del Instituto Nacional Estadounidense de Es...

Common Lisp ( CL ) es un dialecto del lenguaje de programación Lisp , publicado en el documento estándar ANSI INCITS 226-1994 (S2018) del Instituto Nacional Estadounidense de Estándares (ANSI) [ 1 ] (anteriormente X3.226-1994 (R1999) ). [ 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 se desarrolló como un sucesor estandarizado y mejorado de Maclisp . A principios de la década de 1980, varios grupos ya trabajaban en diversos sucesores de MacLisp: Lisp Machine Lisp (también conocido como ZetaLisp), Spice Lisp , NIL y S-1 Lisp . Common Lisp buscaba unificar, estandarizar y extender las características de estos dialectos de MacLisp. Common Lisp no es una implementación, sino una especificación del lenguaje . [ 4 ] Existen varias implementaciones del estándar Common Lisp, incluyendo software libre y de código abierto, así como productos propietarios. [ 5 ] Common Lisp es un lenguaje de programación de propósito general y multiparadigma . 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 de tiempo de ejecución eficientes. Este desarrollo incremental a menudo se realiza de forma interactiva sin interrumpir la aplicación en ejecución.

También admite anotaciones de tipo y conversiones de tipo opcionales, que se pueden agregar según sea necesario en las etapas posteriores de análisis y optimización, para permitir que el compilador genere código más eficiente. Por ejemplo, fixnumpuede almacenar un entero sin empaquetar 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 puede indicar al compilador, módulo por módulo o función 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últiples métodos y combinaciones de métodos. A menudo se implementa con un protocolo de metaobjetos .

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

Common Lisp ofrece compatibilidad parcial con versiones anteriores de Maclisp y el Lisp original de John McCarthy . Esto permite portar software Lisp antiguo a Common Lisp. [ 6 ]

Historia

El trabajo en Common Lisp comenzó en 1981 después de una iniciativa del gerente de ARPA, Bob Engelmore, para desarrollar un dialecto Lisp estándar único de la comunidad. [ 7 ] Gran parte del diseño inicial del lenguaje se realizó por correo electrónico. [ 8 ] [ 9 ] En 1982, Guy L. Steele Jr. dio 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, Condition System para el manejo de errores, una interfaz para el formateador de código 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 (ejemplos son Unicode, Concurrency, E/S basada en CLOS) han sido proporcionadas por implementaciones y bibliotecas .

Sintaxis

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

( + 2 2 ) ; suma 2 y 2, dando 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 asignarle un valor. Los asteriscos forman parte de ; el nombre, que por convención denota una variable especial (global). ; El símbolo *x* también adquiere la propiedad de que ; sus asignaciones posteriores son dinámicas, en lugar de léxicas. ( setf *x* 42.1 ) ; Establece la variable *x* al valor de punto flotante 42.1
;; Define una función que eleva un número al cuadrado: ( defun square ( x ) ( * x x ))
;; Ejecutar la función: ( cuadrado 3 ) ; Devuelve 9
;; La construcción 'let' crea un ámbito para variables locales. Aquí ;; la variable 'a' está vinculada a 6 y la variable 'b' está vinculada ;; 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, por 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 enteros , razones , números de coma 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 razón representa fracciones con exactitud, una funcionalidad 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 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 prácticamente desconocido fuera de ellos. Un símbolo es un objeto de datos único y con nombre, compuesto por varias partes: nombre, valor, función, lista de propiedades y paquete. De estas, la celda de valor y la celda de función son las más importantes. En Lisp, los símbolos se utilizan a menudo de forma similar a los identificadores en otros lenguajes: para almacenar el valor de una variable; sin embargo, tienen 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 del paquete de palabras clave se autoevalúan. Los valores booleanos en Common Lisp se representan mediante los símbolos autoevaluables T y NIL. Common Lisp dispone de espacios de nombres para los símbolos, denominados «paquetes».

Existen varias funciones para redondear valores numéricos escalares de diversas maneras. La función roundredondea el argumento al entero más cercano, y los casos intermedios se redondean al entero par. Las funciones truncate, floor, y 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)produce −3, 0.5; (ceiling -2.5)produce −2, −0.5; (round 2.5)produce 2, 0.5; y (round 3.5)produce 4, −0.5.

Estructuras de datos

En Common Lisp, los tipos de secuencia incluyen listas, vectores, vectores de bits y cadenas. Existen numerosas operaciones que pueden aplicarse a 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 llamados 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 generalmente 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 usar para matemáticas de matrices. Un vector es una matriz unidimensional. Las matrices pueden contener 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 un tipo. Dos tipos de matrices especializadas en un tipo 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 usarse como clave o valor. Las tablas hash se redimensionan automáticamente según sea necesario.

Los paquetes son conjuntos 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, marcándolos como parte de una interfaz pública. Los paquetes pueden utilizar otros paquetes.

Las estructuras , similares en su uso a las estructuras de C y los registros de Pascal , representan estructuras de datos complejas arbitrarias con cualquier número y tipo de campos (llamados ranuras ). Las estructuras permiten la herencia simple.

Las clases son similares a las estructuras, pero ofrecen características más dinámicas y herencia múltiple (véase CLOS ). Las clases se añadieron recientemente 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 a la vez funciones e instancias.

Funciones

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

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

;; Ordena la lista usando las funciones > y < como operadores relacionales. ( 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...), presume que el símbolo llamado f es uno de los siguientes:

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

Si fes el nombre de una función, entonces los argumentos a1, a2, ..., anse evalúan de izquierda a derecha, y la función se encuentra y se invoca con esos valores proporcionados 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 el cuerpo de la función:

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

Las definiciones de funciones pueden incluir directivas del compilador , conocidas como declaraciones , que proporcionan sugerencias al compilador sobre la configuración 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 número de punto flotante simple x." ( declare ( single-float x ) ( optimize ( speed 3 ) ( debug 0 ) ( safety 1 ))) ( the single-float ( * x x )))

Las funciones anónimas ( literales de función ) se definen mediante lambdaexpresiones, por ejemplo, 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 cuales resulta útil proporcionar funciones anónimas como argumentos.(lambda (x) (* x x))

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 `compil`. (Algunos sistemas Lisp ejecutan las funciones mediante un intérprete por defecto, a menos que se indique lo contrario; 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 sobre clases estándar de CLOS , clases del sistema , clases de estructura u objetos individuales. Para muchos tipos, existen clases del sistema correspondientes .

Cuando se llama a una función genérica, el despacho múltiple determinará el método efectivo que se debe utilizar.

( defgeneric agregar ( a b ))
( defmethod add (( a number ) ( b number )) ( + 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 (( a string ) ( b string )) ( concatenate 'string a b ))
( add 2 3 ) ; devuelve 5 ( add #( 1 2 3 4 ) 7 ) ; devuelve #(8 9 10 11) ( add #( 1 2 3 4 ) #( 4 3 2 1 )) ; devuelve #(5 5 5 5) ( add "COMMON " "LISP" ) ; devuelve "COMMON LISP"

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

El espacio de nombres de la función

Una diferencia clave entre Common Lisp y Scheme es que el espacio de nombres de Common Lisp para nombres de funciones está separado de su espacio de nombres para variables de datos. Para Common Lisp, los operadores que definen nombres en el espacio de nombres de funciones incluyen defun, flet, labels, defmethody defgeneric.

Esto sigue el patrón establecido por Lisp 1.5 de John McCarthy , que primero separó las variables y las funciones en sus propios espacios de nombres; el lenguaje Lisp original de John McCarthy tenía un único espacio de nombres para ambos. [ 13 ]

Para pasar una función de Common Lisp por su nombre como argumento a otra función, se debe usar 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 funciones, con el código . Por el contrario, para llamar a una función pasada de esta manera, se usaría el operador sobre el argumento.#'>funcall

El modelo de evaluación de Scheme es más sencillo: solo existe 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 programadores con más experiencia en el otro. Por ejemplo, a muchos programadores de Common Lisp les gusta usar nombres de variables descriptivos como `list` o `string` , lo que podría causar problemas en Scheme, ya que ocultarían localmente los nombres de las funciones.

La conveniencia de un espacio de nombres separado para las funciones es un tema controvertido en la comunidad Lisp. Generalmente se le conoce como el debate Lisp-1 vs. Lisp-2 . Lisp-1 se refiere al modelo de Scheme y Lisp-2 al de Common Lisp. Estos nombres fueron acuñados en un artículo de 1988 de Richard P. Gabriel y Kent Pitman , que compara exhaustivamente ambos enfoques. [ 13 ]

Múltiples valores de retorno

Common Lisp admite el concepto de valores múltiples , [ 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 totalmente opcionales y se pasan a través de un canal lateral dedicado. Esto significa que los llamadores pueden permanecer completamente ajenos a la existencia de los valores secundarios si no los necesitan, y hace 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 cercano a cero. Sin embargo, también devuelve un resto como valor secundario, lo que facilita enormemente determinar qué valor se truncó. Además, admite un parámetro divisor opcional, que permite realizar la división euclidiana de forma trivial:
( let (( x 1266778 ) ( y 458 )) ( multiple-value-bind ( quotient remainder ) ( truncate x y ) ( format nil "~A dividido por ~A es ~A resto ~A" x y quotient remainder )));;;; => "1266778 dividido por 458 es 2765 con resto 408"
  • GETHASH[ 16 ] devuelve el valor de una clave en unmapa asociativo, o el valor predeterminado en caso contrario, y un valor booleano secundario que indica si se encontró el valor. Por lo tanto, el código que no necesita saber si se encontró el valor o se proporcionó como predeterminado puede usarlo tal cual, pero cuando dicha distinción es importante, puede inspeccionar el valor booleano secundario y reaccionar adecuadamente. 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 connull, como se haría en otros lenguajes.
( defun obtener-respuesta ( biblioteca ) ( gethash 'respuesta biblioteca 42 ))( defun the-answer-1 ( library ) ( format nil "La respuesta es ~A" ( get-answer library ))) ;;;; Devuelve "La respuesta es 42" si ANSWER no está presente en LIBRARY( defun the-answer-2 ( library ) ( multiple-value-bind ( answer sure-p ) ( get-answer library ) ( if ( not sure-p ) "No lo sé" ( format nil "La respuesta es ~A" answer )))) ;;;; Devuelve "No lo sé" si ANSWER no está presente en LIBRARY

Se admiten múltiples valores mediante un puñado de formatos estándar, los más comunes de los cuales son el MULTIPLE-VALUE-BINDformato especial para acceder a valores secundarios y VALUESpara devolver múltiples valores:

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

Otros tipos

Otros tipos de datos en Common Lisp incluyen:

  • Las rutas de archivo representan archivos y directorios en el sistema de archivos . La funcionalidad de rutas de archivo de Common Lisp es más general que las convenciones de nomenclatura de archivos de la mayoría de los sistemas operativos, lo que hace que el acceso de los programas Lisp a los archivos sea ampliamente portable en diversos sistemas.
  • Los flujos de entrada y salida representan fuentes y destinos de datos binarios o textuales, como la terminal o los archivos abiertos.
  • Common Lisp cuenta con un generador de números pseudoaleatorios (PRNG) incorporado . 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 de dato que se utiliza para representar errores, excepciones y otros eventos "interesantes" a los que un programa puede responder.
  • Las clases son objetos de primera clase y, a su vez, son instancias de clases llamadas clases de metaobjetos ( o 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 al leer el código, el programador puede modificar o ampliar la sintaxis del lenguaje.

Alcance

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

La asociación entre un nombre y la entidad a la que se refiere dicho nombre se denomina vínculo.

El alcance se refiere al conjunto de circunstancias en las que se determina que un nombre tiene una vinculación 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, una macro o una función; de lo contrario, se refiere a una variable o a otra cosa.
  • el tipo de expresión en la que se produce 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 tagbody están en un espacio de nombres separado de los nombres de las variables. Una forma especial o forma macro tiene control total sobre los significados de todos los símbolos en su sintaxis. Por ejemplo, en (defclass x (a b) ()), una definición de clase, (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 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á encerrada 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 a una variable, se determina si un símbolo de variable ha sido declarado especial, ya sea local o globalmente. Esto define si la referencia se resuelve en un entorno léxico o en 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 hilos, pueden existir múltiples activaciones de la misma función simultáneamente. Estas activaciones comparten el mismo código del programa, pero cada una tiene su propia instancia de entorno léxico.

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

Tipos de ambiente

Global

En Lisp, algunos entornos son de alcance global. Por ejemplo, si se define un nuevo tipo, este se conoce en todas partes a partir de ese momento. Las referencias a ese tipo lo buscan en este entorno global.

Dinámica

En Common Lisp, un tipo de entorno es el entorno dinámico. Las vinculaciones establecidas en este entorno tienen un alcance dinámico, lo que significa que una vinculación se establece al inicio de la ejecución de una construcción, como un letbloque, y desaparece cuando dicha construcción finaliza su ejecución: su tiempo de vida está ligado a la activación y desactivación dinámicas del bloque. Sin embargo, una vinculación dinámica no solo es visible dentro de ese bloque, sino también para todas las funciones invocadas desde él. Este tipo de visibilidad se conoce como alcance indefinido. Se dice que las vinculaciones que presentan un alcance dinámico (tiempo de vida ligado a la activación y desactivación de un bloque) y un alcance indefinido (visibles para todas las funciones que se llaman desde ese bloque) tienen un alcance dinámico.

Common Lisp admite variables de ámbito dinámico, también llamadas variables especiales. Ciertos otros tipos de enlaces también tienen necesariamente un ámbito dinámico, como los reinicios y las etiquetas catch. Los enlaces de funciones no pueden tener un ámbito dinámico usando flet(que solo proporciona enlaces de funciones con ámbito léxico), pero los objetos de función (un objeto de primer nivel en Common Lisp) se pueden asignar a variables de ámbito dinámico, enlazar usando leten ámbito dinámico y luego llamar usando funcallo APPLY.

El alcance dinámico es extremadamente útil porque aporta claridad referencial y disciplina a las variables globales . En informática, las variables globales son mal vistas como posibles fuentes de error, ya que pueden dar lugar a canales de comunicación ad hoc y encubiertos entre módulos que provocan interacciones no deseadas e inesperadas.

En Common Lisp, una variable especial con una única vinculación de nivel superior se comporta como una variable global en otros lenguajes de programación. Se le puede asignar un nuevo valor, que simplemente reemplaza el de la vinculación de nivel superior. El reemplazo descuidado del valor de una variable global es la causa principal de los errores derivados del uso de variables globales. Sin embargo, otra forma de trabajar con una variable especial es asignarle una nueva vinculación local dentro de una expresión. Esto se conoce a veces como "revincular" la variable. Vincular una variable de ámbito dinámico crea temporalmente una nueva ubicación de memoria para dicha variable y asocia su nombre a esa ubicación. Mientras la vinculación esté activa, todas las referencias a la variable apuntan a la nueva vinculación; la anterior queda oculta. Al finalizar la ejecución de la expresión de vinculación, la ubicación de memoria temporal desaparece y se revela la antigua vinculación, con el valor original intacto. Por supuesto, se pueden anidar múltiples vinculaciones dinámicas para la misma variable.

En las implementaciones de Common Lisp que admiten multihilo, los ámbitos dinámicos son específicos de cada hilo de ejecución. Por lo tanto, las variables especiales sirven como una abstracción para el almacenamiento local de hilos. Si un hilo vuelve a enlazar una variable especial, este cambio no tiene efecto sobre esa variable en otros hilos. El valor almacenado en un enlace solo puede ser recuperado por el hilo que creó ese enlace. Si cada hilo enlaza alguna variable especial *x*, entonces *x*se comporta como almacenamiento local de hilos. Entre los hilos que no vuelven a enlazar *x*, se comporta como una variable global ordinaria: todos estos hilos se refieren al mismo enlace de nivel superior de *x*.

Las variables dinámicas se pueden usar para extender el contexto de ejecución con información contextual 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 debe pasar por capas de código no relacionadas, que simplemente no se pueden extender con parámetros adicionales para pasar los datos adicionales. Una situación como esta generalmente requiere una variable global. Esa variable global debe guardarse y restaurarse para que el esquema no falle bajo recursión: la reasignación de variables dinámicas se encarga de esto. Y esa variable debe ser local al hilo (o bien se debe usar un mutex grande) para que el esquema no falle bajo hilos: las implementaciones de ámbito dinámico también pueden encargarse de esto.

En la biblioteca Common Lisp, existen muchas variables especiales estándar. Por ejemplo, todos los flujos de E/S estándar se almacenan en las vinculaciones 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 () ( format 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" ; salida recopilada devuelta como una cadena

Léxico

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

Las etiquetas en un TAGBODY tienen ámbito léxico. La expresión (GO X) es errónea si no está incrustada en un TAGBODY que contenga una etiqueta X. Sin embargo, las vinculaciones de etiquetas desaparecen cuando el TAGBODY finaliza su ejecución, porque tienen un alcance dinámico. Si ese bloque de código se vuelve a ejecutar 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 la (print "Hola") some-label ( print "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, omitiendo el código (print "Hello"). Dado que end-label está al final de tagbody, tagbody termina, produciendo NIL. Supongamos que ahora se llama a la función previamente almacenada:

( funcall *stashed* ) ;; ¡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 la etiqueta SOME-LABEL ya se ha dejado". La función intentó evaluar (go some-label), que está incrustado léxicamente en el cuerpo de la etiqueta, y se resuelve en la etiqueta. Sin embargo, el cuerpo de la etiqueta no se está ejecutando (su extensión ha terminado), por lo que no se puede realizar la transferencia de control.

En Lisp, las vinculaciones de funciones locales tienen ámbito léxico , y las vinculaciones de variables también lo tienen por defecto. A diferencia de las etiquetas GO, ambas tienen un alcance indefinido. Cuando se establece una vinculación de función o variable léxica, esta persiste mientras sea posible hacer referencia a ella, incluso después de que la construcción que la estableció haya finalizado. Las referencias a variables y funciones léxicas tras la finalización de su construcción de establecimiento son posibles gracias a los cierres léxicos .

El enlace léxico es el modo de enlace predeterminado para las variables de Common Lisp. Para un símbolo individual, se puede cambiar a ámbito dinámico, ya sea mediante una declaración local o 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 pretenden que sean léxicas no se conviertan accidentalmente en especiales.

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

En primer lugar, las referencias a variables y funciones se pueden compilar a código máquina eficiente, ya que 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 que se deben generar cierres completos, el acceso al entorno del cierre sigue siendo eficiente; normalmente, cada variable se convierte en un desplazamiento dentro de un vector de enlaces, por lo que una referencia a una variable se convierte en una simple instrucción de carga o almacenamiento con un modo de direccionamiento 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 como objetos de primera clase, lo cual está en 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 a la X vinculada en A. B simplemente no tiene acceso a X. Para situaciones en las que se desean interacciones disciplinadas a través de una variable, Common Lisp proporciona variables especiales. Las variables especiales permiten que un módulo A establezca una vinculación 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 lo es; por consiguiente, Common Lisp admite tanto el ámbito léxico como el dinámico .

Macros

En Lisp, una macro se asemeja superficialmente a una función en su uso. 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 recibe como argumentos el código fuente que contiene, lo vincula a sus parámetros y calcula una nueva forma de código fuente. Esta nueva forma también puede usar una macro. La expansión de la macro se repite hasta que la nueva forma de código fuente no use ninguna macro. La forma final calculada es el código fuente que se ejecuta en tiempo de ejecución.

Usos típicos de las macros en Lisp:

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

Varias características estándar de Common Lisp también deben implementarse como macros, tales como:

  • la abstracción estándar setf, para permitir expansiones personalizadas en tiempo de compilación de operadores de asignación/acceso
  • with-accessors, with-slots, with-open-filey otras WITHmacros similares
  • Dependiendo de la implementación, ifo condes una macro construida sobre la otra, el operador especial; wheny unlessconsisten en macros
  • El potente looplenguaje específico de dominio

Las macros se definen mediante la macro defmacro . El operador especial macrolet permite definir macros locales (con ámbito léxico). También es posible definir macros para símbolos utilizando 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 análisis sobre macros, afirmando que «las macros son la mayor ventaja de 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 untilestructura de bucle. La sintaxis es:

(hasta el formulario de prueba*) 

La definición macro para until :

( defmacro until ( test &body body ) ( let (( start-tag ( gensym "START" )) ( end-tag ( gensym "END" ))) ` ( tagbody , start-tag ( when , test ( go , end-tag )) ( progn ,@ body ) ( go , start-tag ) , end-tag )))

`tagbody` es un operador especial primitivo de Common Lisp que permite nombrar etiquetas y usar la forma `go` para saltar a ellas. La comilla invertida ` proporciona una notación que ofrece plantillas de código, donde se rellenan los valores de las formas precedidas por una coma. Las formas precedidas por una coma y el signo arroba se insertan mediante la función `splice` . La forma `tagbody` comprueba la condición de fin. Si la condición es verdadera, salta a la etiqueta de fin. De lo contrario, se ejecuta el código del cuerpo proporcionado y luego salta a la etiqueta de inicio.

Un ejemplo del uso de la macro until anterior:

( hasta ( = ( aleatorio 10 ) 0 ) ( escribir-línea "Hola" ))

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

( TAGBODY #:START1136 ( WHEN ( ZEROP ( RANDOM 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 suelen convertirse automáticamente a mayúsculas. La expansión utiliza TAGBODY con dos etiquetas. Los símbolos para estas etiquetas son calculados por GENSYM y no están internos en ningún paquete. Dos formas de Go utilizan estas etiquetas para saltar. 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á. Expandir completamente una forma fuente se llama recorrido de código .

En la forma totalmente expandida ( recorrida ), la forma cuando se reemplaza por la forma primitiva si :

( TAGBODY #:START1136 ( SI ( ZEROP ( ALEATORIO 10 )) ( PROG ( IR #:END1137 )) NULO ) ( PROG ( ESCRIBIR-LÍNEA "hola" )) ( IR #: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 del evaluador o compilador para generar el código fuente final. Las macros se escriben en Common Lisp estándar y pueden usar cualquier operador disponible de Common Lisp (o de terceros).

Captura variable y sombreado

Las macros de Common Lisp permiten lo que comúnmente se denomina captura de variables , donde los símbolos del cuerpo de la macro coinciden con los del contexto de llamada, lo que permite al programador crear macros en las que diversos símbolos tienen un significado especial. El término captura de variables puede resultar algo engañoso, ya que todos los espacios de nombres son vulnerables a la captura no deseada, incluidos los espacios de nombres de operadores y funciones, el espacio de nombres de etiquetas tagbody, la etiqueta catch, el manejador de condiciones y los espacios de nombres de reinicio.

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

  • En primer lugar, una expansión de macro puede crear inadvertidamente una referencia simbólica que el autor de la macro asumió que se resolvería en un espacio de nombres global, pero el código donde se expande la macro proporciona una definición local que oculta dicha referencia. A esto lo denominaremos captura de tipo 1.
  • La segunda forma, la captura de tipo 2, es justo lo contrario: algunos de los argumentos de la macro son fragmentos de código proporcionados por quien la llama, y ​​estos fragmentos están escritos de tal manera que hacen referencia a las vinculaciones circundantes. Sin embargo, la macro inserta estos fragmentos de código en una expansión que define sus propias vinculaciones, las cuales capturan accidentalmente algunas de estas referencias.

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

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

Una estrategia consiste en utilizar gensyms : símbolos únicos garantizados que pueden emplearse en una expansión de macro sin riesgo de captura. El uso de gensyms en la definición de una macro es una tarea manual, pero se pueden escribir macros que simplifiquen su instanciación y uso. Los gensyms resuelven fácilmente la captura de tipo 2, pero no son aplicables de la misma manera a la captura de tipo 1, ya que la expansión de la macro no puede renombrar los símbolos interferentes en el código circundante que capturan sus referencias. Los gensyms podrían utilizarse para proporcionar alias estables para los símbolos globales que necesita la expansión de la macro. Esta expansión utilizaría estos alias secretos en lugar de los nombres conocidos, por lo que la redefinición de estos últimos no tendría ningún efecto negativo en la macro.

Otro enfoque consiste en utilizar paquetes. Una macro definida en su propio paquete puede simplemente usar símbolos internos de ese paquete para su expansión. El uso de paquetes permite gestionar 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. Esto se debe a que el uso de paquetes para resolver problemas de captura se basa en el uso de símbolos privados (símbolos de un paquete que no se importan ni se hacen visibles en otros paquetes). En cambio, los símbolos de la biblioteca de 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:

;; expansión de UNTIL hace un uso liberal de DO ( defmacro until ( expresión &body body ) ` ( do () ( , expresión ) ,@ body ));; macrolet establece la vinculación del operador léxico para DO ( macrolet (( do ( ... ) ... algo más ... )) ( until ( = ( random 10 ) 0 ) ( write-line "Hola" )))

La untilmacro se expandirá a una forma que llama doa la que pretende referirse a la macro estándar de Common Lisp do. Sin embargo, en este contexto, dopuede tener un significado completamente diferente, por lo que untilpuede que no funcione correctamente.

Common Lisp resuelve el problema de la ocultación de operadores y funciones estándar prohibiendo su redefinición. Dado que redefine el operador estándar do, el código anterior es en realidad un fragmento de Common Lisp no conforme, lo que permite a las implementaciones diagnosticarlo y rechazarlo.

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 lo llama. El manejador puede entonces buscar reinicios y usar uno de ellos para reparar automáticamente el problema actual, utilizando 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 gestionados por el código, pueden presentarse a los usuarios (como parte de una interfaz de usuario, por ejemplo, la de un depurador), de modo que el usuario pueda seleccionar e invocar uno de los reinicios disponibles. Dado que el manejador de condiciones se llama en el contexto del error (sin desenrollar la pila), es posible una recuperación completa del error en muchos casos, donde otros sistemas de manejo de excepciones ya habrían terminado la rutina actual. El propio depurador también puede personalizarse o reemplazarse mediante la *debugger-hook*variable dinámica. El código que se encuentre dentro de formas protegidas contra el desenrollado, como los finalizadores, también se ejecutará según corresponda a pesar de la excepción.

En el siguiente ejemplo (usando Symbolics Genera ), el usuario intenta abrir un archivo en una función Lisp llamada desde el REPL (Read-Eval-Print-LOOP ), cuando el archivo no existe. El sistema Lisp presenta cuatro reinicios. El usuario selecciona el reinicio " Retry OPEN using a different pathname" e introduce una ruta de acceso distinta (lispm-init.lisp en lugar de lispm-int.lisp). El código del usuario no contiene código para el manejo de errores. Todo el código para el manejo de errores y el reinicio lo proporciona el sistema Lisp, que puede gestionar y corregir el error sin interrumpir la ejecución del código del usuario.

Comando: (test ">zippy>lispm-int.lisp") Error: No se encontró el archivo. Para lispm:>zippy>lispm-int.lisp.newest LMFS:OPEN-LOCAL-LMFS-1 Argumento 0: #P"lispm:>zippy>lispm-int.lisp.newest" sA, <Reanudar>: Reintentar ABRIR de lispm:>zippy>lispm-int.lisp.newest sB: Vuelva a intentar abrir utilizando una ruta de acceso diferente. sC, <Abortar>: Regresar al nivel superior de Lisp en un servidor TELNET sD: Reiniciar el proceso del terminal TELNET -> Vuelva a intentar abrir usando una ruta de acceso diferente Utilice what pathname en su lugar [default lispm:>zippy>lispm-int.lisp.newest]: lispm:>zippy>lispm-init.lisp.newest ...el programa continúa 

Sistema de objetos Lisp común (CLOS)

Common Lisp incluye un conjunto de herramientas para la 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 sencillos de implementar en un lenguaje dinámico con las características de CLOS (herencia múltiple, mixins, multimétodos, metaclases, combinaciones de métodos, etc.). [ 19 ] Se han propuesto varias extensiones de Common Lisp para la programación orientada a objetos para ser incluidas en el estándar ANSI Common Lisp, pero finalmente CLOS fue adoptado como el sistema de objetos estándar para Common Lisp. CLOS es un sistema de objetos dinámico con despacho múltiple y herencia múltiple , y difiere radicalmente de las facilidades de POO 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 a 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 los objetos.

CLOS se ha integrado en ANSI Common Lisp. Las funciones genéricas se pueden usar como funciones normales y son un tipo de dato de primera clase. Cada clase de CLOS está integrada en el sistema de tipos de Common Lisp. Muchos tipos de Common Lisp tienen una clase correspondiente. Existe un mayor potencial de uso de CLOS para Common Lisp. La especificación no indica si las condiciones se implementan con CLOS. Las rutas de acceso y los flujos podrían implementarse con CLOS. Estas posibilidades adicionales de uso de CLOS para ANSI Common Lisp no forman parte del estándar. Las implementaciones actuales de Common Lisp usan CLOS para rutas de acceso, flujos, entrada/salida, condiciones, la implementación de CLOS en sí misma y más.

Compilador e intérprete

Un intérprete de Lisp ejecuta directamente el código fuente de Lisp proporcionado como objetos Lisp (listas, símbolos, números, etc.) leídos a partir de expresiones S. Un compilador de Lisp genera código de bytes o código máquina a partir del código fuente de Lisp. Common Lisp permite compilar funciones individuales de Lisp 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 ámbito léxico en el compilador y el ámbito dinámico en el intérprete. Common Lisp requiere que tanto el intérprete como el compilador utilicen el ámbito léxico por defecto. El estándar Common Lisp describe la semántica tanto del intérprete como del compilador. El compilador se puede llamar usando la función `compile` para funciones individuales y usando la función `compile-file` para archivos. Common Lisp permite declaraciones de tipo y proporciona formas de influir en la política de generación de código del compilador. Para esta última, se pueden dar valores a varias cualidades de optimización entre 0 (no importante) y 3 (muy importante): velocidad , espacio , seguridad , depuración y velocidad de compilación .

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) están implementando evalusando su compilador. De esta manera, el código se compila, aunque se evalúa usando 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 , así como los archivos de código fuente, pueden cargarse en un sistema Common Lisp en ejecución mediante la función ` load` . 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 pueden utilizarse de forma interactiva, aunque el código se compile completamente. Por lo tanto, el concepto de lenguaje interpretado no se aplica a Common Lisp interactivo.

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

Se proporcionan algunos operadores especiales para facilitar el desarrollo interactivo; por ejemplo, defvarsolo asignará un valor a la variable proporcionada si aún no está vinculada, mientras que defparametersiempre realizará la asignación. Esta distinción resulta útil al evaluar, compilar y cargar código de forma interactiva en una imagen en vivo.

También se incluyen algunas características para facilitar la escritura de compiladores e intérpretes. Los símbolos constan de objetos de primer nivel y pueden ser manipulados directamente por el código del usuario. El progvoperador especial permite crear enlaces léxicos mediante programación, y 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ínimo de personas en una habitación para las cuales la probabilidad de que sus cumpleaños sean únicos es inferior al 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 +year-size+ 365 )( defun birthday-paradox ( probabilidad número-de-personas ) ( let (( nueva-probabilidad ( * ( / ( - +year-size+ número-de-personas ) +year-size+ ) probabilidad ))) ( if ( < nueva-probabilidad 0.5 ) ( 1+ número-de-personas ) ( birthday-paradox nueva-probabilidad ( 1+ número-de-personas )))))

Llamada a la función de ejemplo mediante el REPL (Read Eval Print Loop):

CL-USER > (birthday-paradox 1.0 1) 23 

Ordenar una lista de objetos de personas

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 ranuras NOMBRE y EDAD." ))( defmethod display (( object person ) stream ) "Muestra 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 PERSON." )( dolist ( person ( sort ( copy-list *group* ) #' > :key #' person-age )) ( display person *standard-output* ) ( terpri ))

Imprime los tres nombres en orden descendente de edad.

Bob (33) Ash (23) Chris (16) 

Exponentiating by squaring

Use of the LOOP macro is demonstrated:

(defunpower(xn)(loopwithresult=1while(pluspn)when(oddpn)do(setfresult(*resultx))do(setfx(*xx)n(truncaten2))finally(returnresult)))

Example use:

CL-USER>(power2200)1606938044258990275541962092341162602522202993782792835301376

Compare with the built in exponentiation:

CL-USER>(=(expt2200)(power2200))T

Find the list of available shells

WITH-OPEN-FILE is a macro that opens a file and provides a stream. When the form is returning, the file is automatically closed. FUNCALL calls a function object. The LOOP collects all lines that match the predicate.

(defunlist-matching-lines(filepredicate)"Returns a list of lines in file, for which the predicate applied to the line returns T."(with-open-file(streamfile)(loopforline=(read-linestreamnilnil)whilelinewhen(funcallpredicateline)collectit)))

The function AVAILABLE-SHELLS calls the above function LIST-MATCHING-LINES with a pathname and an anonymous function as the predicate. The predicate returns the pathname of a shell or NIL (if the string is not the filename of a 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 Lisps

Common Lisp se compara frecuentemente con Scheme , aunque solo sea porque son los dos dialectos de Lisp más populares. Scheme es anterior a CL y proviene no solo de la misma tradición 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 variantes 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 lenguajes Lisp anteriores, Common Lisp (al igual que Scheme ) utiliza el ámbito léxico de las variables por defecto 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 de ámbito dinámico en sus intérpretes y variables de ámbito léxico en sus compiladores. Scheme introdujo el uso exclusivo de variables de ámbito léxico en Lisp, inspirándose en ALGOL 68. CL también admite variables de á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 veces se denomina a Common Lisp como Lisp-2 y a Scheme como Lisp-1 , en referencia al uso que hace CL de espacios de nombres separados para funciones y variables. (De hecho, CL tiene muchos espacios de nombres, como los de las etiquetas go, los nombres de bloques y looplas palabras clave). Existe una controversia de larga data entre los defensores de CL y Scheme sobre las ventajas y desventajas de usar múltiples espacios de nombres. En Scheme, es (en general) necesario evitar que las variables tengan nombres que entren en conflicto con las funciones; las funciones de Scheme frecuentemente tienen argumentos llamados lis, lst, o lystpara no entrar en conflicto con la función del sistema list. Sin embargo, en CL es necesario referirse explícitamente al espacio de nombres de la función cuando se pasa una función como argumento, lo cual también es algo 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 verdad y falsedad. CL sigue la convención antigua 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 por condicionales, como if, mientras que en Scheme todos los valores que no son #f se tratan como verdaderos. Estas convenciones permiten que algunos operadores en ambos lenguajes sirvan tanto como predicados (respondiendo a una pregunta con valor booleano) como para devolver 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 exige. La mayoría de las implementaciones de CL ofrecen optimización de llamadas de cola, aunque a menudo solo cuando el programador utiliza una directiva de optimización. No obstante, el estilo de codificación común de CL no favorece el uso generalizado de la recursión que prefiere el estilo Scheme: lo que un programador de Scheme expresaría con recursión de cola, un usuario de CL normalmente lo expresaría con una expresión iterativa en do, dolist, loop, o (más recientemente) con el iteratepaquete .

Implementaciones

Consulte la categoría Implementaciones de Common Lisp .

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

Además, las implementaciones suelen incluir extensiones que proporcionan funcionalidades no contempladas en el estándar:

  • Interfaz interactiva de nivel superior (REPL)
  • Recogida de basura
  • Depurador, controlador paso a paso e inspector
  • Estructuras de datos débiles (tablas hash)
  • Secuencias extensibles
  • Bucle extensible
  • Acceso al medio ambiente
  • 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 a C)
  • Interfaz del sistema operativo
  • Interfaz Java
  • Hilos y multiprocesamiento
  • Entrega de aplicaciones (aplicaciones, bibliotecas dinámicas)
  • Guardar imágenes

Se han creado bibliotecas de software libre y de código abierto para admitir extensiones de Common Lisp de forma portátil, 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 admitir compiladores incrementales , compiladores de archivos y compiladores de bloques. En la especificación del lenguaje se proponen declaraciones estándar para optimizar la compilación (como la inserción de funciones o la especialización de tipos). La mayoría de las implementaciones de Common Lisp compilan el código fuente a código 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 código Common Lisp a código C. La idea errónea de que Lisp es un lenguaje puramente interpretado se debe probablemente a que los entornos Lisp proporcionan una interfaz interactiva y ese código se compila uno por uno, de forma incremental. Con Common Lisp, la compilación incremental es ampliamente utilizada.

Algunas implementaciones basadas en Unix ( CLISP , SBCL ) pueden usarse como lenguaje de scripting ; es decir, el sistema las invoca de forma transparente, como lo hace un intérprete de Perl o de shell de Unix . [ 22 ]

Lista de implementaciones

Implementaciones comerciales

Allegro Common Lisp
Para Microsoft Windows, FreeBSD, Linux, Apple macOS y diversas variantes de UNIX. Allegro CL proporciona un entorno de desarrollo integrado (IDE) (para Windows y Linux) y amplias capacidades para la entrega de aplicaciones.
Lisp común líquido
Anteriormente llamado Lucid Common Lisp. Solo mantenimiento, no se publican nuevos lanzamientos.
LispWorks
LispWorks es compatible con Microsoft Windows, FreeBSD, Linux, Apple macOS, iOS, Android y diversas variantes de UNIX. Ofrece un entorno de desarrollo integrado (IDE) (disponible para la mayoría de las plataformas, pero no para iOS ni Android) y amplias funcionalidades para la distribución de aplicaciones.
mocl
Para iOS, Android y macOS.
Generación abierta
Para DEC Alpha.
Lisp común de Scienceer
Diseñado para la computación científica de alto rendimiento.

Implementaciones de libre distribución

Lisp común del oso armado (ABCL)
Una implementación de CL que se ejecuta en la Máquina Virtual de Java . [ 23 ] Incluye un compilador a código de bytes de Java y permite el acceso a bibliotecas de Java desde CL. Anteriormente era solo un componente del editor Armed Bear J.
Corchete
Una implementación basada en LLVM que interactúa sin problemas con las bibliotecas de C++. Se ejecuta en varios sistemas Unix y similares a Unix (incluido macOS ).
CLISP
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 otros sistemas.
Clozure CL (CCL)
Originalmente, CCL era una bifurcación gratuita y de código abierto de Macintosh Common Lisp. Como su historia lo indica, CCL fue escrito para Macintosh, pero ahora Clozure CL se ejecuta en macOS , FreeBSD , Linux , Solaris y Windows . Admite versiones x86 de 32 y 64 bits en cada plataforma. Además, existen versiones para Power PC en macOS y Linux. Anteriormente, CCL se conocía 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 desarrollado en la Universidad Carnegie Mellon , ahora es 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 para Linux y BSD en arquitecturas Intel x86; Linux para Alpha; macOS para Intel x86 y PowerPC; y Solaris, IRIX y HP-UX en sus plataformas nativas.
Corman Common Lisp
Para Microsoft Windows. En enero de 2015, Corman Lisp se publicó bajo la licencia MIT. [ 24 ]
Common Lisp integrable (ECL)
ECL incluye un intérprete y compilador de código de bytes. También puede compilar código Lisp a código máquina mediante un compilador de C. Posteriormente, ECL compila el código Lisp a C, compila el código C con un compilador de C y, finalmente, puede cargar el código máquina resultante. Asimismo, es posible integrar 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 cumple completamente con el estándar ANSI, GCL es la implementación preferida para varios proyectos importantes, 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, macOS, Solaris y FreeBSD .
Macintosh Common Lisp (MCL)
La versión 5.2 para ordenadores Apple Macintosh con procesador PowerPC y macOS X es de código abierto. RMCL (basado en MCL 5.2) se ejecuta en ordenadores Apple Macintosh con procesador Intel mediante el traductor binario Rosetta de Apple.
Lisp común de Mankai (MKCL)
MKCL, una rama de ECL , prioriza la fiabilidad, la estabilidad y la calidad general del código mediante un sistema de ejecución multihilo nativo profundamente rediseñado. En Linux, MKCL cuenta con un sistema de ejecución totalmente compatible con POSIX.
Movitz
Implementa un entorno Lisp para ordenadores x86 sin depender de ningún sistema operativo subyacente.
Registro pop
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. En todos los casos, el lenguaje de implementación es POP-11, que se compila de forma incremental. También cuenta con un editor integrado similar a Emacs que se comunica con el compilador.
Lisp común del Banco de Acero (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 por defecto; todas las expresiones se compilan a código nativo a menos que el usuario active el intérprete. El compilador de SBCL genera código nativo rápido según una versión anterior de The Computer Language Benchmarks Game . [ 27 ]
Ufasoft Common Lisp
Versión de CLISP para Windows con el núcleo escrito en C++.

Otras implementaciones

Austin Kyoto Common Lisp
Una evolución del Lisp común de Kioto por Bill Schelter .
Lisón común mariposa
Una implementación escrita en Scheme para la computadora multiprocesador BBN Butterfly . [ 28 ] [ 29 ]
CLICC
Un compilador de Common Lisp a C. [ 30 ]
CLOE
Common Lisp para PC por Symbolics .
Codemist Common Lisp
Utilizado para la versión comercial del sistema de álgebra computacional Axiom. [ 31 ] [ 32 ]
Lisp ExperCommon
Una implementación temprana para Apple Macintosh por ExperTelligence.
Lisón 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 de Common Lisp que utilizó C como lenguaje de destino. GCL, ECL y MKCL tienen su origen en esta implementación de Common Lisp.
L
Una versión pequeña de Common Lisp para sistemas embebidos desarrollada por IS Robotics, ahora iRobot [ 35 ]
Máquinas Lisp (de Symbolics , TI [ 36 ] [ 37 ] y Xerox [ 38 ] )
Proporcionaban implementaciones de Common Lisp además de su dialecto Lisp nativo (Lisp Machine Lisp o Interlisp). CLOS también estaba disponible. Symbolics proporciona una versión mejorada de Common Lisp. [ 39 ] [ 40 ] [ 41 ]
Procyon Common Lisp
Una implementación para Windows y macOS, utilizada por Franz para su versión de Allegro CL para Windows.
LISP común de zafiro estrella
Una implementación para 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 ]
WCL
Una implementación de biblioteca compartida. [ 44 ] [ 45 ]
Lisp común VAX
Implementación de Digital Equipment Corporation que se ejecutaba en sistemas VAX con VMS o ULTRIX .
XLISP
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 electrónico Yahoo! Store, que originalmente contó con la participación de Paul Graham y que posteriormente fue reescrito en C++ y Perl . [ 47 ] Otros ejemplos notables incluyen:

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

Véase también

Referencias

  1. "Acción sobre 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: Un estudio" . Archivado del original el 21 de abril de 2012. Consultado el 22 de diciembre de 2007 .
  6. "Los programas antiguos de LISP todavía se ejecutan en Common Lisp" . Consultado el 13 de mayo de 2015 .
  7. "Raíces del "Lisp de Yu-Shiang", Correo de Jon L White, 1982" . cmu.edu .
  8. "Índice de correo" . cl-su-ai.lisp.se .
  9. Reacción instintiva contra el bucle y otros fenómenos del correo electrónico: patrones orales, escritos y electrónicos en la comunicación mediada por ordenador, 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 visión general de COMMON LISP». Actas del simposio de la ACM de 1982 sobre LISP y programación funcional - LFP '82 . ACM. págs. 98–107 . doi : 10.1145/800068.802140 . ISBN  9780897910828. S2CID 14517358 . 
  11. Reddy, Abhishek (22 de agosto de 2008). "Características de Common Lisp" .
  12. "Soporte Unicode" . Wiki de Common Lisp . Consultado el 21 de agosto de 2008 .
  13. 1 2 Richard P. Gabriel; Kent M. Pitman (junio de 1988). "Problemas técnicos 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. "Hyperspec de Common Lisp: Sección 3.1.7" .
  15. "Hyperspec de Common Lisp: Función FLOOR" .
  16. "Hyperspec de Common Lisp: Accesor GETHASH" .
  17. "Let Over 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. "Common-Lisp.net" .
  21. "Colección de código abierto de Common Lisp" .
  22. "32.6. Inicio rápido de la entrega con CLISP" . clisp.cons.org .
  23. "Oso armado Lisp común" .
  24. "El código fuente de Corman Lisp ya está disponible" . 5 de enero de 2015.
  25. "Historia y derechos de autor" . Lisp común de Steel Bank .
  26. "Mesa de plataforma" . Lisp común de Steel Bank .
  27. "¿Qué programas son los más rápidos? – Juego de evaluación comparativa de lenguajes informáticos" . 20 de mayo de 2013. Archivado del original el 20 de mayo de 2013.
  28. "Paquete: lang/lisp/impl/bbn/" . cs.cmu.edu .
  29. "Desarrollos recientes en Butterfly Lisp, 1987, Actas de la AAAI" (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 a C". CiteSeerX 10.1.1.38.1282 . {{cite journal}}: Para citar una revista se requiere |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.; et al., et (22 de junio de 1995). "L – Un Lisp común para sistemas embebidos". CiteSeerX 10.1.1.2.1953 . {{cite journal}}: Para citar una revista se requiere |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 Common Lisp – Software Preservation Group" . softwarepreservation.computerhistory.org .
  44. WCL: Desarrollo de 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 del original el 5 de abril de 2016 . Recuperado el 25 de marzo de 2016 . 
  46. "Paquete: lang/lisp/impl/xlisp/" . cs.cmu.edu .
  47. "Superando los promedios " . paulgraham.com
  48. "Asistente del Autorizador" (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. 1 2 "Aeroespacial – Common Lisp" . lisp-lang.org .
  55. "Usuarios de piano, obtenido de la página del fabricante" .
  56. "Grammarly.com, Uso de Lisp en producción" . 26 de junio de 2015.
  57. "Agente remoto" . ti.arc.nasa.gov .
  58. "Ceceo en JPL" .
  59. "Aplicaciones de clientes de Franz Inc: NASA" . franz.com .
  60. Sistema de planificación y programación de picos . Stsci.edu. Consultado el 17 de julio de 2013.
  61. "Aplicaciones de clientes de Franz Inc: Space Telescope Institute" . franz.com .
  62. "Cómo empezó todo... también conocido como el nacimiento de CLR" . microsoft.com . 28 de agosto de 2023.
  63. Huffman, Steve. "sobre el ceceo" . Votado positivamente . Archivado del original el 17 de mayo de 2018. Recuperado el 11 de mayo de 2019 .
  64. https://github.com/tamurashingo/reddit1.0/
  65. https://lisp-journey.gitlab.io/blog/hacker-news-now-runs-on-top-of-common-lisp/
  66. "Pgloader" .
  67. "¿Por qué pgloader es mucho más rápido?" 14 de mayo de 2014.
  68. https://kandria.com/
  69. Informe de experiencia: Kandria, un juego en Common Lisp: https://raw.githubusercontent.com/Shinmera/talks/master/els2023-kandria/paper.pdf

Bibliografía

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

  • Uno de los principales repositorios de software libre Common Lisp es Common-Lisp.net .
  • El libro de cocina de Common Lisp .
  • La lista Awesome CL , una selección curada de frameworks y bibliotecas de Common Lisp.
  • lisp-lang.org cuenta con documentación y una muestra de casos de éxito.
  • Quicklisp : un gestor de bibliotecas muy popular y de alta calidad para Common Lisp.
  • Una visión general de la historia de Common Lisp: "Historia" . Common Lisp HyperSpec .
  • Guía de referencia rápida de Common Lisp : una descripción general concisa del lenguaje estándar Common Lisp.
  • Artículos de Planet Lisp sobre Common Lisp.
  • Quickdocs resume la documentación y la información sobre dependencias de muchos proyectos de Quicklisp.
  • CLiki , una wiki para sistemas Common Lisp gratuitos y de código abierto que se ejecutan en sistemas tipo Unix.