Lisp (históricamente LISP , abreviatura de "list processing") es una familia de lenguajes de programación con una larga historia y una notación de prefijo distintiva, completamente entre paréntesis . [ 3 ] Originalmente especificado a finales de la década de 1950, es el segundo lenguaje de programación de alto nivel más antiguo que todavía se usa comúnmente, después de Fortran . [ 4 ] [ 5 ] Lisp ha cambiado desde sus inicios, y han existido muchos dialectos a lo largo de su historia. Hoy en día, los dialectos de Lisp de propósito general más conocidos son Common Lisp , Scheme , Racket y Clojure . [ 6 ] [ 7 ] [ 8 ]
Lisp se creó originalmente como una notación matemática práctica para programas informáticos , influenciada por (aunque no derivada originalmente de) [ 9 ] la notación del cálculo lambda de Alonzo Church . Rápidamente se convirtió en un lenguaje de programación predilecto para la investigación en inteligencia artificial (IA). [ 10 ] Como uno de los primeros lenguajes de programación, Lisp fue pionero en muchas ideas en ciencias de la computación , incluyendo estructuras de datos de árbol , gestión automática de almacenamiento , tipado dinámico , condicionales , funciones de orden superior , recursión , el compilador autoalojado [ 11 ] y el bucle de lectura-evaluación-impresión . [ 12 ]
El nombre LISP deriva de "List Processor" (Procesador de Listas). [ 13 ] Las listas enlazadas son una de las principales estructuras de datos de Lisp , y el código fuente de Lisp está compuesto por listas. Por lo tanto, los programas Lisp pueden manipular el código fuente como una estructura de datos, dando lugar a los sistemas de macros que permiten a los programadores crear nueva sintaxis o nuevos lenguajes específicos de dominio integrados en Lisp.
La intercambiabilidad del código y los datos le da a Lisp su sintaxis reconocible al instante. Todo el código del programa se escribe como expresiones s , o listas entre paréntesis. Una llamada a función o forma sintáctica se escribe como una lista con el nombre de la función u operador primero, y los argumentos a continuación; por ejemplo, una función fque toma tres argumentos se llamaría como .(farg1arg2arg3)
Historia
John McCarthy comenzó a desarrollar Lisp en 1958 mientras estaba en el Instituto Tecnológico de Massachusetts (MIT). Lo motivó el deseo de crear un lenguaje de programación de IA que funcionara en el IBM 704 , ya que creía que "IBM parecía una buena apuesta para impulsar la investigación en Inteligencia Artificial con vigor". [ 14 ] Se inspiró en el Lenguaje de Procesamiento de Información , que también se basaba en el procesamiento de listas, pero no lo utilizó porque estaba diseñado para un hardware diferente y le resultaba más atractivo un lenguaje algebraico. [ 14 ] Debido a estos factores, colaboró en el diseño del Lenguaje de Procesamiento de Listas de Fortran , que se implementó como una biblioteca de Fortran. Sin embargo, no quedó satisfecho con él porque no admitía recursión ni una instrucción if-then-else moderna (que era un concepto nuevo cuando se introdujo Lisp por primera vez). [ nota 1 ] [ 14 ]
La notación original de McCarthy utilizaba expresiones M entre corchetes que se traducían a expresiones S. Por ejemplo, la expresión M car[cons[A,B]]es equivalente a la expresión S. Una vez implementado Lisp, los programadores optaron rápidamente por usar expresiones S y se abandonaron las expresiones M. [ 14 ] Las expresiones M reaparecieron con intentos efímeros de MLisp [ 15 ] por Horace Enea y CGOL por Vaughan Pratt .(car(consAB))
Lisp fue implementado por primera vez por Steve Russell en una computadora IBM 704 usando tarjetas perforadas . [ 16 ] Russell trabajaba para McCarthy en ese momento y se dio cuenta (para sorpresa de McCarthy) de que la función eval de Lisp podía implementarse en código máquina .
Según McCarthy [ 17 ]
Steve Russell dijo: «Mira, ¿por qué no programo esta función eval ?». Y yo le respondí: «Ja, ja, estás confundiendo la teoría con la práctica; esta función eval está pensada para leer, no para calcular». Pero él siguió adelante y lo hizo. Es decir, compiló la función eval de mi artículo en código máquina IBM 704 , corrigiendo errores , y luego la promocionó como un intérprete de Lisp, que sin duda lo era. Así que, en ese momento, Lisp tenía esencialmente la forma que tiene hoy en día ...
El resultado fue un intérprete de Lisp funcional que podía utilizarse para ejecutar programas Lisp o, más propiamente, para "evaluar expresiones Lisp".
Dos macros en lenguaje ensamblador para el IBM 704 se convirtieron en las operaciones primitivas para descomponer listas: car ( Contenido de la parte de dirección del número de registro) y cdr ( Contenido de la parte de decremento del número de registro), [ 18 ] donde "registro" se refiere a los registros de la unidad central de procesamiento (CPU) de la computadora . Los dialectos de Lisp todavía usan cary cdr( / k ɑːr / y / ˈ k ʊ d ər / ) para las operaciones que devuelven el primer elemento de una lista y el resto de la lista, respectivamente.
McCarthy publicó el diseño de Lisp en un artículo en Communications of the ACM el 1 de abril de 1960, titulado "Funciones recursivas de expresiones simbólicas y su computación por máquina, parte I". [ 19 ] [ 20 ] Demostró que con unos pocos operadores simples y una notación para funciones anónimas tomada de Church, se puede construir un lenguaje Turing-completo para algoritmos.
El primer compilador completo de Lisp, escrito en Lisp, fue implementado en 1962 por Tim Hart y Mike Levin en el MIT, y podía compilarse simplemente haciendo que un intérprete de Lisp existente interpretara el código del compilador, produciendo una salida de código máquina que podía ejecutarse con una mejora de velocidad de 40 veces con respecto a la del intérprete. [ 21 ] Este compilador introdujo el modelo de compilación incremental de Lisp , en el que las funciones compiladas e interpretadas pueden mezclarse libremente. El lenguaje utilizado en el memorándum de Hart y Levin está mucho más cerca del estilo Lisp moderno que el código anterior de McCarthy.
Las rutinas de recolección de basura fueron desarrolladas por el estudiante de posgrado del MIT Daniel Edwards, antes de 1962. [ 22 ]
Durante las décadas de 1980 y 1990, se realizó un gran esfuerzo para unificar el trabajo sobre nuevos dialectos de Lisp (principalmente sucesores de Maclisp, como ZetaLisp y NIL (New Implementation of Lisp)) en un solo lenguaje. El nuevo lenguaje, Common Lisp , era compatible en cierta medida con los dialectos a los que reemplazaba (el libro Common Lisp the Language destaca la compatibilidad de varias construcciones). En 1994, ANSI publicó el estándar Common Lisp, "ANSI X3.226-1994 Information Technology Programming Language Common Lisp".
Cronología
Conexión con la inteligencia artificial
Desde sus inicios, Lisp estuvo estrechamente vinculado a la comunidad de investigación en inteligencia artificial , especialmente en los sistemas PDP-10 [ 23 ] . Lisp se utilizó como implementación del lenguaje Micro Planner , que a su vez se empleó en el famoso sistema de IA SHRDLU . En la década de 1970, a medida que la investigación en IA generó ramificaciones comerciales, el rendimiento de los sistemas Lisp existentes se convirtió en un problema creciente, ya que los programadores debían familiarizarse con las implicaciones en el rendimiento de las diversas técnicas y opciones involucradas en la implementación de Lisp. [ 24 ]
Genealogía y variantes
A lo largo de sus sesenta años de historia, Lisp ha dado lugar a numerosas variantes basadas en el concepto fundamental de lenguaje de expresiones S. Algunas de estas variantes han sido estandarizadas e implementadas por distintos grupos con diferentes prioridades (por ejemplo, tanto Common Lisp como Scheme cuentan con múltiples implementaciones). Sin embargo, en otros casos, un proyecto de software define un Lisp sin un estándar, sin que exista una distinción clara entre el dialecto y la implementación (por ejemplo, Clojure y Emacs Lisp entran en esta categoría).
Las diferencias entre dialectos (y/o implementaciones) pueden ser bastante visibles; por ejemplo, Common Lisp usa la palabra clave defunpara nombrar una función, pero Scheme usa define. [ nota 2 ] Dentro de un dialecto estandarizado, las implementaciones conformes admiten el mismo lenguaje base, pero con diferentes extensiones y bibliotecas. Esto a veces también crea cambios bastante visibles con respecto al lenguaje base; por ejemplo, Guile (una implementación de Scheme) usa define*para crear funciones que pueden tener argumentos predeterminados y/o argumentos de palabra clave , ninguno de los cuales está estandarizado.
Dialectos de importancia histórica


- LISP 1 [ 25 ] – Primera implementación.
- LISP 1.5 [ 26 ] – Primera versión ampliamente distribuida, desarrollada por McCarthy y otros en el MIT. Recibió ese nombre porque contenía varias mejoras en el intérprete original "LISP 1", pero no fue una reestructuración importante como lo sería el LISP 2 planeado.
- Stanford LISP 1.6 [ 27 ] – Sucesor de LISP 1.5 desarrollado en el Laboratorio de IA de Stanford y ampliamente distribuido a los sistemas PDP-10 que ejecutaban el sistema operativo TOPS-10 . Fue reemplazado por Maclisp e InterLisp.
- Maclisp [ 28 ] – desarrollado para el Proyecto MAC del MIT , MACLISP es un descendiente directo de LISP 1.5. Se ejecutaba en los sistemas PDP-10 y Multics . MACLISP más tarde se llamaría Maclisp, y a menudo se le conoce como MacLisp. La sigla "MAC" en MACLISP no tiene relación con el Macintosh de Apple ni con McCarthy .
- Interlisp [ 29 ] – desarrollado en BBN Technologies para sistemas PDP-10 que ejecutaban el sistema operativo TENEX , posteriormente adoptado como un Lisp de la "costa oeste" para las máquinas Lisp de Xerox como InterLisp-D. Se publicó una versión reducida llamada "InterLISP 65" para las computadoras Atari de 8 bits basadas en MOS Technology 6502. Maclisp e InterLisp fueron fuertes competidores.
- Franz Lisp – originalmente un proyecto de la Universidad de California, Berkeley ; posteriormente desarrollado por Franz Inc. El nombre es una deformación humorística del nombre " Franz Liszt " y no se refiere a Allegro Common Lisp , el dialecto de Common Lisp que Franz Inc. vendió en años más recientes.
- muLISP , desarrollado inicialmente por Albert D. Rich y David Stoutemeyer para sistemas de microcomputadoras pequeñas, se comercializó en 1979 y funcionaba en sistemas CP/M con tan solo 64 KB de RAM. Posteriormente, se adaptó a MS-DOS, finalizando su desarrollo en 1995. El software matemático "Derive" se escribió en muLISP para MS-DOS y, más tarde, para Windows hasta 2007.
- XLISP , en el que se basó AutoLISP .
- Standard Lisp y Portable Standard Lisp fueron ampliamente utilizados y adaptados, especialmente con el sistema de álgebra computacional REDUCE.
- ZetaLisp , también conocido como Lisp Machine Lisp, se utilizaba en las máquinas Lisp y es descendiente directo de Maclisp. ZetaLisp tuvo una gran influencia en Common Lisp.
- LeLisp es un dialecto francés de Lisp. Uno de los primeros Interface Builders (llamado SOS Interface [ 30 ] ) fue escrito en LeLisp.
- Esquema (1975). [ 31 ]
- Common Lisp (1984), como se describe en Common Lisp the Language , es una consolidación de varios intentos divergentes (ZetaLisp, Spice Lisp , NIL y S-1 Lisp ) para crear dialectos sucesores [ 32 ] de Maclisp, con influencias sustanciales también del dialecto Scheme. Esta versión de Common Lisp estaba disponible para una amplia gama de plataformas y fue aceptada por muchos como un estándar de facto [ 33 ] hasta la publicación de ANSI Common Lisp (ANSI X3.226-1994). Entre los subdialectos más extendidos de Common Lisp se encuentran Steel Bank Common Lisp (SBCL), CMU Common Lisp (CMU-CL), Clozure OpenMCL (¡que no debe confundirse con Clojure!), GNU CLisp y versiones posteriores de Franz Lisp; todos ellos se adhieren al estándar ANSI CL posterior (véase más abajo).
- En su primera versión, Dylan era una mezcla de Scheme con el Sistema de Objetos de Common Lisp.
- EuLisp : intento de desarrollar una nueva versión de Lisp, más eficiente y depurada.
- ISLISP – intento de desarrollar un nuevo Lisp eficiente y limpio. Estandarizado como ISO/IEC 13816:1997 [ 34 ] y revisado posteriormente como ISO/IEC 13816:2007: [ 35 ] Tecnología de la información – Lenguajes de programación, sus entornos e interfaces de software de sistema – Lenguaje de programación ISLISP .
- Esquema IEEE – Norma IEEE, 1178–1990 (R1995).
- ANSI Common Lisp : un estándar del Instituto Nacional Estadounidense de Estándares (ANSI) para Common Lisp, creado por el subcomité X3J13 , establecido [ 36 ] para comenzar con Common Lisp: The Language como documento base y trabajar a través de un proceso de consenso público para encontrar soluciones a problemas comunes de portabilidad de programas y compatibilidad de implementaciones de Common Lisp. Aunque formalmente es un estándar ANSI, la implementación, venta, uso e influencia de ANSI Common Lisp se ha visto y continúa viéndose en todo el mundo.
- ACL2 , o "Lógica Computacional para Common Lisp Aplicativo", es una variante aplicativa (sin efectos secundarios) de Common LISP. ACL2 es tanto un lenguaje de programación que puede modelar sistemas informáticos como una herramienta para ayudar a demostrar las propiedades de dichos modelos.
- Clojure , un dialecto reciente de Lisp que se compila a la máquina virtual de Java y tiene un enfoque particular en la concurrencia .
- Game Oriented Assembly Lisp (o GOAL) es un lenguaje de programación para videojuegos desarrollado por Andy Gavin en Naughty Dog . Fue escrito utilizando Allegro Common Lisp y se usó en el desarrollo de toda la serie de juegos Jak and Daxter, también desarrollada por Naughty Dog.
Desde el año 2000 hasta la actualidad
Tras un cierto declive en la década de 1990, Lisp ha experimentado un resurgimiento del interés después del año 2000. La mayor parte de la nueva actividad se ha centrado en implementaciones de Common Lisp , Scheme , Emacs Lisp , Clojure y Racket , e incluye el desarrollo de nuevas bibliotecas y aplicaciones portátiles.
Muchos nuevos programadores de Lisp se inspiraron en autores como Paul Graham y Eric S. Raymond para aprender un lenguaje que otros consideraban anticuado. Estos nuevos programadores suelen describir el lenguaje como una experiencia reveladora y afirman ser sustancialmente más productivos que en otros lenguajes. [ 37 ] Este aumento en la concienciación puede contrastarse con el « invierno de la IA » y el breve auge de Lisp a mediados de la década de 1990. [ 38 ]
A partir de 2010, había once implementaciones de Common Lisp mantenidas activamente. [ 39 ]
La comunidad de código abierto ha creado una nueva infraestructura de soporte: CLiki es una wiki que recopila información relacionada con Common Lisp, el directorio Common Lisp enumera recursos, #lisp es un canal popular de IRC y permite compartir y comentar fragmentos de código (con soporte de lisppaste, un bot de IRC escrito en Lisp), Planet Lisp [ 40 ] recopila el contenido de varios blogs relacionados con Lisp, en LispForum [ 41 ] los usuarios discuten temas de Lisp, Lispjobs [ 42 ] es un servicio para anunciar ofertas de trabajo y hay un servicio de noticias semanal, Weekly Lisp News . Common-lisp.net es un sitio de alojamiento para proyectos de código abierto de Common Lisp. Quicklisp [ 43 ] es un gestor de bibliotecas para Common Lisp.
Se celebraron cincuenta años de Lisp (1958–2008) en LISP50@OOPSLA. [ 44 ] Se realizan reuniones periódicas de usuarios locales en Boston, Vancouver y Hamburgo. Otros eventos incluyen la Reunión Europea de Lisp Común, el Simposio Europeo de Lisp y una Conferencia Internacional de Lisp.
La comunidad Scheme mantiene activamente más de veinte implementaciones . Varias implementaciones nuevas e importantes (Chicken, Gambit, Gauche, Ikarus, Larceny, Ypsilon) se desarrollaron en la década de 2000. El estándar Scheme del Informe Revisado 5 sobre el Lenguaje Algorítmico Scheme [ 45 ] fue ampliamente aceptado en la comunidad Scheme. El proceso de Solicitudes de Implementación de Scheme ha creado muchas bibliotecas y extensiones cuasi estándar para Scheme. Las comunidades de usuarios de implementaciones individuales de Scheme continúan creciendo. Un nuevo proceso de estandarización del lenguaje se inició en 2003 y condujo al estándar Scheme R6RS en 2007. El uso académico de Scheme para la enseñanza de la informática parece haber disminuido un poco. Algunas universidades ya no usan Scheme en sus cursos introductorios de informática; [ 46 ] [ 47 ] el MIT ahora usa Python en lugar de Scheme para su programa de informática de pregrado y el curso masivo abierto en línea MITx. [ 48 ] [ 49 ]
Existen varios dialectos nuevos de Lisp: Arc , Hy , Nu , Liskell y LFE (Lisp Flavored Erlang). El analizador sintáctico de Julia está implementado en Femtolisp, un dialecto de Scheme (Julia está inspirada en Scheme, que a su vez es un dialecto de Lisp).
En octubre de 2019, Paul Graham publicó una especificación para Bel , "un nuevo dialecto de Lisp".
Principales dialectos
Common Lisp y Scheme representan dos corrientes principales del desarrollo de Lisp. Estos lenguajes incorporan decisiones de diseño significativamente diferentes.
Common Lisp es un sucesor de Maclisp . Las principales influencias fueron Lisp Machine Lisp , Maclisp, NIL , S-1 Lisp , Spice Lisp y Scheme. [ 50 ] Tiene muchas de las características de Lisp Machine Lisp (un dialecto de Lisp extenso utilizado para programar máquinas Lisp ), pero fue diseñado para ser implementable eficientemente en cualquier computadora personal o estación de trabajo. Common Lisp es un lenguaje de programación de propósito general y, por lo tanto, tiene un estándar de lenguaje extenso que incluye muchos tipos de datos integrados, funciones, macros y otros elementos del lenguaje, y un sistema de objetos ( Common Lisp Object System ). Common Lisp también tomó prestadas ciertas características de Scheme, como el alcance léxico y los cierres léxicos . Existen implementaciones de Common Lisp disponibles para diferentes plataformas como LLVM , [ 51 ] la máquina virtual Java , [ 52 ] x86-64, PowerPC, Alpha, ARM, Motorola 68000 y MIPS, [ 53 ] y sistemas operativos como Windows, macOS, Linux, Solaris, FreeBSD, NetBSD, OpenBSD, Dragonfly BSD y Heroku. [ 54 ]
Scheme es un dialecto del lenguaje de programación Lisp con ámbito estático y recursividad de cola propia, inventado por Guy L. Steele, Jr. y Gerald Jay Sussman . Fue diseñado para tener una semántica excepcionalmente clara y simple, y pocas formas diferentes de formar expresiones. Diseñado aproximadamente una década antes que Common Lisp, Scheme tiene un diseño más minimalista. Tiene un conjunto mucho más pequeño de características estándar, pero con ciertas características de implementación (como la optimización de llamadas de cola y las continuaciones completas ) que no están especificadas en Common Lisp. Una amplia variedad de paradigmas de programación, incluidos los estilos imperativos, funcionales y de paso de mensajes, encuentran una expresión conveniente en Scheme. Scheme continúa evolucionando con una serie de estándares (Revised n Report on the Algorithmic Language Scheme) y una serie de Scheme Requests for Implementation .
Clojure es un dialecto de Lisp que se dirige principalmente a la máquina virtual de Java , el Common Language Runtime (CLR), la máquina virtual de Python , la máquina virtual de Ruby (YARV ) y la compilación a JavaScript . Está diseñado para ser un lenguaje pragmático de propósito general. Clojure se nutre considerablemente de Haskell y pone un gran énfasis en la inmutabilidad. [ 55 ] Clojure proporciona acceso a los frameworks y bibliotecas de Java, con sugerencias de tipo e inferencia de tipos opcionales , de modo que las llamadas a Java pueden evitar la reflexión y permitir operaciones primitivas rápidas. Clojure no está diseñado para ser retrocompatible con otros dialectos de Lisp. [ 56 ]
Además, los dialectos de Lisp se utilizan como lenguajes de scripting en muchas aplicaciones, siendo los más conocidos Emacs Lisp en el editor Emacs , AutoLISP y posteriormente Visual Lisp en AutoCAD , Nyquist en Audacity y Scheme en LilyPond . El tamaño potencialmente reducido de un intérprete de Scheme útil lo hace particularmente popular para el scripting integrado. Ejemplos de ello son SIOD y TinyScheme , ambos integrados con éxito en el procesador de imágenes GIMP bajo el nombre genérico "Script-fu". [ 57 ] LIBREP, un intérprete de Lisp de John Harper basado originalmente en el lenguaje Emacs Lisp , se ha integrado en el gestor de ventanas Sawfish . [ 58 ]
dialectos estandarizados
Lisp tiene dialectos estandarizados oficialmente: Esquema R6RS , Esquema R7RS , Esquema IEEE, [ 59 ] ANSI Common Lisp e ISO ILISP .
innovaciones lingüísticas
Paul Graham identifica nueve aspectos importantes de Lisp que lo distinguen de lenguajes existentes como Fortran : [ 60 ]
- Las condiciones no se limitan a goto.
- Funciones de primera clase
- Recursión
- Tratar las variables uniformemente como punteros , dejando los tipos a los valores.
- Recogida de basura
- Programas compuestos enteramente de expresiones sin enunciados.
- El tipo de datos de símbolo , distinto del tipo de datos de cadena.
- Notación para código formado por árboles de símbolos (usando muchos paréntesis ).
- Idioma completo disponible en tiempo de carga , tiempo de compilación y tiempo de ejecución.
Lisp fue el primer lenguaje donde la estructura del código de programa se representa fiel y directamente en una estructura de datos estándar, una cualidad que mucho más tarde se denominó " homoiconicidad ". De este modo, las funciones de Lisp pueden manipularse, modificarse o incluso crearse dentro de un programa Lisp sin necesidad de manipulaciones de bajo nivel. Esto se considera generalmente una de las principales ventajas del lenguaje en cuanto a su poder expresivo, y lo hace idóneo para macros sintácticas y evaluación metacircular .
McCarthy inventó una estructura condicional con sintaxis if-then-else para un programa de ajedrez escrito en Fortran . Propuso su inclusión en ALGOL , pero no se incorporó a la especificación Algol 58. Para Lisp, McCarthy utilizó la estructura cond, más general . [ 61 ] Algol 60 adoptó if-then-else y la popularizó.
Lisp influyó profundamente en Alan Kay , líder del equipo de investigación que desarrolló Smalltalk en Xerox PARC ; y a su vez, Smalltalk influyó en Lisp, adoptando dialectos posteriores características de programación orientada a objetos (clases de herencia, instancias encapsuladas, paso de mensajes, etc.) en la década de 1970. El sistema de objetos Flavors introdujo el concepto de herencia múltiple y el mixin . El Common Lisp Object System proporciona herencia múltiple, multimétodos con despacho múltiple y funciones genéricas de primera clase , lo que da como resultado una forma flexible y potente de despacho dinámico . Ha servido como plantilla para muchos sistemas de objetos Lisp posteriores (incluido Scheme ), que a menudo se implementan a través de un protocolo de metaobjetos , un diseño metacircular reflexivo en el que el sistema de objetos se define en términos de sí mismo: Lisp fue solo el segundo lenguaje después de Smalltalk (y sigue siendo uno de los pocos lenguajes) en poseer un sistema de metaobjetos de este tipo. Muchos años después, Alan Kay sugirió que, como resultado de la confluencia de estas características, solo Smalltalk y Lisp podían considerarse sistemas de programación orientados a objetos debidamente concebidos. [ 62 ]
Lisp introdujo el concepto de recolección automática de basura , en el que el sistema recorre el montón buscando memoria no utilizada. El progreso en algoritmos modernos y sofisticados de recolección de basura, como la recolección de basura generacional, fue impulsado por su uso en Lisp. [ 63 ]
Edsger W. Dijkstra, en su discurso de aceptación del Premio Turing en 1972 , dijo:
Con unos pocos principios básicos como fundamento, LISP ha demostrado una notable estabilidad. Además, ha servido de base para un número considerable de las que, en cierto modo, son nuestras aplicaciones informáticas más sofisticadas. En tono de broma, se ha descrito a LISP como «la forma más inteligente de mal uso de un ordenador». Creo que esa descripción es un gran halago, pues transmite la esencia misma de la liberación: ha ayudado a muchos de nuestros semejantes más brillantes a concebir ideas antes imposibles. [ 64 ]
Debido principalmente a sus requisitos de recursos en relación con el hardware informático primitivo (incluidos los primeros microprocesadores), Lisp no alcanzó la misma popularidad fuera de la comunidad de IA que Fortran y el lenguaje C , derivado de ALGOL . Gracias a su idoneidad para aplicaciones complejas y dinámicas, Lisp experimentó un resurgimiento del interés popular en la década de 2010. [ 65 ]
Sintaxis y semántica
- Los ejemplos de este artículo están escritos en Common Lisp (aunque la mayoría también son válidos en Scheme ).
Expresiones simbólicas (expresiones S)
Lisp es un lenguaje orientado a expresiones . A diferencia de la mayoría de los demás lenguajes, no se distingue entre "expresiones" e "instrucciones" ; todo el código y los datos se escriben como expresiones. Cuando se evalúa una expresión , produce un valor (posiblemente varios), que luego se puede incorporar a otras expresiones. Cada valor puede ser de cualquier tipo de dato.
El artículo de McCarthy de 1958 introdujo dos tipos de sintaxis: expresiones simbólicas ( expresiones S , sexps), que reflejan la representación interna del código y los datos; y metaexpresiones ( expresiones M ), que expresan funciones de las expresiones S. Las expresiones M nunca se popularizaron, y casi todos los lenguajes Lisp actuales utilizan expresiones S para manipular tanto el código como los datos.
El uso de paréntesis es la diferencia más evidente de Lisp con respecto a otras familias de lenguajes de programación. Por ello, los estudiantes le han dado a Lisp apodos como « Lost In Stupid Parentheses » o «Lots of Irritating Superfluous Parentheses » [ 66 ] . Sin embargo, la sintaxis de expresiones S también es responsable de gran parte del poder de Lisp: su sintaxis es simple y consistente, lo que facilita su manipulación por parte del ordenador. No obstante, la sintaxis de Lisp no se limita a la notación tradicional de paréntesis. Puede extenderse para incluir notaciones alternativas. Por ejemplo, XMLisp es una extensión de Common Lisp que emplea el protocolo de metaobjetos para integrar expresiones S con el Lenguaje de Marcado Extensible ( XML ).
La dependencia de las expresiones confiere al lenguaje una gran flexibilidad. Dado que las funciones de Lisp se escriben como listas, pueden procesarse exactamente como datos. Esto facilita la escritura de programas que manipulan otros programas ( metaprogramación ). Muchos dialectos de Lisp aprovechan esta característica mediante sistemas de macros, lo que permite extender el lenguaje prácticamente sin límites.
Liza
Una lista de Lisp se escribe con sus elementos separados por espacios en blanco y entre paréntesis. Por ejemplo, es una lista cuyos elementos son los tres átomos , , y . Estos valores tienen un tipo implícito: son respectivamente dos enteros y un tipo de dato específico de Lisp llamado "símbolo", y no es necesario declararlos como tales.(12foo)12foo
La lista vacía ()también se representa como el átomo especial nil. Esta es la única entidad en Lisp que es a la vez un átomo y una lista.
Las expresiones se escriben como listas, utilizando la notación prefija . El primer elemento de la lista es el nombre de una función, el nombre de una macro, una expresión lambda o el nombre de un "operador especial" (véase más abajo). El resto de la lista son los argumentos. Por ejemplo, la función listdevuelve sus argumentos como una lista, por lo que la expresión
( lista 1 2 ( cita foo ))se evalúa a la lista . La "comilla" antes del en el ejemplo anterior es un "operador especial" que devuelve su argumento sin evaluarlo. Cualquier expresión sin comillas se evalúa recursivamente antes de que se evalúe la expresión que la contiene. Por ejemplo,(12foo)foo
( lista 1 2 ( lista 3 4 ))se evalúa a la lista . El tercer argumento es una lista; las listas pueden estar anidadas.(12(34))
Operadores
Los operadores aritméticos se tratan de forma similar. La expresión
( + 1 2 3 4 )se evalúa a 10. El equivalente en notación infija sería " ".1+2+3+4
Lisp no tiene el concepto de operadores tal como se implementa en los lenguajes derivados de ALGOL . Los operadores aritméticos en Lisp son funciones variádicas (o n-arias ), capaces de tomar cualquier número de argumentos. A veces se implementa un operador de incremento al estilo de C '++' bajo la incfsintaxis de nombre.
( incf x )equivalente a (setq x (+ x 1)), devolviendo el nuevo valor de x.
Los "operadores especiales" (a veces llamados "formas especiales") proporcionan la estructura de control de Lisp. Por ejemplo, el operador especial iftoma tres argumentos. Si el primer argumento no es nulo, se evalúa al segundo argumento; de lo contrario, se evalúa al tercer argumento. Por lo tanto, la expresión
( si es nulo ( lista 1 2 "foo" ) ( lista 3 4 "bar" ))se evalúa a . Por supuesto, esto sería más útil si se hubiera sustituido una expresión no trivial en lugar de .(34"bar")nil
Lisp también proporciona los operadores lógicos and , or y not . Los operadores and y or realizan una evaluación de cortocircuito y devolverán su primer argumento nulo y no nulo, respectivamente.
( o ( y "cero" nulo "nunca" ) "James" 'tarea 'tiempo )será evaluado como "James".
Expresiones lambda y definición de funciones
Otro operador especial, lambda, se utiliza para vincular variables a valores que luego se evalúan dentro de una expresión. Este operador también se utiliza para crear funciones: los argumentos de lambdason una lista de argumentos y la expresión o expresiones a las que se evalúa la función (el valor devuelto es el valor de la última expresión que se evalúa). La expresión
( lambda ( arg ) ( + arg 1 ))se evalúa como una función que, al aplicarse, toma un argumento, lo vincula argy devuelve el número uno mayor que ese argumento. Las expresiones lambda no se tratan de manera diferente a las funciones con nombre; se invocan de la misma manera. Por lo tanto, la expresión
(( lambda ( arg ) ( + arg 1 )) 5 )se evalúa como 6. Aquí, estamos haciendo una aplicación de función: ejecutamos la función anónima pasándole el valor 5.
Las funciones con nombre se crean almacenando una expresión lambda en un símbolo mediante la macro defun.
( defun foo ( a b c d ) ( + a b c d ))(defunf(a)b...)define una nueva función denominada fen el entorno global. Es conceptualmente similar a la expresión:
( setf ( fdefinition 'f ) #' ( lambda ( a ) ( block f b... )))donde setfes una macro utilizada para establecer el valor del primer argumento de un nuevo objeto de función. es una definición de función global para la función llamada . es una abreviatura de operador especial, que devuelve un objeto de función.fdefinition'ffdefinitionf#'function
Átomos
En el LISP original existían dos tipos de datos fundamentales : átomos y listas. Una lista era una secuencia finita y ordenada de elementos, donde cada elemento era un átomo o una lista, y un átomo era un número o un símbolo. Un símbolo era esencialmente un elemento con nombre único, escrito como una cadena alfanumérica en el código fuente , y utilizado como nombre de variable o como elemento de datos en el procesamiento simbólico . Por ejemplo, la lista contiene tres elementos: el símbolo , la lista y el número 2.(FOO(BAR1)2)FOO(BAR1)
Consecuencias y listas

Una lista de Lisp se implementa como una lista enlazada simple . [ 67 ] Cada celda de esta lista se llama cons (en Scheme, un par ) y está compuesta por dos punteros , llamados car y cdr . Estos son respectivamente equivalentes a los campos datay nextdiscutidos en el artículo lista enlazada .
De las muchas estructuras de datos que se pueden construir a partir de celdas cons, una de las más básicas se llama lista propia . Una lista propia es el nilsímbolo especial (lista vacía) o un cons en el que carapunta a un dato (que puede ser otra estructura cons, como una lista) y cdrapunta a otra lista propia.
Si un elemento dado se considera la cabeza de una lista enlazada, entonces su `car` apunta al primer elemento de la lista y su `cdr` apunta al resto de la lista. Por esta razón, las funciones ` carand` cdrtambién se denominan first`and` restcuando se hace referencia a elementos que forman parte de una lista enlazada (en lugar de, por ejemplo, un árbol).
Por lo tanto, una lista de Lisp no es un objeto atómico, como lo sería una instancia de una clase contenedora en C++ o Java. Una lista no es más que un conjunto de elementos enlazados. Una variable que hace referencia a una lista dada es simplemente un puntero al primer elemento de la lista. El recorrido de una lista se puede realizar mediante la operación `cdring` , es decir, utilizando `cdrs` sucesivos para visitar cada elemento de la lista, o bien mediante el uso de diversas funciones de orden superior para aplicar una función a una lista.
Debido a que las listas y los cons son tan comunes en los sistemas Lisp, es un error frecuente pensar que son las únicas estructuras de datos de Lisp. De hecho, casi todos los Lisp, excepto los más simples, tienen otras estructuras de datos, como vectores ( arrays ), tablas hash , estructuras, etc.
Las expresiones S representan listas.

Las expresiones S entre paréntesis representan estructuras de listas enlazadas. Hay varias maneras de representar la misma lista como una expresión S. Un cons se puede escribir en notación de par punteado como , donde es el car y el cdr. Una lista propia más larga podría escribirse en notación de par punteado. Esto se abrevia convencionalmente como en notación de lista . Una lista impropia [ nota 3 ] puede escribirse en una combinación de las dos, como para la lista de tres cons cuyo último cdr es (es decir, la lista en forma completamente especificada).(a.b)ab(a.(b.(c.(d.nil))))(abcd)(abc.d)d(a.(b.(c.d)))
Procedimientos de procesamiento de listas
Lisp proporciona numerosos procedimientos integrados para acceder y controlar listas. Las listas se pueden crear directamente con el listprocedimiento, que acepta cualquier número de argumentos y devuelve la lista de dichos argumentos.
( lista 1 2 'a 3 ) ;Salida: (1 2 a 3)( lista 1 ' ( 2 3 ) 4 ) ;Salida: (1 (2 3) 4)Debido a la forma en que se construyen las listas a partir de pares cons , el consprocedimiento se puede usar para agregar un elemento al principio de una lista. El consprocedimiento es asimétrico en el manejo de argumentos de lista, debido a la forma en que se construyen las listas.
( cons 1 ' ( 2 3 )) ;Salida: (1 2 3)( cons ' ( 1 2 ) ' ( 3 4 )) ;Salida: ((1 2) 3 4)El appendprocedimiento concatena dos (o más) listas. Dado que las listas de Lisp son listas enlazadas, concatenar dos listas tiene una complejidad temporal asintótica.
( agregar ' ( 1 2 ) ' ( 3 4 )) ;Salida: (1 2 3 4)( agregar ' ( 1 2 3 ) ' () ' ( a ) ' ( 5 6 )) ;Salida: (1 2 3 a 5 6)Estructura compartida
Las listas de Lisp, al ser listas enlazadas simples, pueden compartir estructura entre sí. Es decir, dos listas pueden tener la misma cola , o secuencia final de consejos. Por ejemplo, después de la ejecución del siguiente código Common Lisp:
( setf foo ( lista 'a 'b 'c )) ( setf bar ( cons 'x ( cdr foo )))Las listas fooy barson y respectivamente. Sin embargo, la cola tiene la misma estructura en ambas listas. No es una copia; las celdas cons que apuntan a y están en las mismas ubicaciones de memoria para ambas listas.(abc)(xbc)(bc)bc
Compartir la estructura en lugar de copiarla puede ofrecer una mejora drástica en el rendimiento. Sin embargo, esta técnica puede interactuar de forma indeseada con funciones que modifican las listas que se les pasan como argumentos. Modificar una lista, por ejemplo, reemplazando un elemento ccon otro goose, afectará a la otra:
( setf ( tercer foo ) 'ganso )Esto cambia fooa , pero por lo tanto también cambia a , un resultado posiblemente inesperado. Esto puede ser fuente de errores, y las funciones que modifican sus argumentos están documentadas como destructivas precisamente por esta razón.(abgoose)bar(xbgoose)
Los aficionados a la programación funcional evitan las funciones destructivas. En el dialecto Scheme, que favorece el estilo funcional, los nombres de las funciones destructivas se marcan con un signo de exclamación de advertencia, o "bang", como set-car!(léase set car bang ), que reemplaza el coche de un cons. En el dialecto Common Lisp, las funciones destructivas son comunes; el equivalente de set-car!se llama rplacapor "reemplazar coche". Sin embargo, esta función rara vez se ve, ya que Common Lisp incluye una facilidad especial, setf, para facilitar la definición y el uso de funciones destructivas. Un estilo frecuente en Common Lisp es escribir código funcionalmente (sin llamadas destructivas) al prototipar, y luego agregar llamadas destructivas como una optimización cuando sea seguro hacerlo.
Formularios de autoevaluación y cotización
Lisp evalúa las expresiones que introduce el usuario. Los símbolos y las listas se evalúan a alguna otra expresión (normalmente, más sencilla); por ejemplo, un símbolo se evalúa al valor de la variable que nombra; se evalúa a . Sin embargo, la mayoría de las demás formas se evalúan a sí mismas: si se introduce en Lisp, devuelve .(+23)555
Cualquier expresión también puede marcarse para evitar que se evalúe (como es necesario para los símbolos y las listas). Esta es la función del quoteoperador especial, o su abreviatura '(una comilla). Por ejemplo, normalmente si se introduce el símbolo foo, devuelve el valor de la variable correspondiente (o un error, si no existe dicha variable). Para referirse al símbolo literal, introduzca o, normalmente, .(quotefoo)'foo
Tanto Common Lisp como Scheme admiten el operador de comillas invertidas (denominado cuasicitación en Scheme), que se introduce con el `carácter ( comilla invertida ). Esto es casi igual que la comilla simple, excepto que permite evaluar expresiones y que sus valores se interpolen en una lista entre comillas con los operadores de empalme de coma y coma -at . Si la variable tiene el valor, se evalúa como , mientras que se evalúa como . Las comillas invertidas se utilizan con mayor frecuencia para definir expansiones de macros. [ 68 ] [ 69 ],,@snue(barbaz)`(foo,snue)(foo(barbaz))`(foo,@snue)(foobarbaz)
Las formas autoevaluables y las formas entre comillas son el equivalente a los literales en Lisp. Es posible modificar los valores de los literales (mutables) en el código del programa. Por ejemplo, si una función devuelve una forma entre comillas y el código que la llama modifica dicha forma, esto puede alterar el comportamiento de la función en invocaciones posteriores.
( defun debería-ser-constante () ' ( uno dos tres ))( let (( stuff ( should-be-constant ))) ( setf ( third stuff ) 'bizarro )) ; ¡mal!( debería ser constante ) ; devuelve (uno dos extraños)Modificar una cita de esta manera generalmente se considera un mal estilo y ANSI Common Lisp la define como errónea (lo que resulta en un comportamiento "indefinido" en los archivos compilados, porque el compilador de archivos puede fusionar constantes similares, colocarlas en memoria protegida contra escritura, etc.).
La formalización de la cita en Lisp ha sido señalada por Douglas Hofstadter (en Gödel, Escher, Bach ) y otros como un ejemplo de la idea filosófica de autorreferencia .
Alcance y conclusión
La familia Lisp se divide en cuanto al uso del ámbito dinámico o estático (también conocido como ámbito léxico) . Clojure, Common Lisp y Scheme utilizan el ámbito estático por defecto, mientras que newLISP , Picolisp y los lenguajes integrados en Emacs y AutoCAD utilizan el ámbito dinámico. Desde la versión 24.1, Emacs utiliza ambos tipos de ámbito.
Estructura de lista del código del programa; explotación mediante macros y compiladores.
Una distinción fundamental entre Lisp y otros lenguajes es que, en Lisp, la representación textual de un programa es simplemente una descripción legible para humanos de las mismas estructuras de datos internas (listas enlazadas, símbolos, números, caracteres, etc.) que utilizaría el sistema Lisp subyacente.
Lisp utiliza esto para implementar un sistema de macros muy potente. Al igual que otros lenguajes de macros, como el definido por el preprocesador de C (el preprocesador de macros para los lenguajes de programación C++ , Objective-C y C++ ), una macro devuelve código que luego se puede compilar. Sin embargo, a diferencia de las macros del preprocesador de C, las macros son funciones de Lisp y, por lo tanto, pueden aprovechar todo el potencial de Lisp.
Además, dado que el código Lisp tiene la misma estructura que las listas, se pueden crear macros con cualquiera de las funciones de procesamiento de listas del lenguaje. En resumen, todo lo que Lisp puede hacer con una estructura de datos, las macros de Lisp pueden hacerlo con el código. En cambio, en la mayoría de los demás lenguajes, la salida del analizador sintáctico es puramente interna a la implementación del lenguaje y el programador no puede manipularla.
Esta característica facilita el desarrollo de lenguajes eficientes dentro de otros lenguajes. Por ejemplo, el Sistema de Objetos de Common Lisp se puede implementar de forma limpia como una extensión del lenguaje mediante macros. Esto significa que si una aplicación necesita un mecanismo de herencia diferente, puede usar un sistema de objetos distinto. Esto contrasta notablemente con la mayoría de los demás lenguajes; por ejemplo, Java no admite la herencia múltiple y no existe una forma razonable de añadirla.
En las implementaciones más sencillas de Lisp, esta estructura de lista se interpreta directamente para ejecutar el programa; una función es, literalmente, un fragmento de la estructura de lista que el intérprete recorre durante su ejecución. Sin embargo, la mayoría de los sistemas Lisp más complejos también incluyen un compilador. El compilador traduce la estructura de lista a código máquina o bytecode para su ejecución. Este código puede ejecutarse tan rápido como el código compilado en lenguajes convencionales como C.
Las macros se expanden antes del paso de compilación y, por lo tanto, ofrecen algunas opciones interesantes. Si un programa necesita una tabla precalculada, una macro podría crearla en tiempo de compilación, de modo que el compilador solo tendría que generar la tabla y no tendría que llamar a código para crearla en tiempo de ejecución. Algunas implementaciones de Lisp incluso tienen un mecanismo eval-whenque permite que el código esté presente durante el tiempo de compilación (cuando una macro lo necesitaría), pero no en el módulo generado. [ 70 ]
Evaluación y el ciclo de lectura-evaluación-impresión
Los lenguajes Lisp se utilizan a menudo con una línea de comandos interactiva , que puede combinarse con un entorno de desarrollo integrado (IDE). El usuario introduce expresiones en la línea de comandos o le indica al IDE que las transmita al sistema Lisp. Lisp lee las expresiones introducidas, las evalúa e imprime el resultado. Por este motivo, la línea de comandos de Lisp se denomina bucle de lectura-evaluación-impresión ( REPL ).
El funcionamiento básico del REPL es el siguiente. Esta es una descripción simplificada que omite muchos elementos de un Lisp real, como las comillas y las macros.
La readfunción acepta expresiones S textuales como entrada y las analiza para convertirlas en una estructura de datos interna. Por ejemplo, si escribe el texto en la línea de comandos, lo traduce en una lista enlazada con tres elementos: el símbolo , el número 1 y el número 2. Resulta que esta lista también es un fragmento de código Lisp válido; es decir, se puede evaluar. Esto se debe a que el elemento de la lista nombra una función: la operación de suma.(+12)read+
A foose leerá como un solo símbolo. 123se leerá como el número ciento veintitrés. "123"se leerá como la cadena "123".
La evalfunción evalúa los datos y devuelve cero o más datos Lisp como resultado. La evaluación no tiene por qué significar interpretación; algunos sistemas Lisp compilan cada expresión a código máquina nativo. Sin embargo, es sencillo describir la evaluación como interpretación: para evaluar una lista cuyo nombre de función es, evalprimero se evalúan todos los argumentos dados en su cdr y luego se aplica la función a los argumentos. En este caso, la función es la suma, y al aplicarla a la lista de argumentos se obtiene la respuesta . Este es el resultado de la evaluación.(12)3
El símbolo foose evalúa al valor del símbolo foo. Los datos como la cadena "123" se evalúan a la misma cadena. La lista se evalúa a la lista (1 2 3).(quote(123))
La printfunción se encarga de mostrar el resultado al usuario. Para un resultado sencillo como 3este, es trivial. Una expresión que se evalúa como una lista requeriría printrecorrerla e imprimirla como una expresión S.
Para implementar un REPL de Lisp, solo es necesario implementar estas tres funciones y una función de bucle infinito. (Naturalmente, la implementación de evalserá compleja, ya que también debe implementar todos los operadores especiales como ifo lambda.) Hecho esto, un REPL básico es una línea de código: .(loop(print(eval(read))))
La consola interactiva de Lisp también suele proporcionar edición de entrada, un historial de entrada, manejo de errores y una interfaz para el depurador.
Lisp se evalúa generalmente de forma inmediata . En Common Lisp , los argumentos se evalúan en orden aplicativo (del más a la izquierda al más interno), mientras que en Scheme el orden de los argumentos no está definido, lo que deja margen para la optimización por parte del compilador.
Estructuras de control
Lisp originalmente tenía muy pocas estructuras de control, pero se añadieron muchas más durante la evolución del lenguaje. (El operador condicional original de Lisp, cond, es el precursor de if-then-elseestructuras posteriores).
Los programadores en el dialecto Scheme a menudo expresan bucles usando recursión de cola . La frecuencia de Scheme en la informática académica ha llevado a algunos estudiantes a creer que la recursión de cola es la única, o la más común, forma de escribir iteraciones en Lisp, pero esto es incorrecto. Todos los dialectos Lisp que se ven con frecuencia tienen construcciones de iteración de estilo imperativo, desde el dobucle de Scheme hasta las expresiones complejas de Common Lisploop . Además, el problema clave que hace que esto sea un asunto objetivo en lugar de subjetivo es que Scheme establece requisitos específicos para el manejo de llamadas de cola , y por lo tanto la razón por la que el uso de la recursión de cola generalmente se fomenta para Scheme es que la práctica está expresamente respaldada por la definición del lenguaje. Por el contrario, ANSI Common Lisp no requiere [ 71 ] la optimización comúnmente denominada eliminación de llamadas de cola. Por lo tanto, el hecho de que el estilo recursivo de cola como reemplazo casual del uso de construcciones de iteración más tradicionales (como do, dolisto loop) se desaconseje [ 72 ] en Common Lisp no es solo una cuestión de preferencia estilística, sino potencialmente una cuestión de eficiencia (ya que una llamada de cola aparente en Common Lisp puede no compilarse como un salto simple ) y corrección del programa (ya que la recursión de cola puede aumentar el uso de la pila en Common Lisp, arriesgando un desbordamiento de pila ).
Algunas estructuras de control de Lisp son operadores especiales , equivalentes a las palabras clave sintácticas de otros lenguajes. Las expresiones que utilizan estos operadores tienen la misma apariencia superficial que las llamadas a funciones, pero se diferencian en que los argumentos no necesariamente se evalúan o, en el caso de una expresión de iteración, pueden evaluarse más de una vez.
A diferencia de la mayoría de los demás lenguajes de programación importantes, Lisp permite implementar estructuras de control utilizando el propio lenguaje. Varias estructuras de control se implementan como macros de Lisp, e incluso el programador que desee comprender su funcionamiento puede ampliarlas mediante macros.
Tanto Common Lisp como Scheme cuentan con operadores para el control de flujo no local. Las diferencias en estos operadores constituyen algunas de las diferencias más profundas entre ambos dialectos. Scheme admite continuaciones reentrantes mediante un call/ccprocedimiento que permite a un programa guardar (y posteriormente restaurar) un punto específico de la ejecución. Common Lisp no admite continuaciones reentrantes, pero sí ofrece varias formas de gestionar las continuaciones de escape.
A menudo, un mismo algoritmo puede expresarse en Lisp tanto en estilo imperativo como funcional. Como se mencionó anteriormente, Scheme tiende a favorecer el estilo funcional, utilizando recursión de cola y continuaciones para expresar el flujo de control. Sin embargo, el estilo imperativo sigue siendo perfectamente posible. El estilo preferido por muchos programadores de Common Lisp puede resultar más familiar para quienes están acostumbrados a lenguajes estructurados como C, mientras que el preferido por los programadores de Scheme se asemeja más a lenguajes puramente funcionales como Haskell .
Debido a su origen en el procesamiento de listas, Lisp cuenta con una amplia gama de funciones de orden superior relacionadas con la iteración sobre secuencias. En muchos casos donde se necesitaría un bucle explícito en otros lenguajes (como un forbucle en C), en Lisp la misma tarea se puede realizar con una función de orden superior. (Lo mismo ocurre con muchos lenguajes de programación funcional).
Un buen ejemplo es una función que en Scheme se llama mapy en Common Lisp se llama mapcar. Dada una función y una o más listas, mapcaraplica la función sucesivamente a los elementos de las listas en orden, recopilando los resultados en una nueva lista:
( mapacar #' + ' ( 1 2 3 4 5 ) ' ( 10 20 30 40 50 ))Esto aplica la +función a cada par correspondiente de elementos de la lista, obteniendo el resultado .(1122334455)
Ejemplos
Aquí tenéis ejemplos de código Common Lisp.
El programa básico " ¡Hola, mundo! "
( imprimir "¡Hola, mundo!" )La sintaxis de Lisp se presta naturalmente a la recursión. Problemas matemáticos como la enumeración de conjuntos definidos recursivamente son sencillos de expresar en esta notación. Por ejemplo, para calcular el factorial de un número :
( defun factorial ( n ) ( if ( zerop n ) 1 ( * n ( factorial ( 1- n )))))Una implementación alternativa ocupa menos espacio en la pila que la versión anterior si el sistema Lisp subyacente optimiza la recursión de cola :
( defun factorial ( n &optional ( acc 1 )) ( if ( zerop n ) acc ( factorial ( 1- n ) ( * acc n ))))Contrasta los ejemplos anteriores con una versión iterativa que utiliza la macro de Common Lisploop :
( defun factorial ( n ) ( loop for i from 1 to n for fac = 1 then ( * fac i ) finally ( return fac )))La siguiente función invierte una lista. (La función `reverse` integrada de Lisp hace lo mismo).
( defun -reverse ( lista ) ( let (( valor-de-retorno )) ( dolist ( e lista ) ( push e valor-de-retorno )) valor-de-retorno ))Sistemas de objetos
Se han construido varios sistemas y modelos de objetos sobre, junto a o dentro de Lisp, incluyendo:
- El Sistema de Objetos de Common Lisp (CLOS) es una parte integral de ANSI Common Lisp. CLOS deriva de New Flavors y CommonLOOPS. ANSI Common Lisp fue el primer lenguaje de programación orientado a objetos estandarizado (1994, ANSI X3J13).
- ObjectLisp [ 73 ] u Object Lisp , utilizado por Lisp Machines Incorporated y las primeras versiones de Macintosh Common Lisp.
- LOOPS (Sistema de Programación Orientada a Objetos Lisp) y posteriormente CommonLoops
- Flavors , creado en el MIT , y su sucesor New Flavors (desarrollado por Symbolics ).
- KR (abreviatura de Knowledge Representation), un sistema de objetos basado en restricciones desarrollado para ayudar a escribir Garnet, una biblioteca GUI para Common Lisp .
- El entorno de ingeniería del conocimiento (KEE) utilizó un sistema de objetos llamado UNITS y lo integró con un motor de inferencia [ 74 ] y un sistema de mantenimiento de la verdad (ATMS).
Sistemas operativos
Varios sistemas operativos , incluidos los sistemas basados en lenguajes , se basan en Lisp (utilizan características, convenciones, métodos, estructuras de datos, etc. de Lisp) o están escritos en Lisp, [ 75 ] incluyendo:
Genera , renombrado Open Genera, [ 76 ] por Symbolics ; Medley, escrito en Interlisp, originalmente una familia de sistemas operativos gráficos que se ejecutaban en las estaciones de trabajo Star posteriores de Xerox ; [ 77 ] [ 78 ] Mezzano; [ 79 ] Interim; [ 80 ] [ 81 ] ChrysaLisp, [ 82 ] por los desarrolladores de TAOS de Tao Systems; [ 83 ] y también el sistema Guix para GNU/Linux.
Véase también
Notas a pie de página
- ↑ En aquel entonces, Fortran tenía una estructura if-then-else que aceptaba números de línea como destinos de salto, al estilo de una instrucción Goto , en lugar de aceptar expresiones arbitrarias en los bloques "then" y "else".
- ↑ Common Lisp:
(defun f (x) x)Esquema:(define f (lambda (x) x))o(define (f x) x) - ↑ NB: una llamada "lista punteada" es solo un tipo de "lista impropia". El otro tipo es la "lista circular" donde las celdas cons forman un bucle. Normalmente, esto se representa usando
#n=(...)para representar la celda cons de destino que tendrá múltiples referencias, y#n#se usa para referirse a esta cons. Por ejemplo,(#1=(a b) . #1#)normalmente se imprimiría como((a b) a b)(sin la impresión de estructura circular habilitada), pero hace clara la reutilización de la celda cons.#1=(a . #1#)normalmente no se puede imprimir ya que es circular, aunque(a...)a veces se muestra, el CDR de la celda cons definida por#1=es ella misma.
Referencias
- ↑ "Introducción" . El manual de Julia . Lea la documentación. Archivado del original el 8 de abril de 2016. Consultado el 10 de diciembre de 2016 .
- ↑ "Preguntas y respuestas sobre el lenguaje Wolfram" . Wolfram Research . Consultado el 10 de diciembre de 2016 .
- ↑ Edwin D. Reilly (2003). Hitos en informática y tecnología de la información . Greenwood Publishing Group. págs. 156–157 . ISBN 978-1-57356-521-9.
- ↑ "SICP: Prólogo" . Archivado del original el 27 de julio de 2001.
Lisp es un lenguaje que ha sobrevivido, habiéndose utilizado durante aproximadamente un cuarto de siglo. Entre los lenguajes de programación activos, solo Fortran ha tenido una vida más larga.
- ↑ "Conclusiones" . Archivado del original el 3 de abril de 2014. Consultado el 4 de junio de 2014 .
- ↑ Steele, Guy L. (1990). Common Lisp: el lenguaje (2.ª ed.). Bedford, MA: Digital Press. ISBN 1-55558-041-6OCLC 20631879
- ^ Felleisen, Matías; Findler, Robert; Flatt, Mateo; Krishnamurthi, Shriram; Barzilay, Eli; McCarthy, Jay; Tobin-Hochstadt, Sam (2015). ""El manifiesto del crimen organizado"" (PDF) .
- ↑ "Clojure - Diferencias con otros Lisp" . clojure.org . Consultado el 27 de octubre de 2022 .
- ↑ Steele, Guy Lewis; Sussman, Gerald Jay (mayo de 1978). "El arte del intérprete, o el complejo de modularidad (partes cero, uno y dos), parte cero, pág. 4" . Bibliotecas del MIT. hdl : 1721.1/6094 . Consultado el 1 de agosto de 2020 .
- ↑ Hofstadter, Douglas R. (1999) [1979], Gödel, Escher, Bach: Una eterna trenza dorada (Edición del vigésimo aniversario) , Basic Books, pág. 292, ISBN 0-465-02656-7
Uno de los lenguajes de programación más importantes y fascinantes es LISP (acrónimo de "List Processing", que significa "Procesamiento de Listas"), inventado por John McCarthy casi al mismo tiempo que Algol. Posteriormente, LISP ha gozado de gran popularidad entre los investigadores de Inteligencia Artificial
. - ↑ Paul Graham. "La venganza de los nerds" . Consultado el 14 de marzo de 2013 .
- ↑ Chisnall, David (2011-01-12). Lenguajes de programación influyentes, parte 4: Lisp .
- ↑ Jones, Robin; Maynard, Clive; Stewart, Ian (6 de diciembre de 2012). El arte de la programación en Lisp . Springer Science & Business Media. pág. 2. ISBN 9781447117193.
- 1 2 3 4 McCarthy, John; Wexelblat, Richard L. (1978). Historia de los lenguajes de programación . Association for Computing Machinery. págs. 173–183 . ISBN 0127450408.
- ↑ Smith, David Canfield. Manual de usuario de MLISP (PDF) . Consultado el 13 de octubre de 2006 .
- ↑ McCarthy, John (12 de febrero de 1979). "Historia de Lisp: Laboratorio de Inteligencia Artificial" (PDF) .
- ↑ Stoyan, Herbert (6 de agosto de 1984). Historia temprana de LISP (1956–1959) . LFP '84: Actas del Simposio ACM de 1984 sobre LISP y programación funcional. Association for Computing Machinery . pág. 307. doi : 10.1145/800055.802047 .
- ↑ McCarthy, John. "Prehistoria de LISP: verano de 1956 a verano de 1958" . Consultado el 14 de marzo de 2010 .
- ↑ McCarthy, John (1960). "Funciones recursivas de expresiones simbólicas y su cálculo por máquina, Parte I" . Communications of the ACM . 3 (4). Asociación para la maquinaria informática: 184–195 . doi : 10.1145/367177.367199 . Consultado el 28 de febrero de 2025 .
- ↑ McCarthy, John. "Funciones recursivas de expresiones simbólicas y su cálculo por máquina, parte I" . Archivado del original el 4 de octubre de 2013. Consultado el 13 de octubre de 2006 .
- ↑ Hart, Tim; Levin, Mike. "AI Memo 39-The new compiler" (PDF) . Archivado del original (PDF) el 6 de julio de 2017. Consultado el 18 de marzo de 2019 .
- ↑ McCarthy, John; Abrahams, Paul W.; Edwards, Daniel J.; Hart, Timothy P.; Levin, Michael I. (1985) [1962]. Manual del programador de LISP 1.5 (PDF) . 15.ª impresión (2.ª ed.). p. Prefacio.
- ↑ El tamaño de palabra de 36 bits del PDP-6 / PDP-10 fue influenciado por la utilidad de tener dos punteros Lisp de 18 bits en una sola palabra. Peter J. Hurley (18 de octubre de 1990). "La historia de TOPS o la vida en los AC rápidos" . Grupo de noticias : alt.folklore.computers . Usenet: 84950@tut.cis.ohio-state.edu .
El proyecto PDP-6 comenzó a principios de 1963, como una máquina de 24 bits. Creció a 36 bits para LISP, un objetivo de diseño.
- ↑ Steele, Guy L.; Gabriel, Richard P. (enero de 1996), "La evolución de Lisp", en Bergin, Thomas J.; Gibson, Richard G. (eds.), Historia de los lenguajes de programación---II , Nueva York, NY, EE. UU.: ACM, pp. 233–330 , doi : 10.1145/234286.1057818 , ISBN 978-0-201-89502-5
- ↑ McCarthy, J .; Brayton, R.; Edwards, D.; Fox, P .; Hodes, L .; Luckham, D .; Maling, K.; Park, D .; Russell, S. (marzo de 1960). Manual del programador de LISP I (PDF) . Boston: Grupo de Inteligencia Artificial, Centro de Computación y Laboratorio de Investigación del MIT. Archivado del original (PDF) el 17 de julio de 2010.Consultado el 11 de mayo de 2010.
- ↑ McCarthy, John; Abrahams, Paul W.; Edwards, Daniel J.; Hart, Timothy P.; Levin, Michael I. (1985) [1962]. Manual del programador de LISP 1.5 (PDF) (2.ª ed.). MIT Press . ISBN 0-262-13011-4.
- ↑ Quam, Lynn H.; Diffle, Whitfield. Manual de Stanford LISP 1.6 (PDF) .
- ↑ "Manual de referencia de Maclisp" . 3 de marzo de 1979. Archivado del original el 14 de diciembre de 2007.
- ↑ Teitelman, Warren (1974). Manual de referencia de InterLisp (PDF) . Archivado del original (PDF) el 2 de junio de 2006. Consultado el 19 de agosto de 2006 .
- ^ Herramientas de generación de interfaces : estado del arte y clasificación por H. El Mrabet
- ↑ Gerald Jay Sussman y Guy Lewis Steele Jr. (diciembre de 1975). "Scheme: un intérprete para el cálculo lambda extendido" (PDF) . MIT AI Lab . AIM-349 . Consultado el 23 de diciembre de 2021 .
- ↑ Steele, Guy L. Jr. (1990). "Propósito" . Common Lisp the Language (2.ª ed.). Digital Press. ISBN 0-13-152414-3.
- ↑ Kantrowitz, Mark; Margolin, Barry (20 de febrero de 1996). "Historia: ¿De dónde viene Lisp?" . Preguntas frecuentes: Preguntas frecuentes sobre Lisp 2/7 .
- ↑ "ISO/IEC 13816:1997" . Iso.org. 1 de octubre de 2007. Consultado el 15 de noviembre de 2013 .
- ↑ "ISO/IEC 13816:2007" . Iso.org. 30 de octubre de 2013. Consultado el 15 de noviembre de 2013 .
- ↑ "Carta X3J13" .
- ↑ "Encuesta sobre el camino hacia Lisp" . Archivado del original el 4 de octubre de 2006. Consultado el 13 de octubre de 2006 .
- ↑ "Tendencias para el futuro" . Faqs.org. Archivado del original el 3 de junio de 2013. Consultado el 15 de noviembre de 2013 .
- ↑ Weinreb, Daniel. "Implementaciones de Common Lisp: una revisión" . Archivado del original el 21 de abril de 2012. Consultado el 4 de abril de 2012 .
- ↑ "Planet Lisp" . Consultado el 12 de octubre de 2023 .
- ↑ "LispForum" . Consultado el 12 de octubre de 2023 .
- ↑ "Lispjobs" . Consultado el 12 de octubre de 2023 .
- ↑ "Quicklisp" . Consultado el 12 de octubre de 2023 .
- ↑ «LISP50@OOPSLA» . Lisp50.org . Consultado el 15 de noviembre de 2013 .
- ↑ Documentos: Estándares: R5RS . schemers.org (11 de enero de 2012). Consultado el 17 de julio de 2013.
- ↑ "Por qué el MIT ahora usa Python en lugar de Scheme para su programa de pregrado en Ciencias de la Computación" . cemerick.com . 24 de marzo de 2009. Archivado del original el 17 de septiembre de 2010. Consultado el 10 de noviembre de 2013 .
- ↑ Broder, Evan (8 de enero de 2008). "El fin de una era" . mitadmissions.org . Consultado el 10 de noviembre de 2013 .
- ↑ "Programas de pregrado de EECS del MIT" . www.eecs.mit.edu . Ingeniería Eléctrica e Informática del MIT . Consultado el 31 de diciembre de 2018 .
- ↑ "El curso introductorio de Python de MITx alcanza los 1,2 millones de inscripciones" . MIT EECS . Ingeniería Eléctrica e Informática del MIT. Archivado del original el 25 de febrero de 2021. Consultado el 31 de diciembre de 2018 .
- ↑ Capítulo 1.1.2, Historia, Norma ANSI CL
- ↑Clasp es una implementación de Common Lisp que interactúa con C++ y utiliza LLVM para la compilación justo a tiempo (JIT) a código nativo.
- ↑"Armed Bear Common Lisp (ABCL) es una implementación completa del lenguaje Common Lisp que incluye tanto un intérprete como un compilador, y se ejecuta en la JVM".
- ↑Archivado el 22/06/2018 en Wayback Machine Implementaciones de Common Lisp: Un estudio
- ↑Comparación de implementaciones de Common Lisp en desarrollo activo
- ↑ Un análisis en profundidad de las colecciones de Clojure , consultado el 24 de junio de 2012.
- ↑ "Clojure rational" . Consultado el 27 de agosto de 2019.
Clojure es un Lisp que no está restringido por la compatibilidad con versiones anteriores
. - ↑ Script-fu en GIMP 2.4 , consultado el 29/10/2009
- ↑ librep en Sawfish Wikia, consultado el 29/10/2009
- ↑ "IEEE Scheme" . IEEE 1178-1990 - Norma IEEE para el lenguaje de programación Scheme . Consultado el 27 de agosto de 2019 .
- ↑ Paul Graham (mayo de 2002). "Lo que hizo diferente a Lisp" .
- ↑ "Prehistoria de LISP: verano de 1956 a verano de 1958" .
Inventé expresiones condicionales en relación con un conjunto de rutinas de movimientos legales de ajedrez que escribí en FORTRAN para el IBM 704 en el MIT durante 1957-58
... Un artículo que definía expresiones condicionales y proponía su uso en Algol fue enviado a Communications of the ACM, pero fue degradado arbitrariamente a una carta al editor, porque era muy corto.
- ↑ "Significado de 'Programación Orientada a Objetos' según el Dr. Alan Kay" . 23/07/2003.
En aquel entonces no entendía la idea monstruosa de LISP sobre el metalenguaje tangible, pero me acerqué un poco con las ideas sobre lenguajes extensibles
... La segunda fase fue finalmente comprender LISP y luego usar ese conocimiento para crear subestructuras mucho más agradables, pequeñas, potentes y con enlace tardío
... Para mí, la POO significa solo mensajería, retención local, protección y ocultación del estado del proceso, y enlace tardío extremo de todo. Se puede hacer en Smalltalk y en LISP. Posiblemente haya otros sistemas en los que esto sea posible, pero no los conozco.
- ↑ Lieberman, Henry; Hewitt, Carl (junio de 1983), "Un recolector de basura en tiempo real basado en la vida útil de los objetos" , Communications of the ACM , 26 (6): 419–429 , CiteSeerX 10.1.1.4.8633 , doi : 10.1145/358141.358147 , hdl : 1721.1/6335 , S2CID 14161480
- ↑ Edsger W. Dijkstra (1972), El programador humilde (EWD 340)(Conferencia del Premio Turing de la ACM).
- ↑ "Una mirada a Clojure y el resurgimiento de Lisp" .
- ↑ "The Jargon File - Lisp" . Consultado el 13 de octubre de 2006 .
- ^ Sebesta, Robert W. (2012). ""2.4 Programación funcional: LISP";"6.9 Tipos de listas";"15.4 El primer lenguaje de programación funcional: LISP"« Conceptos de lenguajes de programación (impreso) (10.ª ed.). Boston, MA, EE. UU.: Addison-Wesley. págs. 47–52 , 281–284 , 677–680 . ISBN 978-0-13-139531-2.
- ↑ "CSE 341: Scheme: Quote, Quasiquote, and Metaprogramming" . University of Washington Computer Science & Engineering. Invierno de 2004. Consultado el 15 de noviembre de 2013 .
- ↑ Bawden, Alan. "Quasiquotation in Lisp" (PDF) . Archivado del original (PDF) el 3 de junio de 2013.
- ↑ " Tiempo de evaluación (extensiones de Common Lisp) ". GNU. Consultado el 17 de julio de 2013.
- ↑ 3.2.2.3 Restricciones semánticas en Common Lisp HyperSpec
- ↑ 4.3. Abstracción de control (recursión frente a iteración) en Tutorial sobre buen estilo de programación en Lisp por Kent Pitman y Peter Norvig , agosto de 1993.
- ↑ pág. 17 de Bobrow 1986
- ↑ Veitch, pág. 108, 1988
- ↑ Proven, Liam (29 de marzo de 2022). "El salvaje mundo de los sistemas operativos que no son C" . The Register . Consultado el 4 de abril de 2024 .
- ↑ "Symbolics Open Genera 2.0" . Archivo de Internet de GitHub . 7 de enero de 2020. Consultado el 2 de febrero de 2022 .
- ↑ "Proyecto Interlisp.org" . Interlisp.org . 15 de marzo de 2022. Consultado el 2 de febrero de 2022 .
- ↑ "Interlisp Medley" . GitHub . Marzo de 2022. Consultado el 2 de febrero de 2022 .
- ↑ froggey (1 de agosto de 2021). "Mezzano" . GitHub . Consultado el 2 de febrero de 2022 .
- ↑ Hartmann, Lukas F. (10 de septiembre de 2015). "Interim" . Interim-os . Recuperado el 2 de febrero de 2022 .
- ↑ Hartmann, Lukas F. (11 de junio de 2021). "Interim" . GitHub . Recuperado el 2 de febrero de 2022 .
- ↑ Hinsley, Chris (23 de febrero de 2022). "ChrysaLisp" . GitHub . Recuperado el 2 de febrero de 2022 .
- ↑ Smith, Tony (21 de agosto de 2013). "El pionero británico de la microtecnología, Chris Shelton: La mente detrás del Nascom 1" . The Register . Consultado el 2 de febrero de 2022 .
Lecturas adicionales
- McCarthy, John (1979-02-12). "La implementación de Lisp" . Historia de Lisp . Universidad de Stanford . Recuperado el 17 de octubre de 2008 .
- Steele, Jr., Guy L.; Richard P. Gabriel (1993). La evolución de Lisp (PDF) . Segunda conferencia ACM SIGPLAN sobre la historia de los lenguajes de programación. Nueva York, NY: ACM. pp. 231–270 . ISBN 0-89791-570-4Archivado del original (PDF) el 12 de octubre de 2006. Consultado el 17 de octubre de 2008 .
- Veitch, Jim (1998). «Historia y descripción de CLOS». En Salus, Peter H. (ed.). Manual de lenguajes de programación . Vol. IV, Lenguajes de programación funcional y lógica (1.ª ed.). Indianápolis, IN: Macmillan Technical Publishing. pp. 107–158 . ISBN 1-57870-011-6.
- Abelson, Harold ; Sussman, Gerald Jay ; Sussman, Julie (1996). Estructura e interpretación de programas informáticos (2.ª ed.). MIT Press. ISBN 0-262-01153-0.
- Mis experiencias con Lisp y el desarrollo de GNU Emacs , transcripción del discurso de Richard Stallman , 28 de octubre de 2002, en la Conferencia Internacional de Lisp.
- Graham, Paul (2004). Hackers y pintores. Grandes ideas de la era informática . O'Reilly. ISBN 0-596-00662-4.
- Berkeley, Edmund C.; Bobrow , Daniel G. , eds. (marzo de 1964). El lenguaje de programación LISP: su funcionamiento y aplicaciones (PDF) . Cambridge, Massachusetts: MIT Press.
- Artículo basado en gran medida en el capítulo LISP - Una introducción sencilla : Berkeley, Edmund C. (septiembre de 1964). "El lenguaje de programación Lisp: una introducción y evaluación" . Computers and Automation : 16-23 .
- Weissman, Clark (1967). LISP 1.5 Primer (PDF) . Belmont, California: Dickenson Publishing Company Inc.
Enlaces externos
- Historia
- Historia de Lisp – Historia de John McCarthy del 12 de febrero de 1979
- Historia del Lisp : la historia de Herbert Stoyan, recopilada a partir de los documentos (reconocida por McCarthy como más completa que la suya propia; véase: enlaces a la historia de McCarthy ).
- Historia de LISP en el Museo de Historia de la Computación
- Bell, Adam Gordon (2 de mayo de 2022). LISP en el espacio, con Ron Garret . CoRecursive (podcast, transcripción, fotos).sobre el uso del software LISP en los robots de la NASA .
- Cassel, David (22 de mayo de 2022). "Un programador de la NASA recuerda haber depurado Lisp en el espacio profundo" . The New Stack .
- Asociaciones y reuniones
- Asociación de Usuarios de Lisp
- Reunión Europea de Lisp Común
- Simposio Europeo de Lisp
- Conferencia Internacional de Lisp
- Libros y tutoriales
- Cómo lanzar SPELs en Lisp : un tutorial introductorio al estilo de un cómic.
- Sobre Lisp , un libro gratuito de Paul Graham
- Lisp práctico , edición gratuita de Peter Seibel
- Lisp para la web
- Tierra de Lisp
- Deja pasar Lambda
- Entrevistas
- Entrevista de historia oral con John McCarthy en el Instituto Charles Babbage de la Universidad de Minnesota, Minneapolis. McCarthy habla sobre su papel en el desarrollo del tiempo compartido en el Instituto Tecnológico de Massachusetts (MIT). También describe su trabajo en inteligencia artificial (IA), financiado por la Agencia de Proyectos de Investigación Avanzada (ARPA), incluyendo la IA basada en lógica (LISP) y la robótica.
- Entrevista con Richard P. Gabriel (Podcast)
- Recursos
- CLiki: la wiki de Common Lisp
- El directorio de Common Lisp (a través de Wayback Machine ; archivado desde el original )
- Índice de preguntas frecuentes sobre Lisp
- lisppaste Archivado el 9 de junio de 2021 en Wayback Machine
- Planeta Lisp
- Noticias semanales de Lisp
- newLISP: un lenguaje de scripting moderno y de propósito general.
- Lisp Semanal
- Lisp (lenguaje de programación)
- Lenguajes de programación académica
- Inventos estadounidenses
- Lenguajes de programación de tipado dinámico
- Lenguajes de programación con sintaxis extensible
- Lenguajes funcionales
- Familia de lenguajes de programación Lisp
- Lenguajes de programación
- Lenguajes de programación creados en 1958