4. Paradigma Lógico y Monografía de Prolog
En lugar de concebir un algoritmo como instrucciones paso a paso, el paradigma lógico establece una base de conocimiento compuesta por hechos y reglas de inferencia basadas en la lógica de predicados. Computar es demostrar la veracidad de una consulta.
- 1879 · Gottlob Frege: Introduce la lógica de predicados de primer orden, permitiendo formalizar relaciones matemáticas entre objetos.
- 1965 · J. Alan Robinson: Descubre el Principio de Resolución, un algoritmo computacional capaz de deducir automáticamente conclusiones a partir de axiomas.
- Cláusulas de Horn: Subconjunto de la lógica de primer orden con a lo sumo un literal positivo, clave para que la resolución sea eficiente y computable.
- 1972 · Alain Colmerauer y Philippe Roussel (Univ. de Marsella): Crean Prolog (PROgrammation en LOGique), implementando la resolución SLD.
- 1982 · Proyecto de 5ª Generación de Japón: El gobierno nipón adoptó la programación lógica como la arquitectura central del hardware y software de inteligencia artificial del futuro.
Declarativo Puro
Se define QUÉ es verdad mediante axiomas. El motor de inferencia interno se encarga de explorar todas las rutas de búsqueda para deducir la respuesta.
Unificación
Mecanismo central por el cual dos términos se emparejan haciendo coincidir sus estructuras y ligando variables libres a valores concretos (sustitución más general MGU).
Backtracking Automático
Si una alternativa de deducción falla o el usuario solicita más resultados, el motor de Prolog retrocede automáticamente al punto de elección previo y explora otra rama.
En el modelo teórico lógico puro, el orden de las cláusulas no altera el resultado. Sin embargo, en la práctica computacional real de Prolog:
- El orden importa: Prolog evalúa de arriba hacia abajo y de izquierda a derecha; un orden incorrecto puede provocar bucles infinitos.
- El Operador de Corte (Cut
!): Permite podar el árbol de búsqueda de backtracking para ganar rendimiento, pero rompe la pureza declarativa de la lógica formal.
• Las constantes y los predicados empiezan con letra minúscula (ej: juan, padre, pedro).
• Las variables inician siempre con letra MAYÚSCULA (ej: X, Y, Padre).
• Cada cláusula finaliza obligatoriamente con un punto final (.).
% ========================================================
% 1. HECHOS: Afirmaciones directas sobre el mundo (Slide 48)
% ========================================================
padre(juan, maria).
padre(juan, pedro).
padre(maria, luis).
madre(ana, maria).
hombre(juan).
hombre(pedro).
hombre(luis).
mujer(ana).
mujer(maria).
% ========================================================
% 2. REGLAS: Relaciones inferidas (Cabeza :- Cuerpo)
% :- se lee "SI" | la coma (,) representa el AND lógico
% ========================================================
abuelo(X, Z) :-
padre(X, Y),
padre(Y, Z).
hermano(X, Y) :-
padre(P, X),
padre(P, Y),
X \= Y. % X debe ser distinto de Y
ancestro(X, Y) :- padre(X, Y).
ancestro(X, Y) :-
padre(X, Z),
ancestro(Z, Y). % Regla recursiva
Consultas al Motor de Prolog (Slide 49)
En la consola interactiva (REPL), el signo ?- abre una consulta para que Prolog verifique la base de conocimientos:
?- padre(juan, maria).
true. % Demostración positiva directa
?- padre(juan, X).
X = maria ; % Presionando ';' exigimos backtracking
X = pedro. % Segunda solución deducida
?- abuelo(juan, Q).
Q = luis. % Inferencia: juan es padre de maria y maria de luis
?- ancestro(juan, luis).
true.
Al igual que en Haskell, las listas en Prolog se procesan descomponiéndolas en cabeza (H, un elemento) y cola (T, una sublista).
% 1. Pertenencia a lista: member(Elemento, Lista)
member(X, [X|_]). % Caso base: X es el primer elemento (cabeza)
member(X, [_|T]) :- % Paso recursivo: X es miembro de la cola T
member(X, T).
% 2. Longitud de lista: length(Lista, Longitud)
longitud([], 0). % Caso base: una lista vacía mide 0
longitud([_|T], N) :- % Paso recursivo: mide la cola y suma 1
longitud(T, N1),
N is N1 + 1.
% 3. Invertir lista: reversa(Lista, ListaInvertida)
reversa([], []).
reversa([H|T], R) :-
reversa(T, RT),
append(RT, [H], R).