resueltos listas imprimir ejercicios ejemplos basicos autolisp lisp

listas - lisp pdf



¿Cómo te deja Lisp redefinir el lenguaje en sí? (7)

He oído que Lisp te permite redefinir el idioma en sí, y he tratado de investigarlo, pero no hay una explicación clara en ninguna parte. ¿Alguien tiene un ejemplo simple?


Buen ejemplo en http://www.cs.colorado.edu/~ralex/papers/PDF/X-expressions.pdf

las macros de lector definen expresiones X para que coexistan con expresiones S, por ejemplo,

? (cx <circle cx="62" cy="135" r="20"/>) 62

plain plain Common Lisp en http://www.AgentSheets.com/lisp/XMLisp/XMLisp.lisp ...

(eval-when (:compile-toplevel :load-toplevel :execute) (when (and (not (boundp ''*Non-XMLISP-Readtable*)) (get-macro-character #/<)) (warn "~%XMLisp: The current *readtable* already contains a #/< reader function: ~A" (get-macro-character #/<))))

... por supuesto, el analizador XML no es tan simple, pero sí lo es conectarlo al lector de lisp.


Desde el exterior, mirando en ...

Siempre pensé que era porque Lisp proporcionaba, en su núcleo, operadores lógicos básicos, atómicos, que cualquier proceso lógico se puede construir (y se ha creado y proporcionado como conjuntos de herramientas y complementos) a partir de los componentes básicos.

No es tanto que pueda redefinirse a sí mismo, ya que su definición básica es tan maleable que puede tomar cualquier forma y que no se asume / presume ninguna forma en la estructura.

Como metáfora, si solo tienes compuestos orgánicos, haz química orgánica, si solo tienes óxidos metálicos, haz metalurgia, pero si solo tienes elementos, puedes hacer de todo, pero tienes pasos iniciales adicionales para completar ... la mayoría de los otros ya lo he hecho por ti ....

Creo.....


Esta respuesta se refiere específicamente a Common Lisp (CL a continuación), aunque partes de la respuesta pueden aplicarse a otros idiomas en la familia de lisp.

Como CL usa expresiones S y (principalmente) parece una secuencia de aplicaciones de funciones, no hay una diferencia obvia entre las integradas y el código de usuario. La principal diferencia es que "las cosas que proporciona el lenguaje" están disponibles en un paquete específico dentro del entorno de codificación.

Con un poco de cuidado, no es difícil codificar reemplazos y usarlos en su lugar.

Ahora, el lector "normal" (la parte que lee el código fuente y lo convierte en notación interna) espera que el código fuente esté en un formato bastante específico (expresiones S entre paréntesis), pero como el lector es impulsado por algo llamado "lectura- tablas "y estos pueden ser creados y modificados por el desarrollador, también es posible cambiar la apariencia del código fuente.

Estas dos cosas deberían al menos proporcionar alguna justificación de por qué Common Lisp puede considerarse un lenguaje de programación reprogramable. No tengo un ejemplo simple a mano, pero tengo una implementación parcial de una traducción de Common Lisp a sueco (creada para el 1 de abril, unos años atrás).


Las macros son la razón habitual para decir esto. La idea es que debido a que el código es solo una estructura de datos (un árbol, más o menos), puede escribir programas para generar esta estructura de datos. Todo lo que sabe sobre la escritura de programas que generan y manipulan estructuras de datos, por lo tanto, aumenta su capacidad para codificar expresivamente.

Las macros no son una redefinición completa del lenguaje, al menos hasta donde sé (en realidad soy un Schemer, podría estar equivocado), porque hay una restricción. Una macro solo puede tomar un subárbol único de tu código y generar un solo subárbol para reemplazarlo. Por lo tanto, no puede escribir macros de transformación de programa completo, tan genial como sería.

Sin embargo, las macros, tal como están, aún pueden hacer un montón de cosas, definitivamente más que cualquier otro idioma que te permita hacer. Y si está utilizando una compilación estática, no sería difícil hacer una transformación de programa completo, por lo que la restricción es menos importante que eso.


Los usuarios de Lisp se refieren a Lisp como el lenguaje de programación programable . Se utiliza para la computación simbólica , la computación con símbolos.

Las macros son solo una forma de explotar el paradigma de la computación simbólica. La visión más amplia es que Lisp proporciona formas fáciles de describir expresiones simbólicas: términos matemáticos, expresiones lógicas, declaraciones de iteración, reglas, descripciones de restricciones y más. Las macros (transformaciones de formas de origen de Lisp) son solo una aplicación de computación simbólica.

Hay ciertos aspectos para eso: si pregunta por ''redefinir'' el lenguaje, redefinirlo estrictamente significaría redefinir algún mecanismo de lenguaje existente (sintaxis, semántica, pragmática). Pero también hay extensión, incrustación, eliminación de características del lenguaje.

En la tradición de Lisp ha habido muchos intentos de proporcionar estas características. Un dialecto Lisp y una cierta implementación pueden ofrecer solo un subconjunto de ellos.

Algunas formas de redefinir / cambiar / extender la funcionalidad según lo provisto por las principales implementaciones de Common Lisp:

  • Sintaxis de s-expresión . La sintaxis de s-expressions no es fija. El lector (la función LEER) usa las llamadas tablas de lectura para especificar funciones que se ejecutarán cuando se lea un carácter. Uno puede modificar y crear tablas de lectura. Esto le permite, por ejemplo, cambiar la sintaxis de listas, símbolos u otros objetos de datos. También se puede introducir una nueva sintaxis para tipos de datos nuevos o existentes (como hash-tables). También es posible reemplazar la sintaxis s-expression por completo y usar un mecanismo de análisis diferente. Si el nuevo analizador devuelve formularios Lisp, no es necesario cambiar el intérprete o el compilador. Un ejemplo típico es una macro de lectura que puede leer expresiones infija. Dentro de dicha macro de lectura, se utilizan reglas de infijo y reglas de precedencia para operadores. Las macros de lectura son diferentes de las macros comunes: las macros de lectura funcionan en el nivel de caracteres de la sintaxis de datos de Lisp.

  • reemplazando funciones . Las funciones de nivel superior están ligadas a símbolos. El usuario puede cambiar este enlace. La mayoría de las implementaciones tienen un mecanismo que permite esto incluso para muchas funciones incorporadas. Si desea proporcionar una alternativa a la función integrada ROOM, puede reemplazar su definición. Algunas implementaciones generarán un error y luego ofrecerán la opción de continuar con el cambio. Algunas veces es necesario desbloquear un paquete. Esto significa que las funciones en general se pueden reemplazar con nuevas definiciones. Hay limitaciones a eso. Una es que el compilador puede alinear funciones en código. Para ver un efecto, entonces uno necesita recompilar el código que usa el código cambiado.

  • funciones de asesoramiento . A menudo uno quiere agregar algún comportamiento a las funciones. Esto se llama ''asesorar'' en el mundo de Lisp. Muchas implementaciones de Common Lisp proporcionarán dicha instalación.

  • paquetes personalizados Los paquetes agrupan los símbolos en los espacios de nombre. El paquete COMMON-LISP es el hogar de todos los símbolos que forman parte del estándar ANSI Common Lisp. El programador puede crear nuevos paquetes e importar símbolos existentes. Por lo tanto, podría usar en sus programas un paquete EXTENDED-COMMON-LISP que proporcione más o diferentes instalaciones. Simplemente agregando (IN-PACKAGE "EXTENDED-COMMON-LISP") puede comenzar a desarrollar usando su propia versión extendida de Common Lisp. Dependiendo del espacio de nombres utilizado, el dialecto Lisp que use puede verse ligeramente o incluso radicalmente diferente. En Genera on the Lisp Machine hay varios dialectos Lisp uno al lado del otro de esta manera: ZetaLisp, CLtL1, ANSI Common Lisp y Symbolics Common Lisp.

  • CLOS y objetos dinámicos. El sistema de objetos Common Lisp viene con el cambio incorporado. El protocolo Meta-Object amplía estas capacidades. CLOS en sí mismo puede ampliarse / redefinirse en CLOS. Quieres una herencia diferente Escribe un método Desea diferentes formas de almacenar instancias. Escribe un método Las máquinas tragamonedas deberían tener más información. Proporcione una clase para eso. CLOS está diseñado de tal manera que es capaz de implementar una "región" completa de diferentes lenguajes de programación orientados a objetos. Ejemplos típicos son agregar cosas como prototipos, integración con sistemas de objetos extraños (como Objective C), agregar persistencia, ...

  • Lisp formas . La interpretación de los formularios Lisp se puede redefinir con macros. Una macro puede analizar el código fuente que encierra y cambiarlo. Hay varias formas de controlar el proceso de transformación. Las macros complejas usan un buscador de código, que comprende la sintaxis de las formas Lisp y puede aplicar transformaciones. Las macros pueden ser triviales, pero también pueden ser muy complejas, como las macros LOOP o ITERATE. Otros ejemplos típicos son macros para SQL incorporado y generación de HTML incorporado. Las macros también se pueden usar para mover los cálculos para compilar el tiempo. Como el compilador es en sí mismo un programa Lisp, se puede realizar un cálculo arbitrario durante la compilación. Por ejemplo, una macro Lisp podría calcular una versión optimizada de una fórmula si se conocen ciertos parámetros durante la compilación.

  • Símbolos Common Lisp proporciona macros de símbolos. Las macros de símbolo permiten cambiar el significado de los símbolos en el código fuente. Un ejemplo típico es este: (con-slots (foo) bar (+ foo 17)) Aquí el símbolo FOO en la fuente incluida con WITH-SLOTS será reemplazado por una llamada (slot-value bar ''foo).

  • optimizaciones , con las llamadas macros de compilación, se pueden proporcionar versiones más eficientes de algunas funcionalidades. El compilador usará esas macros de compilación. Esta es una forma efectiva para que el usuario optimice sus programas.

  • Manejo de condiciones : maneje las condiciones que resultan del uso del lenguaje de programación de cierta manera. Common Lisp proporciona una forma avanzada de manejar errores. El sistema de condiciones también se puede usar para redefinir las características del lenguaje. Por ejemplo, uno podría manejar errores de funciones indefinidos con un mecanismo de autocarga auto-escrito. En lugar de aterrizar en el depurador cuando Lisp ve una función no definida, el manejador de errores podría intentar cargar automáticamente la función y volver a intentar la operación después de cargar el código necesario.

  • Variables especiales : inyecta enlaces de variables en el código existente. Muchos dialectos Lisp, como Common Lisp, proporcionan variables especiales / dinámicas. Su valor se busca en el tiempo de ejecución en la pila. Esto permite que el código adjunto agregue enlaces de variables que influyen en el código existente sin cambiarlo. Un ejemplo típico es una variable como * standard-output *. Uno puede volver a vincular la variable y todos los resultados que usan esta variable durante el alcance dinámico de la nueva vinculación irán a una nueva dirección. Richard Stallman argumentó que esto era muy importante para él, ya que estaba predeterminado en Emacs Lisp (a pesar de que Stallman sabía sobre el enlace léxico en Scheme y Common Lisp).

Lisp tiene estas y más instalaciones, porque se ha utilizado para implementar muchos lenguajes y paradigmas de programación diferentes. Un ejemplo típico es una implementación integrada de un lenguaje lógico, por ejemplo, Prolog. Lisp permite describir los términos de Prolog con s-expressions y con un compilador especial, los términos de Prolog se pueden compilar a código Lisp. A veces se necesita la sintaxis habitual de Prolog, luego un analizador analizará los términos típicos de Prolog en formularios Lisp, que luego se compilarán. Otros ejemplos para lenguajes incrustados son lenguajes basados ​​en reglas, expresiones matemáticas, términos SQL, ensamblador Lisp en línea, HTML, XML y muchos más.


Una referencia a "estructura e interpretación de los programas de computadora" capítulo 4-5 es lo que me faltaba en las respuestas ( enlace ).

Estos capítulos lo guían en la construcción de un evaluador Lisp en Lisp. Me gusta la lectura porque no solo muestra cómo redefinir Lisp en un nuevo evaluador, sino que también te permite conocer las especificaciones del lenguaje de programación Lisp.


Voy a pipe en ese esquema es diferente de Common Lisp cuando se trata de definir nueva sintaxis. Le permite definir plantillas usando define-syntax que se aplican a su código fuente donde quiera que se utilicen. Se parecen a funciones, solo se ejecutan en tiempo de compilación y transforman el AST.

Aquí hay un ejemplo de cómo let se puede definir en términos de lambda . La línea con let es el patrón que se emparejará, y la línea con lambda es la plantilla de código resultante.

(define-syntax let (syntax-rules () [(let ([var expr] ...) body1 body2 ...) ((lambda (var ...) body1 body2 ...) expr ...)]))

Tenga en cuenta que esto NO es como la sustitución textual. En realidad puede redefinir lambda y la definición anterior de let seguirá funcionando, porque está usando la definición de lambda en el entorno donde let fue definido. Básicamente, es poderoso como las macros, pero funciona como la limpieza.