El problema fundamental que 'vau' de Kernel busca resolver es la dualidad histórica entre la manipulación de código (macros) y la manipulación de datos (funciones) en lenguajes Lisp. Tradicionalmente, los sistemas de macros como syntax-rules o syntax-case en Scheme operan en una fase de compilación separada, generando código que luego es ejecutado. Esto introduce dos 'lenguajes' o sistemas metalingüísticos distintos: uno para la transformación del código fuente y otro para la lógica de tiempo de ejecución.

'Vau' propone una unificación radical: un único mecanismo, el 'operative', que recibe sus argumentos sin evaluar y el entorno de llamada como un valor de primera clase. Esto permite que el mismo código decida cuándo y cómo evaluar sus argumentos, eliminando la necesidad de una separación de fases explícita y un DSL de macros. La relevancia actual de esta propuesta radica en la búsqueda de una mayor simplicidad conceptual y una reducción de la superficie de error en la programación meta-circular, especialmente en sistemas donde la introspección y transformación del código son operaciones frecuentes.

Históricamente, los 'fexprs' (funciones que reciben sus argumentos sin evaluar) fueron descartados por su dificultad de compilación y la imposibilidad de razonamiento ecuacional, como lo demostró Wand en 1998. Sin embargo, el artículo argumenta que una restricción clave —hacer que el entorno dinámico recibido por el 'vau' sea inmutable— restaura suficiente conocimiento estático para permitir una compilación eficiente, comparable a la de sistemas como Chez Scheme.

Arquitectura del Sistema

El núcleo de la propuesta de Kernel y su implementación en Seed (una extensión de Chez Scheme) reside en el concepto de 'vau' como una 'operative'. A diferencia de una función tradicional que evalúa sus argumentos antes de la llamada, un 'vau' recibe una lista de expresiones sin evaluar y el entorno dinámico del llamador como un objeto de primera clase. Este entorno, crucialmente, es inmutable. Esta inmutabilidad es la decisión de diseño clave que permite la compilación.

En un sistema 'vau' inmutable, el operative puede introspeccionar las expresiones de sus argumentos y el entorno de llamada, decidiendo dinámicamente qué evaluar, cuándo y en qué entorno. Por ejemplo, un operador lógico myor implementado con vau puede evaluar el primer argumento, y si es verdadero, evitar la evaluación de los argumentos restantes, emulando el comportamiento de cortocircuito sin necesidad de generar código auxiliar en una fase de macro. La implementación del compilador, al saber que el entorno no puede ser mutado por el 'vau', recupera la capacidad de realizar optimizaciones como la sustitución, el inlining y otras transformaciones de código que son estándar en compiladores de Scheme.

La comparación con syntax-case ilustra la diferencia: syntax-case utiliza un lenguaje de plantillas y un sistema de expansión de macros que opera en tiempo de compilación para transformar árboles de sintaxis abstracta. Esto a menudo requiere let-bindings para evitar la doble evaluación de expresiones. En contraste, vau permite al programador escribir directamente la lógica de evaluación y control de flujo (como el let para la evaluación única) dentro del mismo cuerpo del operative, utilizando el lenguaje base. Esto se alinea con el concepto de catamorfismo, donde las transformaciones se aplican recursivamente a subexpresiones de forma automática, simplificando la manipulación de árboles de sintaxis.

CapaTecnologíaJustificación
compute Kernel Lisp Lenguaje de programación que implementa el concepto 'vau' para la unificación de macros y procedimientos. vs Scheme (con syntax-rules o syntax-case), Common Lisp (con macros)
compute Chez Scheme Plataforma base para la implementación de Seed, una extensión que integra 'vau' y permite la compilación eficiente.

Trade-offs

Ganancias
  • Economía conceptual (unificación de macros y procedimientos)
  • Simplificación del código meta-programático
Costes
  • Pérdida de mutabilidad directa del entorno de llamada por parte del operative
(define myor
  (vau args env
    (if (null? args) #f
        (let ((v (eval (car args) env)))
          (if v v
              (eval (cons myor (cdr args)) env))))))
Demuestra cómo 'vau' permite controlar directamente la evaluación de argumentos, a diferencia de las macros tradicionales que generan código para ese control. El 'let' interno maneja la evaluación única del primer argumento.

Fundamentos Teóricos

La idea de 'vau' y los 'fexprs' tiene raíces profundas en la investigación de lenguajes de programación, particularmente en la familia Lisp. El trabajo seminal de Brian Cantwell Smith en su tesis de 1982 sobre 3-Lisp, que introdujo los 'reified environments' (entornos reificados), es un antecedente directo. La capacidad de tratar el entorno de ejecución como un valor de primera clase que puede ser manipulado y pasado es fundamental para 'vau'.

El desafío de los 'fexprs' fue articulado por David Wand en su paper de 1998, "The Theory of Fexprs is Trivial", donde argumentó que los fexprs hacían imposible el razonamiento ecuacional debido a su control directo sobre la evaluación, lo que impedía la sustitución de iguales por iguales. Este fue un golpe significativo para la viabilidad de los fexprs en lenguajes compilados. Sin embargo, la solución propuesta en Kernel, al imponer la inmutabilidad en el entorno dinámico pasado a los 'vau', reintroduce las propiedades estáticas necesarias para la compilación, reviviendo el concepto de fexprs de una manera que aborda las preocupaciones de Wand. Esto demuestra cómo las restricciones bien elegidas pueden transformar un problema teóricamente intratable en una solución práctica.