Defuncionalización en Haskell: cómo colar funciones dentro de datos puros
Un desarrollador que construye un lenguaje funcional sobre WASM GC resuelve con diccionarios de clases de tipos el viejo problema de embeber comportamiento en estructuras de datos serializables y comparables.
El autor de un lenguaje funcional experimental que compila a WASM con tipos GC ha publicado cómo mete funciones dentro de estructuras de datos que deberían ser puro dato. El problema no es nuevo: si quieres que tu AST sea inspeccionable, comparable y testeable con propiedades, necesitas que sea plano y legible; si además quieres que sea extensible sin tocar el generador de código, necesitas comportamiento dentro. Las dos cosas chocan de frente.
Su contexto concreto: un lenguaje pequeño con sintaxis para arrays, texto y tipos algebraicos, donde cada tipo debería poder elegir su codificación (un enum como i8, o como i31, que recorta un i32 para que sea colocable junto a punteros del GC). No quiere mantener un registro de tipos especializados ni infectar el codegen con ese conocimiento. Y no quiere renunciar a que sus expresiones sean dato puro.
Diccionarios como contrabando
El truco son los diccionarios de clases de tipos de Haskell, que son globales, coherentes y están indexados por tipo: no contienen datos, solo hay que saber qué tipo tienen. Y contienen funciones gratis. El autor define primero un sinónimo de clase, Existentiable, que agrupa lo que necesita de cualquier dato oculto de forma existencial: Typeable, NFData, Ord y Show.
Encima va una clase Semantics con los ganchos que quiere inyectar: el tipo (semTyp), la generación de código (semCode), una evaluación simulada (semEval), las expresiones asociadas (semExprs) y un recuento de efectos para análisis estático (semEffects). Después envuelve cualquier instancia en un existencial, ForeignSemantics, que arrastra su diccionario. Como todos los métodos son proyectivos —reciben el sem, no lo producen—, el propio envoltorio puede implementar Semantics reenviando cada llamada al valor que lleva dentro.
El agujero de NFData
Lo interesante es dónde se rompe. Eq y Ord no dan problema porque TypeRep ya los trae, y Show se resuelve desenvolviendo. Read sí queda fuera de la historia. Y NFData es el punto delicado: normalizar una función implicaría normalizar su clausura, es decir, todo el estado que captura para hacer su trabajo. Pero parte del trabajo de una clausura es precisamente esconder ese estado, y no tienes ni idea de qué tipos contiene. El autor enlaza los debates abiertos en deepseq sobre si debería permitirse la instancia superficial en WHNF para funciones como atajo.
No hay repositorio enlazado ni mediciones en el texto: es un esbozo de diseño, con firmas y razonamiento, no una implementación publicada. Para quien diseñe lenguajes, IRs o incluso DSLs embebidos, la idea es reutilizable: si tu representación tiene diccionarios coherentes por tipo, ya tienes por dónde pasar comportamiento sin ensuciar los datos. Lo que queda por ver es si el patrón aguanta cuando el envoltorio existencial se anida o cuando alguien intenta serializar de verdad un ForeignSemantics.

