El problema fundamental que aborda este trabajo es la rigidez de los sistemas de construcción tradicionales y la compilación separada en lenguajes como OCaml, donde el orden de compilación de las dependencias debe ser predeterminado. Esto contrasta con la necesidad moderna de compiladores como servicio, que pueden resolver dependencias de forma dinámica y compilar bajo demanda. La tesis es que, al introducir efectos (del tipo 'algebraic effects') y dominios (unidades de ejecución paralelas con aislamiento de estado) en el compilador OCaml, es posible transformar un compilador monolítico y secuencial en un sistema de construcción auto-organizado y paralelo, capaz de resolver y compilar dependencias en tiempo de ejecución.

Históricamente, los compiladores como OCaml fueron diseñados para un modelo de compilación por lotes, donde cada módulo se compila de forma independiente después de que sus dependencias de interfaz (.mli) han sido procesadas. Esto requiere un sistema de construcción externo (como Make o ocamldep) para gestionar el grafo de dependencias y el orden de compilación. La complejidad de estos sistemas externos a menudo se convierte en un cuello de botella para la productividad y la mantenibilidad, especialmente en proyectos grandes o al intentar integrar el compilador en entornos interactivos o de servicio. La propuesta busca internalizar gran parte de esta lógica de construcción dentro del compilador mismo, simplificando la cadena de herramientas y mejorando la flexibilidad.

Arquitectura del Sistema

El núcleo de la arquitectura propuesta reside en la modificación del sistema de resolución de rutas de carga (Load_path) del compilador OCaml para utilizar 'efectos'. Cuando el compilador encuentra una referencia a un módulo cuya información de tipo (.cmi) no está disponible, en lugar de fallar, 'efectúa' una operación. Este efecto suspende la compilación actual y delega la resolución y compilación de la dependencia a un manejador externo. Inicialmente, este manejador podía lanzar una nueva instancia del compilador para compilar la dependencia, y luego reanudar la compilación original con la información de tipo ya disponible.

La evolución clave de esta arquitectura es la reentrada del compilador. Para evitar el overhead de lanzar nuevas instancias, el compilador modificado es capaz de suspender su estado actual, compilar la dependencia internamente, y luego reanudar la compilación original. Esto se logra mediante un mecanismo de 'snapshotting' del estado global mutable del type checker, inspirado en el proyecto Merlin. Antes de efectuar una solicitud de .cmi, el compilador guarda su estado; después de que la dependencia es compilada y el efecto es manejado, el estado se restaura. Para la paralelización, se introducen 'Dominios' (Domains) de OCaml, que permiten múltiples hilos de ejecución concurrentes. Cada dominio puede iniciar la compilación de un archivo .ml de forma independiente. Cuando un dominio encuentra una dependencia no resuelta, efectúa una solicitud que es gestionada por un scheduler central. Este scheduler puede asignar la compilación de la dependencia a otro dominio disponible o al mismo dominio después de un cambio de contexto, utilizando Domain Local Storage y el mecanismo de snapshotting para gestionar el estado de cada compilación concurrente. La ausencia de compartición de estado mutable entre dominios simplifica el modelo de concurrencia.

Flujo de Compilación con Resolución de Dependencias por Efectos

  1. 1 Compilador (Dominio A) Inicia compilación de bar.ml
  2. 2 Compilador (Dominio A) Encuentra referencia a Foo.value, requiere foo.cmi
  3. 3 Compilador (Dominio A) Snapshot de estado global, efectúa solicitud de foo.cmi
  4. 4 Scheduler/Manejador Recibe solicitud, asigna compilación de foo.mli a Dominio B
  5. 5 Compilador (Dominio B) Compila foo.mli, genera foo.cmi
  6. 6 Scheduler/Manejador Notifica a Dominio A que foo.cmi está disponible
  7. 7 Compilador (Dominio A) Restaura estado, reanuda compilación de bar.ml con foo.cmi
  8. 8 Compilador (Dominio A) Finaliza compilación de bar.ml, genera bar.cmi
CapaTecnologíaJustificación
compute OCaml Compiler Plataforma base para la modificación, su Load_path y type checker son los puntos de inyección.
compute Algebraic Effects and Handlers Mecanismo para invertir el control de flujo y suspender/reanudar la compilación de forma estructurada. vs Monads, Excepciones con continuaciones
orchestration OCaml Domains Unidades de ejecución paralelas para la compilación concurrente de módulos. vs Threads tradicionales con mutexes, Procesos separados Uso de Domain Local Storage para aislamiento de estado.
storage Merlin's Snapshotting Mechanism Permite guardar y restaurar el estado global mutable del type checker para la reentrada del compilador. vs Refactorización completa del compilador para eliminar estado global

Fundamentos Teóricos

El concepto de 'efectos' (effects) utilizado en este trabajo tiene profundas raíces en la investigación de lenguajes de programación, particularmente en los 'efectos algebraicos y manejadores de efectos' (algebraic effects and handlers). Este paradigma, popularizado por trabajos como los de Plotkin y Pretnar (2008), ofrece una alternativa estructurada a las excepciones, continuaciones y monads para manejar efectos laterales en programas funcionales. Permite que las operaciones que producen efectos sean declaradas y luego interpretadas por 'manejadores' en un contexto diferente, invirtiendo el control de flujo de manera elegante.

La gestión del estado global mutable y la reentrada en un sistema legacy se relaciona con principios de diseño de sistemas operativos y bases de datos, donde el 'snapshotting' y la 'recuperación de estado' son fundamentales para la tolerancia a fallos y la concurrencia. La idea de aislar el estado mutable por cada unidad de trabajo concurrente (aquí, cada compilación en un dominio) es un patrón común en sistemas distribuidos y concurrencia, similar a las transacciones ACID en bases de datos o el uso de Thread-Local Storage (TLS) en programación concurrente tradicional, pero adaptado aquí al contexto de los dominios de OCaml.