¿Se beneficiaría Rebol (o Red) de las macros de estilo Lisp?

7

Como un 'experimentado' desarrollador de Rebol con un poco de conocimiento del mundo exterior, tendría curiosidad por la utilidad / trampa de implementar macros de estilo Lisp en Rebol (y / o Rojo) .

Mi entendimiento (siempre feliz de revisar) es que Lisp puede preprocesar el código antes de la evaluación / compilación, modificando ese código de acuerdo con las reglas de las macros aplicables. Esto puede permitir declaraciones más complejas / expresivas que de otra manera, con eficiencias ya que esas declaraciones se expanden solo una vez a medida que se carga un cuerpo de código. Las reglas macro en sí mismas son relativamente sencillas, ya que la homoiconicidad de Lisp permite que el código sea manipulado por los mismos términos que se modificarían los datos.

Dado que Rebol también es un lenguaje homoicónico, es lógico que también pueda acomodar macros entre la carga y la evaluación con una gramática de transformación expresiva similar (aunque postulo que el modelo de evaluación de forma libre de Rebol, declaraciones que no suelen estar entre paréntesis, lo hace Es más difícil identificar las partes del código que se van a transformar).

Mi propia inclinación es que, en general, las macros no son realmente necesarias en Rebol; ya puede crear estructuras de código complejas que son bastante eficientes, y donde se desea mayor eficiencia, Rebol tiene la capacidad de adaptarse sin una pérdida significativa de expresividad Por otro lado, 'bastante' y 'sin pérdida significativa' podrían considerarse palabras de comadreja y las macros ofrecen un aumento de eficiencia / expresividad, pero ¿a qué costo de implementación? / p>

Además, como en Rebol puede cargar código antes de la evaluación, sería posible implementar un mecanismo para cargar-expandir-evaluar en el nivel de usuario que permita implementaciones de macros de terceros.

Esta publicación es en parte una respuesta a esta pregunta y todo (casi) Sé sobre macros proviene de este intercambio .

Actualizar

Entrando en el mundo de las macros

Red introdujo un sistema macro rudimentario en la versión 0.6.2. Los he usado de manera efectiva para crear scripts de compatibilidad cruzada que se dirigen tanto al Ren-C Rama de Rebol 3 y Red.

    
pregunta rgchris 08.07.2015 - 23:55

3 respuestas

6

Esta es la primera vez que escucho sobre Rebol, pero de un vistazo rápido a la página de Wikipedia, me parece que los dialectos de Rebol son como las macros de Lisp: ambos reciben un código ordinario del lenguaje que ha pasado léxico y sintáctico ( pero no semántico!) Procesarlo y procesarlo con sus propias reglas semánticas.

Por lo tanto, Rebol no se beneficiará de las macros de Lisp, porque ya tiene esa característica con un nombre diferente, y tener dos características de lenguaje central que hacen exactamente lo mismo es malo, especialmente para los idiomas que se basan en Homoiconicity , donde la simplicidad uniforme en la sintaxis es la clave de su magia.

Actualizar

El explicador del que pregunta en los comentarios dice que las macros tienen la ventaja de que se expanden una vez, antes de la ejecución del código, y se insertan en el código.

Esto, IMO, empeorará las cosas, ¡porque arruinaría el orden del análisis!

Por ejemplo, digamos que tenemos el comando Rebol foo x bar y , donde foo es un dialecto y bar es una macro. ¿Qué debe hacer el intérprete? Depende de arit de foo :

  • Si foo acepta un solo argumento, eso significa que tenemos dos comandos: foo x y bar y . Entonces bar y necesita ser expandido.
  • Si foo acepta tres argumentos, eso significa que tenemos un comando, y bar es el segundo argumento de foo . Esto significa que bar no se debe expandir y, en cambio, se pasa a foo como está.

Las reglas son claras, para un humano y probablemente también para compiladores estáticos. Pero Rebol es dinámico e interpretado, por lo que foo solo se evalúa cuando debe ejecutarse, ¡pero bar debe expandirse antes de que eso suceda! Así que ahora el interpretado debe evaluar los dialectos antes de expandir las macros, para que pueda expandir las macros antes de evaluar el dialecto, y alrededor y alrededor de los interpretados va tratando de resolver el círculo ...

Lisp no tiene este problema, porque:

  • Es fácil saber dónde comienza una función / macro, porque debes ponerlas entre paréntesis. No puede tener foo x bar y ; debe tener (foo x bar y) o (foo x) (bar y) o incluso (foo x (bar y)) , por lo que es fácil para el intérprete saber lo que está tratando de hacer.
  • Lisp no tiene dialectos, solo funciones y macros. Y como las funciones no controlan la evaluación de sus argumentos, las macros siempre se evalúan a sí mismas. Si Rebol no tuviera dialectos, y foo fuera una función, foo x bar y requeriría que el intérprete primero evalúe x , bar y y , y como bar es una macro que se habría expandido independientemente de la aridad de foo , porque foo no tiene control alguno sobre la evaluación de sus argumentos.
respondido por el Idan Arye 09.07.2015 - 02:49
3

Rebol probablemente no lo haría, ya que no hay un paso de compilación explícito. Habría que agregar un pase adicional de 'expansión de macros' para implementar las macros de Lisp correctamente, lo que no es tan diferente de la sugerencia de expand- * de @rgchris.

Las macros de Lisp "funcionan" porque todo lo que entra en una imagen de Lisp es técnicamente necesario para pasar por un paso de compilación según la especificación Common Lisp. Ese paso es lo que determina el resultado de las llamadas (eval-when), determina cómo manejar los bits y piezas de flujo de control, hacer JIT-ting, y la magia de código de propósito general. El código Lisp pasa por el lector, pero siempre hay una imagen existente a la que llamar. En cierto sentido, el tiempo de ejecución Lisp y el compilador están trabajando en conjunto. A diferencia de C, donde el compilador está trabajando por sí mismo. Rebol es similar a C en ese aspecto; El intérprete se está ejecutando por sí mismo. Necesita ambos para que las macros Lisp tengan sentido.

Dado que Red tiene un JIT planificado y lleva Red / System que es JIT o está compilado de antemano, la capacidad de imitar macros Lisp sería ventajosa. La mayor parte del trabajo realizado para admitir macros ya lo hacen necesariamente los compiladores JIT y AOT, ya que ya deben escanear funciones y firmas de parámetros para determinar qué tipo de código de ensamblaje se producirá. Todo lo que queda en ese punto es decidir si una declaración es parte de una declaración para compilar, o una declaración para ejecutar en el contexto Rojo del compilador y tratar el valor de retorno como una declaración para compilar. Dado que ejecutar eval es una práctica mal visto en general, esto significa que la única vez que una macro podría cambiar potencialmente el estado de su entorno rojo es durante las fases de arranque o desarrollo de su programa, ya que modifica el entorno en esos, por lo que esperalo.

Lisp también tiene las instalaciones (macroexpand-1) y (macroexpand-all), que le permiten ver qué va a utilizar el entorno Lisp como la expansión de una macro determinada. Sorprendentemente, esto es más útil para la capacidad de depuración que los sistemas de plantillas normales: puede solicitar una copia exacta de la expansión de la plantilla, que no es algo que pueda pedir a ningún compilador de C ++. Menciono esto porque, en última instancia, alguien siempre muestra cómo los sistemas de macros pueden dificultar un poco más la depuración; sin embargo, un sistema que es aún más difícil de depurar se utiliza en un lenguaje mucho más popular a diario.

Un ejemplo de esta utilidad es que PARSE de Red podría usarse para crear un dialecto que acepta la definición de un formato de archivo binario, que luego genera un bloque de código Rojo / Sistema, que luego se compilará. Dado que la ejecución solo es necesaria en tiempo de compilación , el código completo que realiza el análisis, así como el propio texto de especificación, no son necesarios en los archivos binarios. El preprocesador completo también podría eliminarse, ya que todo desde #if hasta #define y #import se podría lograr usando un sistema macro similar a Lisp.

    
respondido por el Skrylar 04.10.2015 - 13:40
3

Probablemente no.

Las macros de Lisp parecen tener dos grandes propósitos. Primero está el aspecto DRY ("no te repitas"), que permite la captura de patrones que de otro modo serían difíciles o imposibles en el idioma. La segunda es una ventaja de rendimiento que viene de poder aplicar cálculos arbitrarios en tiempo de compilación.

Un buen número de casos en los que los programadores Lisp parecen que las macros requieren para la expresión se debe a que las funciones ordinarias de Lisp están limitadas en la forma en que pueden trabajar con "fragmentos de código dependientes del contexto" pasados como argumentos. Rebol ataca este problema haciendo que los enlaces de los símbolos individuales "viajen" con sus fragmentos de código. El resultado es que muchos casos que requieren macros en Lisp pueden escribirse como funciones Rebol ordinarias.

Además, Rebol articula su historia "DRY" en dialectos. Los dialectos son esencialmente la idea de procesar el código "citado" literalmente bajo nuevas reglas, distinto del evaluador central. Esto compite con las macros como estrategia para la extensión del lenguaje ... y también es incompatible. El propio Lisp no ejecuta macros en partes del código entre comillas, y no habría una forma general de realizar parametrizaciones y expansiones en la "gramática" de un dialecto desconocido.

El ángulo de rendimiento solo afecta al rojo (ya que es poco probable que Rebol se compile). Pero si los servicios de tiempo de compilación están disponibles para optimizar las cosas con forma de función, entonces el único beneficio que las macros podrían ofrecer aquí sería para cosas que no podrían tener la forma de funciones. Los casos realmente motivadores probablemente encontrarán una mejor expresión como un dialecto, lo que presumiblemente también podría aprovechar los servicios de tiempo de compilación.

(Ampliado en Rebol vs. Lisp Macros )

    
respondido por el HostileFork 20.04.2016 - 21:47

Lea otras preguntas en las etiquetas