Estaba intentando montar un motor de reglas para un proyectillo de la universidad en Java. El resultado estaba siendo una auténtica chapuza: un laberinto de condicionales anidados, if-else encadenados y bucles for que, para cuando llegaba a la línea 300, ya no sabía ni qué demonios estaba comprobando.
Y entonces, mientras rebuscaba en una carpeta llena de folios viejos de la asignatura de Inteligencia Artificial, me topé con mis apuntes de Prolog. Llevaba sin tocarlo desde que aprobé la materia, pero decidí bajarme la última versión de SWI-Prolog y trastear un rato. Fue como cambiar el chip del cerebro por completo.
Cambiando la forma de pensar
A los que nos pasamos el día picando código en C, C++ o Java nos enseñan a ser unos dictadores de la CPU. Le decimos a la máquina exactamente cómo tiene que hacer las cosas paso a paso: "Crea esta variable de iteración, recorre este array, si el valor es mayor que X, entonces incrementa este contador". Eso es la programación imperativa de toda la vida.
Prolog es otro rollo radicalmente distinto. Es programación lógica y declarativa. En lugar de darle instrucciones minuciosas, tú le describes a la máquina qué es verdad, le defines las reglas del juego, y dejas que ella solita infiera la solución usando su propio motor de inferencia interno (el famoso backtracking o vuelta atrás). En vez de construir un algoritmo detallado, lo que haces es construir una base de conocimiento.
Para probar si me acordaba de algo, me monté un ejemplito clásico. Imagina que quieres modelar relaciones familiares, o permisos de acceso a un sistema complejo. En C, te montarías tus structs, usarías punteros, listas enlazadas y funciones recursivas a cascoporro. En Prolog, simplemente declaras hechos concretos y reglas lógicas.
Un vistazo al código
Abrí mi editor favorito (Bloc de notas qué te pensabas) y escribí esto en un triste archivo reglas.pl:
% Hechos: lo que sabemos que es estrictamente verdad
es_padre(juan, maria).
es_padre(juan, pedro).
es_padre(pedro, ana).
es_madre(laura, maria).
% Reglas: cómo deducir nueva información a partir de los hechos
es_progenitor(X, Y) :- es_padre(X, Y).
es_progenitor(X, Y) :- es_madre(X, Y).
es_abuelo(X, Z) :- es_padre(X, Y), es_progenitor(Y, Z).
es_hermano(X, Y) :- es_progenitor(Z, X), es_progenitor(Z, Y), X \= Y.
Guardas el archivo, arrancas el intérprete en la consola y empiezas a hacerle consultas (queries). La magia de esto es que no le dices que busque un dato iterando, simplemente le preguntas si algo es cierto basándose en su universo:
?- es_abuelo(juan, ana).
Yes
?- es_hermano(maria, pedro).
Yes
?- es_abuelo(X, ana).
X = juan
¡Boom! Fijaos en esa última consulta. No le he preguntado si Juan es el abuelo, le he preguntado literalmente quién es el abuelo de Ana usando una variable (X). El motor de Prolog ha evaluado las reglas, ha cruzado los datos disponibles en su árbol lógico y me ha devuelto X = juan. Y todo esto sin escribir ni un solo bucle de búsqueda.
El futuro (y el presente) de lo declarativo
Es cierto que Prolog no es la herramienta que vas a usar para montarte una página web dinámica en PHP, ni para hacer un sistema de facturación. Cacharrear con él puede llegar a ser muy frustrante al principio porque el backtracking a veces te juega malas pasadas y te mete en bucles infinitos si no controlas bien el operador de corte (el puñetero !).
Aun así, creo firmemente que este enfoque de "dime qué quieres y yo busco el cómo" tiene mucho sentido para ciertas arquitecturas, especialmente si te metes en sistemas expertos, comprobación de teoremas o cuando tienes que manejar árboles de decisión muy enrevesados. De hecho, si lo piensas, lenguajes como SQL funcionan bajo un paradigma muy parecido: tú lanzas un SELECT enorme y el motor de base de datos ya se apaña para optimizar el plan de ejecución y buscarte las filas.
No sé si de aquí a diez años Prolog vivirá un renacimiento o se quedará como esa rareza académica que solo vemos en las aulas de la universidad y olvidamos al salir, pero la idea de separar la lógica del control me sigue pareciendo brillante. De momento, a mí me ha salvado de escribir hoy otras quinientas líneas de código infumable.