Prolog (PROgramming in LOGic) es un lenguaje funcional, declarativo, que a diferencia de los lenguajes de programación imperativos, en este caso lo que hace es describir el problema y Prolog, a través de su mecanismo de inferencia (implementado por Robinson en 1968), da los resultados a la problemática definida. Parece magia en algún sentido porque ¿cómo puede ser que un programa mecánico llegue a una conclusión en base a inferencias? Pues no lo es tanto. Prolog usa hechos y reglas para llegar a conclusiones. Por ejemplo, podemos definir los siguientes hechos:

padre(juan,manuel).
padre(pedro,manuel).

En este caso leemos «manuel es el padre de juan» y «manuel es el padre de pedro».

¿Cómo podríamos hacer la inferencia evidente de que son hermanos? Muy fácil, creando la siguiente regla:

hermanos(X,Y) :- padre(X,Z), padre(Y,Z), X=\=Y.

Lo cual se lee: X y Y son hermanos SI el padre de X es Z, el padre de Y es también Z y X no es Y.

Tenemos que aclarar esto último -que X no es Y- pues sino, el programa reportaría que juan es hermano de sí mismo o que pedro es hermano de sí mismo, lo cual lógicamente no tiene sentido.

Y quizás estamos abreviando (demasiado) lo que puede hacer Prolog, pero la idea es ésa: poder hacer inferencias y llegar a resultados. Es interesante aclarar que en un lenguaje como estos, muchas veces caemos en el no determinismo, es decir, no podemos saber qué clase de respuestas entregará el programa y si éste entregará acaso alguna respuesta. Un ejemplo de esto puede verse en el problema que Bertrand Russell expresara: «En un pueblo existe un barbero, el cual rasura a todos aquellos que no se rasuran a sí mismos». Y la pregunta que hace Russell: «¿Quién es el que rasura al barbero?

Este tipo de problemas se puede expresar en Prolog, a pesar de que lógicamente no parece haber un resultado. Russell -de hecho- se inventa una teoría llamada «de tipos», en donde los conjuntos están perfectamente definidos. En esta teoría, el filósofo y matemático nos dice: «la pregunta no tiene sentido, es inválida».

Pues bien, el problema de Russell se puede expresar de la siguiente manera en Prolog:

rasura(X,Y) :- not(rasura(Y,Y)).

Esto se lee así: X rasura a Y SI Y no se rasura a sí mismo.

Como puede verse, es una regla recursiva, que se llama a sí misma. Si se ejecuta este programa en algún intérprete o compilador de Prolog, el resultado será simple: error por memoria insuficiente, overeflow, etcétera.

Quien tenga interés en desarrollar programas de esta naturaleza, o de entender mejor el paradigma funcional y declarativo, bien puede usar intérpretes y compiladores que son de código abierto y/o libres. Un ejemplo de ellos es SWI Prolog, el cual es una implementación muy cercana al Prolog estándar, que si mal no recuerdo, tiene ya más de 15 años de haberse propuesto.

SWI Prolog está documentado, hay ejemplos, tutoriales, comunidad de usuarios e incluso, se puede correr en el navegador. Todo esto la hace una herramienta estupenda por muchos motivos, aparte de gratuita, está muy bien cuidada y trabajada. Échenle un ojo, de verdad me ha convencido.

Referencias:

SWI-Prolog