PROgramación LOGica g PROLOG
D Old R d í R j
Dr. Oldemar Rodríguez Rojas Escuela de Informática
Escuela de Informática
Universidad de Nacional
¿Dónde bajar?
Strawberry PROLOG:
Strawberry PROLOG:
www.dobrev.com
PROLOG -> PROgramming in LOGig Paradigma -> El lenguaje de la lógica puede ser usado para programar
p p p g
Padre de PROLOG -> Francés Alain Colmerauer
Colmerauer
Fue desarrollado en 1970 en la Universidad de Marseilles
Universidad de Marseilles
En el curso usaremos Strawberry
O OG ó
PROLOG Versión 2.3
La interfaz
Ejemplo 1:
le_gusta(elena,tenis).
le_gusta(jony,football).
le_gusta(tomas,baseball).
le_gusta(erik,natacion).
le gusta(marco,tenis).
le_gusta(marco,tenis).
le_gusta(_,tenis).
le_gusta(juan,X) :- le_gusta(tomas,X).
?-le_gusta(juan,tenis).
Las clausulas contienen hechos y reglas
Un hecho es: le_gusta(elena,tenis)
que corresponde a: "a elena le gusta el tenis"
que corresponde a: a elena le gusta el tenis
Una regla es: le_gusta(juan,X):-le_gusta(tomas,X).
que corresponde a la regla lógica:
a tomas le gusta X => a juan le gusta X o equivalentemente:
a juan le gusta X si a tomas le gusta X a juan le gusta X si a tomas le gusta X
Dos Corridas: os Co das
?-le_gusta(juan,baseball) g (j , ) Yes.
?-le gusta(jony,tenis) _g (j y, )
Yes
Variables: a ab es
En la regla:g
le gusta(juan X) : le gusta(tomas X) le_gusta(juan,X) :- le_gusta(tomas,X).
aparece la variable X
La variables deben comenzar con letra mayúscula.
mayúscula.
Uso del fail
Cuando PROLOG tiene una meta interna encuentra solamente una solución para cadap submeta y continua con la próxima submeta, por lo que encuentra solamente una solución.
Cuando PROLOG tiene una submeta a la derecha de una regla también encuentra
l t l ió
solamente una solución.
El uso del fail forzará el backtraking
( l ió ) b it i l
(reevaluación) en ambas situaciones con lo que si se encontrarán todas las soluciones.
EJEMPLO: Versión sin fail
padre(leonardo,katherine).
padre(carlos,jason).
padre(carlos,marilyn).
p ( , y )
todos :-
padre(X Y) padre(X,Y), write(X),
write(" es el padre de "), write(Y),nl.( ),
?-todos
?-todos.
Salida:
S
leonardo es el padre de katherine
leonardo es el padre de katherine
Yes.
EJEMPLO: Versión con fail
padre(leonardo,katherine).
p ( )
padre(carlos,jason).
padre(carlos marilyn) padre(carlos,marilyn).
todos :-
d ( )
padre(X,Y), write(X),
write(" es el padre de "), write(Y) nl fail
write(Y),nl,fail.
? d
?-todos.
Salida:
S
leonardo es el padre de katherine leonardo es el padre de katherine carlos es el padre de jason
carlos es el padre de marilyn No
No.
Ejemplo de unificación de variables:
?-le gusta(Persona,tenis),write(Persona)._g ( , ), ( ) Salida:
elena Yes elena Yes
? le gusta(Persona tenis) write(Persona)
?-le_gusta(Persona,tenis),write(Persona), write(" "), fail.
S lid Salida:
elena marco _0 juan No.
Objetos y Relaciones
Toda clausula en PROLOG está
conformada por relaciones que afectan conformada por relaciones que afectan a objetos.
Los nombres de las relaciones y de los objetos deben estar escritos en
objetos deben estar escritos en
minúscula.
Ejemplo 2: Metas (Goals) t
compuestas
carro(toyota,130000,3,rojo,12000).
(f d 90000 4 i 25000) carro(ford,90000,4,gris,25000).
carro(datsun,8000,1,rojo,30000).
?-carro(M,K,E,C,P), P < 24000, write(M), write(" "),
write(K), write(" "),( ), ( ), write(E), write(" "), write(C), write(" "), write(P) write(" ") write(P), write( ).
Salida:
toyota 130000 3 rojo 12000 Yes.
Observación:
Observación:
la es el AND la , es el AND
el ; es el OR
P 25000 i lid d (P 25000)
P<25000 invoca en realidad <(P,25000)
Variables Anónimas a ab es ó as
Para variables anónimas se utiliza "_", por ejemplo:
? carro( Edad Costo) Costo < 27000
?-carro(_,_,Edad,_,Costo), Costo < 27000, write(Edad), write(" "),
write(Costo), write(" "), fail.
Salida:
3 12000 4 25000 No.
La variables anónimas puede ser usadas en hechos, por ejemplo:
le gusta( tenis) le_gusta(_,tenis).
se lee "a toda persona le gusta el tenis”
El mecanismo"Backtraking"
(reevaluación)
Ejemplo 3:
alumno(peter,9).
alumno(paul,10).
l ( 9)
alumno(ana,9).
alumno(susan,9).
?-alumno(P1,9), alumno(P2,9), not(P1=P2), write(P1), write(" "), write(P2),nl,fail.( ), ( ), ( ), ,
Este programa responde:
peter ana peter susan peter susan ana peter ana susan ana susan susan peter susan ana No.
El mecanismo"Backtraking" funciona como sigue:
Ejemplo 4: Uso del Not j p
Queremos escribir un programa que le busque novio a Sofía El programa
busque novio a Sofía. El programa contiene una "base de datos" con la
í
lista de solteros y sus características, además contiene una regla para los g p
requisitos pedidos por Sofía, a saber, el novio debe ser vegetariano y no
novio debe ser vegetariano y no
fumador.
hombre(jose).(j ) hombre(bill).
hombre(tom).
fumador(jorge).
fumador(tom).
vegetariano(jose) vegetariano(jose).
vegetariano(tom).
sofia hace pareja(X) :- hombre(X), not(fumador(X))._ _p j ( ) ( ), ( ( )) sofia_hace_pareja(X) :- hombre(X), vegetariano(X).
? fi h j ( )
?-sofia_hace_pareja(X),
write("una posible pareja para Sofia es: "), write(X), nl.
La salida al ejecutar este programa es:
La salida al ejecutar este programa es:
l f
una posible pareja para Sofia es: jose Yes.
Yes.
Ejemplo 5: un árbol genealógico
masculino(alan).
masculino(carlos).
masculino(luis).( ) masculino(ivan).
femenino(ana).
femenino(andrea) femenino(andrea).
femenino(eugenia).
femenino(damaris).
madre(eugenia,ana).
madre(alan,damaris).
padre(alan luis) padre(alan,luis).
padre(ana,carlos).
padre(andrea,luis).
padre(eugenia,alan).
padres(X,Y) :- madre(X,Y).
padres(X,Y) :- padre(X,Y).
hermano(X,Y) :- /* El hermano of X es Y si */
masculino(Y) /* Y es masculino y */
masculino(Y) , /* Y es masculino y */
padres(X,P) , /* los padres de X son P y */
padres(Y P) /* los padres de Y son P y */
padres(Y,P) , /* los padres de Y son P y */
not(X=Y). /* X y Y no son el mismo */
hermana(X,Y) :- /* La hermana de X es Y si */
femenino(Y) , /* Y es femenino y */
femenino(Y) , / Y es femenino y / padres(X,P) , /* los padres de X son P y */
padres(Y,P) , /* los padres de Y son P y */
p ( , ) , / p y /
not(X=Y). /* X y Y no son el mismo */
tio(X,U) :- /* El tio de X es U si */
madre(X,P) , /* la madre de X es P y */
hermano(P,U). /* el hermano de P es U. */
tio(X,U) :- /* el tio de X es U si */
padre(X P) /* el padre de X es P y */
padre(X,P) , /* el padre de X es P y */
hermano(P,U). /* el hermano of P es U */
abuelo(X,G) :- /* El abuelo de X es G si */
padre(P G) /* si el padre de P es G */
padre(P,G) , /* si el padre de P es G */
madre(X,P). /* y la madre de X es P.
*//
abuelo(X G) :- /* El abuelo of X es G si */
abuelo(X,G) : / El abuelo of X es G si / padre(X,P) , /* el padre de X es P */
padre(P G) /* el padre de P es G */
padre(P,G). / el padre de P es G /
?-hermana(alan X) write(X)
? hermana(alan,X), write(X).
L S lid
La Salida es:
andrea Yes.
Simulación de compuertas lógicas en PROLOG
PROLOG
E ib PROLOG
Escriba en PROLOG un programa para
simular (producir) la tabla de verdad del
XOR usando OR, AND, NOT:
cnot(1,0). cnot(0,1).
cand(0 0 0) cand(0 1 0) cand(1 0 0) cand(0,0,0). cand(0,1,0). cand(1,0,0).
cand(1,1,1).
cor(0 0 0) cor(0 1 1) cor(1 0 1) cor(1 1 1) cor(0,0,0). cor(0,1,1). cor(1,0,1). cor(1,1,1).
cxor(X Y Z) :- cxor(X,Y,Z) :
cnot(X,N1), cnot(Y,N2),
cand(X N2 N3) cand(Y N1 N4) cand(X,N2,N3), cand(Y,N1,N4), cor(N3,N4,Z).
?-cxor(I1,I2,S),
write(I1) write(" ") write(I1), write( ), write(I2), write(" "),
write(S) write(" ") nl fail write(S), write( ), nl, fail.
Una corrida puede ser:
U p
?-cxor(I1,I2,S)
? cxor(I1,I2,S) 1 1 0
1 0 1 1 0 1 0 1 1 0 0 0 No
No.
Variables Libres y Acotadas a ab es b es y cotadas
Se dice que una variable es LIBRE si Se dice que una variable es LIBRE si PROLOG no conoce su valor.
Se dice que una variable es ACOTADA q
si PROLOG conoce su valor.
Ejemplo:
le_gusta(elena,lectura).
le gusta(john computadoras) le_gusta(john,computadoras).
le_gusta(john,ciclismo).
le gusta(leonardo ciclismo) le_gusta(leonardo,ciclismo).
le_gusta(eric,natacion).
le gusta(eric lectura) le_gusta(eric,lectura).
?-le gusta(X lectura) le gusta(X natacion)
? le_gusta(X,lectura),le_gusta(X,natacion).
Por ejemplo, en la meta:
?-le gusta(X,lectura), le gusta(X,natacion)._gu a( , u a), _gu a( , a a o ) en la submeta le gusta(X lectura) la variable X en la submeta le_gusta(X,lectura) la variable X ocurre libre, mientras que en la submeta
le gusta(X natacion) la variable X ocurre le_gusta(X,natacion) la variable X ocurre acotada. Pues cuando el mecanismo de
backtraking inicia instancia la variable X con backtraking inicia instancia la variable X con elena.
Objetos Compuestos Objetos Co puestos
Un Objeto Compuesto consiste de un functorj p y los subobjetos que lo conforman, esto es:
functor(obj1,obj2,. . .,objn) Un objeto compuesto puede se vacio:
functor() ó functor functor() ó functor
Ejemplo: estudiante es un objeto compuesto
lee_estudiante(e(Nombre,Nota1,Nota2,Promedio,Resultado)) :- write("Cual es su nombre? "), read(Nombre),
write("Nota en examen 1? ") read(Nota1) write( Nota en examen 1? ), read(Nota1), write("Nota en examen 2? "), read(Nota2), Promedio = (Nota1 + Nota2)/2,
paso(Promedio Resultado) paso(Promedio,Resultado).
paso(Promedio,Resultado) :- Promedio >= 70, l d 'S'
Resultado = 'S';
Promedio < 70, Promedio >= 60, Resultado = 'A';
Promedio < 60, Resultado = 'P'.
run:- lee_estudiante(E),nl,write(E),nl,nl,
write("Desea continuar(s/n)"),read(Ch), =(Ch,'n').
run:-nl,nl,write("Digite los datos de otro ( g estudiante"),nl,nl,run.
?-run.
/* VER CORRIDA EJ8.SPJ */
Ejemplo: estudiante es un objeto compuesto V2
l t di t ( (N b N t 1 N t 2 P di R lt d )) lee_estudiante(e(Nombre,Nota1,Nota2,Promedio,Resultado))
:- write("Cual es su nombre? "), read(Nombre), write("Nota en examen 1? "), read(Nota1), write( Nota en examen 1? ), read(Nota1), write("Nota en examen 2? "), read(Nota2), Promedio is (Nota1 + Nota2)/2,
paso(Promedio,Resultado).
i i t di t ( (N b N t 1 N t 2 P di R lt d ))
imprime_estudiante(e(Nombre,Nota1,Nota2,Promedio,Resultado)) :- write(" Nombre: "), write(Nombre), nl,
write(" Examen 1: "), write(Nota1), nl, write( Examen 1: ), write(Nota1), nl, write(" Examen 2: "), write(Nota2), nl, write(" Promedio: "), write(Promedio), nl, write(" Resultado: "), write(Resultado), nl.
Ejemplo: estudiante es un objeto compuesto V2
(P di R lt d ) P di 70
paso(Promedio,Resultado) :- Promedio >= 70, Resultado is 'S';
Promedio < 70, Promedio < 70, Promedio >= 60, Resultado is 'A';
Promedio < 60, Resultado is 'P'.
run:- lee_estudiante(E),nl, imprime_estudiante(E),nl,nl, write("Desea continuar(s/n)"),read(Ch), =(Ch,'n').
write( Desea continuar(s/n) ),read(Ch), (Ch, n ).
run:-nl,nl,write("Digite los datos de otro estudiante"),nl,nl,run.
?-run.
Recursividad en PROLOG
Ejemplo 1:
u(1,2).
u(N,Res) :- N > 1,( , ) ,
N1 is N - 1, /* OJO dejar espacio después del - */
u(N1,Res1),( , ),
Res is (2 * Res1).
?-u(4,X), write(X).
Salida:
Salida:
16Yes..
Ejemplo 2:
Ejemplo 2:
fibonacci(1,1).
fibonacci(2,1).
fibonacci(N F) :- fibonacci(N,F) :-
N > 2,
M is N - 1, K is N - 2, K is N 2,
fibonacci(M,G), fib i(K H) fibonacci(K,H), F is G + H.
?-fibonacci(6 Res) write(Res)
?-fibonacci(6,Res), write(Res).
Listas en PROLOG stas e O OG
Las Listas en PROLOG se manejan a Las Listas en PROLOG se manejan a través de Recursión.
Las listas se encierran entre los
operadores [ ] y se separan por comas.
Ejemplos
[1, 2, 8]
[perro, gato, canario]
["Luisa" "Juan"]
[ Luisa , Juan ]
PROLOG divide una lista en dos t
partes:
Head o cabeza (primer elemento de la lista)(p ) Tail o resto (una lista menos la cabeza)
Ejemplos:
Lista Head Tail
Lista Head Tail
[1,2,3] 1 [2,3]
[[1 2 3] [7 8] []] [1 2 3] [[7 8] []]
[[1,2,3],[7,8],[]] [1,2,3] [[7,8],[]]
[] indefinido indefinido
[ | ] [] []
[ | ] [] []
NOTA: PROLOG usa | como separador entre el NOTA: PROLOG usa | como separador entre el Head y el Tail
Más ejemplos: ás eje p os
Lista 1 Lista 2 Instanciación
[1,2,3,4,7,8] [X|Y] X=1, Y=[2,3,4,7,8]
[7] [X|Y] X=7, Y=[]
[12 3 9 0] [X Y|Z] X=12 Y=3 Z=[9 0]
[12,3,9,0] [X,Y|Z] X=12, Y=3, Z=[9,0]
[1,2] [3|X] falla
[caballo|Q] [P|blanco] P=caballo, Q=blanco
[ |Q] [ | ] , Q
Ejemplos de programas con listas Imprimir una lista
imprime_lista([]). p ([])
imprime_lista([H|T]) :- write(H), write(" "), imprime lista(T)
imprime_lista(T).
?-imprime_lista([5,2,8,9,22]).
Pertenece a una lista e e ece a u a s a
miembro(Nombre [Nombre| ]) miembro(Nombre,[Nombre|_]).
miembro(Nombre,[_|Tail]):- miembro(Nombre,Tail).
?-miembro(2,[5,6,2,7,89,0]).
? miembro(2,[5,6,2,7,89,0]).
Lectura de una Lista ec u a de u a s a
leerlista([X|Xr]):- leerlista([X|Xr]):
read(X),leerlista(Xr).
leerlista([]).
?-leerlista(X),write(X).
? leerlista(X),write(X).
Un ejemplo completo
append([],Lista,Lista).
d([X|L1] L2 [X|L3]) d(L1 L2 L3) append([X|L1], L2, [X|L3]) :- append(L1,L2,L3).
pares(X [X| ]) :- Z is X mod 2 Z is 0 pares(X,[X|_]) : Z is X mod 2, Z is 0.
pares(X,[_|Cola]) :- pares(X,Cola).
ultimo(X,[X]).
ultimo(X,[_|Cola]) :- ultimo(X,Cola).
consecutivos(X,Y,[X,Y|_]).
consecutivos(X Y [ |Cola]) :- consecutivos(X Y Cola) consecutivos(X,Y,[_|Cola]) : consecutivos(X,Y,Cola).
([] []) invierte([],[]).
invierte([H|T],L) :- invierte(T,Z), append(Z,[H],L).
burbuja(L,O) :- append(X,[A,B|Y],L), B < A,,
append(X,[B,A|Y],M),
burbuja(M,O), !.
b b j (L L) burbuja(L,L).
imprime([]) imprime([]).
imprime([Head|Tail]) :- write(Head),nl,imprime(Tail).
leerlista([X|Xr]):- read(X),leerlista(Xr).
leerlista([]).
CORRIDAS ( j14 j) CORRIDAS: (ver ej14.spj)
%?-leerlista(X),imprime(X).
%?-append([4 5 2 3] [5 62 23 3 0] L) write(L)
%? append([4,5,2,3],[5,62,23,3,0],L),write(L).
%?-pares(X,[3,4,6,9,7]),write(X).
%?-ultimo(X [3 4 6 9 7]) write(X)
%? ultimo(X,[3,4,6,9,7]),write(X).
%?-consecutivos(6,9,[3,4,6,9,7]).
%?-invierte([3 4 6 9 7] X) write(X)
%?-invierte([3,4,6,9,7],X),write(X).
?-burbuja([3,4,6,9,7],X),write(X).
Más Ejemplos
suma_lista([],0).
l ([ | O ] )
suma_lista([CABEZA|COLA], RESULT) :- suma_lista(COLA,R1),
RESULT is CABEZA + R1.
multiplica_lista([],1).
l i li li ([CABEZA|COLA] RESULT) multiplica_lista([CABEZA|COLA], RESULT) :-
multiplica_lista(COLA,R1), RESULT is CABEZA * R1.
Más Ejemplos suma_dos_listas([],[],[]).
suma dos listas([CABEZA1|COLA1]
suma_dos_listas([CABEZA1|COLA1],
[CABEZA2|COLA2], [CABEZA3|COLA3]) :- CABEZA3 is CABEZA1 + CABEZA2,,
suma_dos_listas(COLA1, COLA2, COLA3).
producto_dos_listas([],[],[]).
producto_dos_listas([CABEZA1|COLA1], [CABEZA2|COLA2] [CABEZA3|COLA3]) [CABEZA2|COLA2], [CABEZA3|COLA3]) :-
CABEZA3 is CABEZA1 * CABEZA2,
producto dos listas(COLA1 COLA2 COLA3)
producto_dos_listas(COLA1, COLA2, COLA3).
Ejemplo: estudiante es un objeto compuesto V3
imprime_lista([]).
imprime_lista([CABEZA|COLA]) :- l l
nl, nl,
imprime_estudiante(CABEZA), write(" "),
imprime_lista(COLA).p
lee_lista([CABEZA|COLA]) :- datos_estudiante(CABEZA), lee lista(COLA)
lee_lista(COLA).
lee_lista([]).
invoca_datos_estudiante :- l li t (L1)
lee_lista(L1),
write("RESULTADO:"), imprime_estudiante(L1).
imprime_estudiante(e(NOMBRE,NOTA1,NOTA2,PROMEDIO,RESULTADO)) :- write(" Nombre: "), write(NOMBRE), nl,
write(" Examen 1: "), write(NOTA1), nl, write(" Examen 2: ") write(NOTA2) nl write( Examen 2: ), write(NOTA2), nl, write(" Promedio: "), write(PROMEDIO), nl, write(" Resultado: "), write(RESULTADO), nl.
d di (d (NOMBRE NOTA1 NOTA2 PROMEDIO RESULTADO))
datos_estudiante(datos(NOMBRE, NOTA1, NOTA2, PROMEDIO, RESULTADO)):- write("Nombre del Estudiante"),nl,
read(NOMBRE),nl,
write("Nota Del Examen #1"),nl,( ) read(NOTA1),nl,
write("Nota Del Examen #2"),nl, read(NOTA2),nl,
PROMEDIO is (NOTA1 + NOTA2)/2 PROMEDIO is (NOTA1 + NOTA2)/2, resultado(PROMEDIO, RESULTADO).
resultado(P,R) :- P >= 70, R ' '
R = 'S'.
resultado(P,R) :- P >= 60, P < 70,
R = 'A'.
resultado(P,R) :- P < 60, R = 'P'.
?-invoca_datos_estudiante.
Ejemplos de sumatorias j p
sumar(1,1) .
sumar(N,Res) :- N1 is N - 1, sumar(N1,R1), Res is R1 + N.
armonica(1,1) .
armonica(N,Res) :- N1 is N - 1, armonica(N1,R1), Res is R1+1/N.
%?-sumar(20,X),write(X).
?-armonica(20,X),write(X).
El algoritmo de unificación usado por PROLOG
PROLOG
Una variable libre puede ser unificada con Una variable libre puede ser unificada con cualquier término, luego la variable se considera acotada.
Una constante puede ser unificada con si misma o con una variable libre.
Un objeto compuesto puede ser unificado con un objeto compuesto, donde ambosj p , tengan los mismos functores y el mismo número de argumentos, de modo que los términos son unificados dos a dos.