2008-08-05 15 views
41

He leído mucho que LISP puede redefinir la sintaxis sobre la marcha, presumiblemente con macros. Tengo curiosidad de cuánto va esto realmente? ¿Se puede redefinir la estructura del lenguaje tanto que se convierta en un compilador para otro idioma? Por ejemplo, ¿podría cambiar la naturaleza funcional de LISP en una sintaxis y semántica más orientadas a objetos, tal vez decir tener una sintaxis más cercana a algo como Ruby?¿Hasta dónde pueden llegar las macros LISP?

Especialmente, ¿es posible deshacerse del paréntesis usando macros? Aprendí lo suficiente (Emacs-) LISP para personalizar Emacs con mis propias micro-características, pero estoy muy curioso de lo lejos que pueden llegar las macros en la personalización del lenguaje.

+3

Tenga en cuenta que lisp está orientado a objetos. Ver el sistema de objetos Common Lisp. – catphive

+2

[Peter Norvig] (http://norvig.com/bio.html) hizo un [Intérprete Prolog] (http://norvig.com/paip/prolog.lisp) en su [libro] (http://norvig.com/paip.html). –

+1

Las macros de esquema son muy potentes. Escribí una implementación completa de LINQ como Scheme macro hace un tiempo. [https://ironscheme.svn.codeplex.com/svn/IronScheme/IronSchemeConsole/ironscheme/linq.ss](https://ironscheme.svn.codeplex.com/svn/IronScheme/IronSchemeConsole/ironscheme/linq.ss) ¡Con todo este poder, me estoy quedando sin buenas ideas para aplicarlo! – leppie

Respuesta

32

Esa es una muy buena pregunta.

creo que es matizada pero definitivamente responder:

Las macros no están atrapados en s-expresiones. Vea la macro LOOP para un lenguaje muy complejo escrito usando palabras clave (símbolos). Entonces, aunque puede comenzar y terminar el ciclo con paréntesis, dentro tiene su propia sintaxis.

Ejemplo:

(loop for x from 0 below 100 
     when (even x) 
     collect x) 

Dicho esto, macros más simples sólo tiene que utilizar s-expresiones. Y estarías "atrapado" usándolos.

Pero s-expresiones, como Sergio ha respondido, comienzan a sentirse bien. La sintaxis se quita del camino y comienzas a codificar en el árbol de sintaxis.

En cuanto a las macros lector, sí, que posiblemente podría escribir algo como esto:

#R{ 
     ruby.code.goes.here 
    } 

Pero se necesitaría para escribir su propio analizador de sintaxis de Ruby.

También puede imitar algunas de las construcciones Ruby, como bloques, con macros que se compilan con las construcciones Lisp existentes.

#B(some lisp (code goes here)) 

se traduciría en

(lambda() (some lisp (code goes here))) 

Ver this page de cómo hacerlo.

+1

Tu ejemplo de una macro "no está pegado en s-expressions" me parece una expresión s. –

+12

El ejemplo de macro de bucle es un s-expr, pero las "subexpresiones" no lo son. –

+0

* Esa es una muy buena pregunta. * Pero no para stackoverflow.com; no es una tarea ni nada que pueda responderse definitivamente sin la opinión y la religión infiltrándose para llenar los vacíos donde el análisis se hunde en un tiempo indefinido. – Kaz

2

Si quieres que lisp se vea como Ruby usa Ruby.

Es posible usar Ruby (y Python) de una manera muy ceceante, que es una de las principales razones por las que han ganado aceptación tan rápidamente.

1

@sparkes

veces LISP es la elección lenguaje claro, es decir, las extensiones de Emacs. Estoy seguro de que podría usar Ruby para extender Emacs si quisiera, pero Emacs fue diseñado para ser extendido con LISP, por lo que parece tener sentido usarlo en esa situación.

0

Es una pregunta difícil. Como lisp ya está estructuralmente tan cerca de un árbol de análisis, la diferencia entre un gran número de macros y la implementación de su propio mini lenguaje en un generador de analizador no es muy clara. Pero, a excepción del paréntesis de apertura y cierre, podrías terminar fácilmente con algo que no se parece al ceceo.

+1

"excepto para abrir y cerrar paren" <- Incluso puede cambiar esto. Consulte http://planet.plt-scheme.org/package-source/chongkai/sml.plt/1/6/planet-docs/ml/index.html para ML estándar embebido en Scheme (Racket) usando el equivalente de Scheme de lector macro. – p4bl0

10

Las macros normales operan en listas de objetos. Más comúnmente, estos objetos son otras listas (formando así árboles) y símbolos, pero pueden ser otros objetos como cadenas, tablas hash, objetos definidos por el usuario, etc. Estas estructuras se llaman s-exps.

Por lo tanto, cuando carga un archivo fuente, su compilador Lisp analizará el texto y producirá s-exps. Las macros operan en estos. Esto funciona muy bien y es una forma maravillosa de extender el lenguaje dentro del espíritu de s-exps.

Además, el proceso de análisis mencionado anteriormente se puede extender a través de "macros de lector" que le permiten personalizar la forma en que su compilador convierte el texto en s-exps. Sugiero, sin embargo, que abracen la sintaxis de Lisp en lugar de doblarla en otra cosa.

Parece un poco confuso cuando menciona la "naturaleza funcional" de Lisp y la "sintaxis orientada a objetos" de Ruby. No estoy seguro de qué se supone que es la "sintaxis orientada a objetos", pero Lisp es un lenguaje multi-paradigma y admite la programación orientada a objetos extremely bien.

Por cierto, cuando digo Lisp, me refiero a Common Lisp.

Le sugiero que aleje sus prejuicios y give Lisp an honest go.

15

No soy un experto en Lisp, diablos, ni siquiera soy un programador de Lisp, pero después de un poco de experimentación con el lenguaje llegué a la conclusión de que después de un tiempo los paréntesis comienzan a ser 'invisibles' y comienzas viendo el código como lo quieres. Comienza a prestar más atención a las construcciones sintácticas que crea a través de s-exprs y macros, y menos a la forma léxica del texto de listas y paréntesis.

Esto es especialmente cierto si aprovecha un buen editor que ayuda con la indentación y la coloración de sintaxis (intente establecer los paréntesis en un color muy similar al fondo).

Es posible que no pueda reemplazar el idioma por completo y obtener la sintaxis 'Ruby', pero no lo necesita. Gracias a la flexibilidad del idioma, puede terminar teniendo un dialecto que parezca seguir el "estilo Ruby de programación" si lo desea, sea lo que sea que eso signifique para usted.

Sé que esto es solo una observación empírica, pero creo que tuve uno de esos momentos de iluminación Lisp cuando me di cuenta de esto.

5

Sí, básicamente se puede cambiar la sintaxis, e incluso escapar "el paréntesis infierno". Para eso, necesitará definir una nueva sintaxis de lector. Mire las macros de los lectores.

Sospecho, sin embargo, que para alcanzar el nivel de pericia de Lisp para programar tales macros tendrá que sumergirse en el lenguaje a tal punto que ya no considere paréntesis como "infierno". Es decir. para cuando sepa cómo evitarlos, habrá llegado a aceptarlos como algo bueno.

8

Paréntesis infierno?No veo más paréntesis en:

(function toto) 

que en:

function(toto); 

Y en

(if tata (toto) 
    (titi) 
    (tutu)) 

no más que en:

if (tata) 
    toto(); 
else 
{ 
    titi(); 
    tutu(); 
} 

veo menos soportes y ';' aunque.

+0

Mira alguna sintaxis de Ruby ... puedes soltar completamente los parens a menos que sean ABSOLUTAMENTE necesarios para eliminar la ambigüedad ... incluso Haskell que también es muy fuerte funcional no está vinculado a parens como Lisp (u otros lenguajes como usted señala) –

+1

@Mike: tiene razón. Pero Lisp versus C/C++/Java/C#: ¡no tiene mucho más paréntesis, y mucho menos paréntesis y no semicolumnas! Y eso fue hace 50 años, esto siempre me sorprende. –

+0

se puede escribir un lector en/para lisp que usa indentación y no necesita paréntesis. sería una página de código. ¿Eso cambiaría mucho? es como buscar una esposa para su apariencia ... aunque sea tonto, mucha gente lo hace ... :) –

19

Sí, puede redefinir la sintaxis para que Lisp se convierta en un compilador. Lo hace utilizando "Macros de lector", que son diferentes de las "Macros de compilador" normales en las que probablemente esté pensando.

Common Lisp tiene la función incorporada para definir una nueva sintaxis para que las macros de lector y lector procesen esa sintaxis. Este procesamiento se realiza en tiempo de lectura (que viene antes del tiempo de compilación o evaluación). Para obtener más información sobre la definición de macros de lector en Common Lisp, consulte el Common Lisp Hyperspec: querrá leer Ch. 2, "Syntax" y Ch. 23, "Reader". (Creo que Scheme tiene las mismas facilidades, pero no estoy tan familiarizado con él - vea el Scheme sources para el Arc programming language).

Como un ejemplo simple, supongamos que quiere que Lisp utilice llaves en vez de paréntesis. Esto requiere algo así como las siguientes definiciones lector:

;; { and } become list delimiters, along with (and). 
(set-syntax-from-char #\{ #\() 
(defun lcurly-brace-reader (stream inchar) ; this was way too easy to do. 
    (declare (ignore inchar)) 
    (read-delimited-list #\} stream t)) 
(set-macro-character #\{ #'lcurly-brace-reader) 

(set-macro-character #\} (get-macro-character #\))) 
(set-syntax-from-char #\} #\)) 

;; un-lisp -- make parens meaningless 
(set-syntax-from-char #\) #\]) ; (and) become normal braces 
(set-syntax-from-char #\(#\[) 

Usted está diciendo que el Lisp {es como una (y que el} es como una). A continuación, crea una función (lcurly-brace-reader) a la que el lector llamará siempre que vea un {, y utilice set-macro-character para asignar esa función al {. Luego le dices a Lisp que (y) son como [y] (es decir, sin sintaxis significativa).

Otras cosas que podría hacer incluir, por ejemplo, creating a new string syntax o usar [y] para encerrar la notación in-fix y procesarla en S-expressions.

También puede ir más allá de esto, redefiniendo toda la sintaxis con sus propios caracteres macro que desencadenarán acciones en el lector, por lo que el cielo es realmente el límite. Esta es solo una de las razones por las que Paul Graham y others siguen diciendo que Lisp es un buen lenguaje para escribir un compilador.

14

Una y otra vez, los recién llegados a Lisp quieren "deshacerse de todos los paréntesis". Dura unas pocas semanas. Ningún proyecto para construir una sintaxis seria de programación de propósito general sobre el analizador de expresiones S habitual llega a ninguna parte, porque invariablemente los programadores acaban prefiriendo lo que actualmente perciben como "infierno de paréntesis". ¡Lleva un tiempo acostumbrarse, pero no mucho! Una vez que te acostumbras, y realmente puedes apreciar la plasticidad de la sintaxis predeterminada, volviendo a los idiomas donde hay una sola forma de expresar cualquier construcción de programación en particular es realmente gratificante.

Dicho esto, Lisp es un sustrato excelente para crear idiomas específicos de dominio. Tan bueno como, si no mejor que, XML.

¡Buena suerte!

+0

Bueno, admito que nunca he usado Lisp o un dialecto durante un tiempo prolongado, pero me siento bastante cómodo usando la sintaxis (y su simplicidad es bastante impresionante), pero aún prefiero la sintaxis de Ruby sobre cualquier otro idioma que haya utilizado. . –

+2

¿Qué pasa si la sintaxis puede ser algo que considera apropiado para expresar el programa en cuestión? – jfm3

+0

En realidad, alguien ha desarrollado una sintaxis seria de programación de propósito general además de S-expressions - ["Sweet-expressions"] (http://www.dwheeler.com/readable/). Conservan todas las ventajas de flexibilidad de las expresiones S. Los usuarios Lisp-familiares de esa extensión * no * prefieren "infierno de paréntesis". Sin embargo, Sweet-expressions no se ha contagiado. Mi hipótesis es que esto se debe a que el autor de Sweet-expressions ha implementado esa sintaxis para solo unos pocos dialectos Lisp, y ha escrito poca documentación sobre cómo instalar esas extensiones. –

1

ver este ejemplo de cómo macros lector puede ampliar el lector Lisp con tareas complejas, como plantillas XML:

http://common-lisp.net/project/cl-quasi-quote/present-class.html

esta biblioteca usuario compila las partes estáticas del XML en UTF-8 codificado literal matrices de bytes en tiempo de compilación que están listas para ser secuencia de escritura en el flujo de red. y son utilizables en macros de lisp normales, son ortogonales ... la ubicación del carácter de coma influye en qué partes son constantes y cuáles deben evaluarse en tiempo de ejecución.

más detalles disponibles en: http://common-lisp.net/project/cl-quasi-quote/

otro proyecto que para las extensiones comunes de la sintaxis Lisp: http://common-lisp.net/project/cl-syntax-sugar/

8

lo que están pidiendo es un poco como preguntar cómo llegar a ser un chocolatero experto para que pueda eliminar todo lo infernal cosas marrones de tu pastel de chocolate favorito.

0

Uno de los usos de las macros que me voló la mente fue la verificación en tiempo de compilación de las solicitudes SQL contra DB.

Una vez que se da cuenta de que tiene todo el lenguaje a mano en tiempo de compilación, abre interesantes perspectivas nuevas. Lo que también significa que puede dispararse en el pie de maneras nuevas e interesantes (como la compilación de renderización no reproducible, que puede convertirse fácilmente en una pesadilla de depuración).

11

La mejor explicación de las macros de Lisp que he visto es en

https://www.youtube.com/watch?v=4NO83wZVT0A

a partir de unos 55 minutos en. Este es un video de una conferencia pronunciada por Peter Seibel, el autor de "común práctico Lisp ", que es el mejor libro de texto de Lisp que existe.

La motivación para las macros de Lisp suele ser difícil de explicar, porque realmente se desarrollan en situaciones que son demasiado largas para presentarse en un simple tutorial. Peter viene con un gran ejemplo; puedes agarrarlo por completo y hace un buen uso de las macros Lisp.

Ha preguntado: "podría cambiar la naturaleza funcional de LISP en una sintaxis y semántica más orientadas a objetos". La respuesta es sí. De hecho, Lisp originalmente no tenía ninguna programación orientada a objetos en absoluto, ¡no es sorprendente ya que Lisp ha existido desde mucho antes de la programación orientada a objetos! Pero cuando descubrimos OOP por primera vez en 1978, pudimos agregarlo fácilmente a Lisp, usando, entre otras cosas, macros. Eventualmente se desarrolló el Sistema de Objetos Common Lisp (CLOS), un sistema de programación orientado a objetos muy poderoso que encaja elegantemente en Lisp. Todo se puede cargar como una extensión: ¡nada está incorporado! Todo está hecho con macros.

Lisp tiene una característica completamente diferente, llamada "macros de lector", que se puede utilizar para ampliar la sintaxis de la superficie del idioma. Usando macros de lector, puede hacer sublenguajes que tengan sintaxis similar a C o Ruby. Transforman el texto en Lisp, internamente. Estos no son ampliamente utilizados por la mayoría de los programadores reales de Lisp, principalmente porque es difícil ampliar el entorno de desarrollo interactivo para comprender la nueva sintaxis. Por ejemplo, los comandos de sangría de Emacs se confundirían con una nueva sintaxis. Sin embargo, si eres enérgico, Emacs también es extensible y podrías enseñarle acerca de tu nueva sintaxis léxica.

Cuestiones relacionadas