PROgramación LOGica PROLOG Dr. Oldemar Rodríguez Rojas Escuela de Informática Universidad de Nacional
Dónde bajar? Strawberry PROLOG: www.dobrev.com
PROLOG -> PROgramming in LOGig Paradigma -> El lenguaje de la lógica puede ser usado para programar Padre de PROLOG -> Francés Alain Colmerauer Fue desarrollado en 1970 en la Universidad de Marseilles En el curso usaremos Strawberry PROLOG OG 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(_,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" Una regla es: le_gusta(juan,x):-le_gusta(tomas,x). que corresponde a la regla lógica: o equivalentemente: a tomas le gusta X => a juan le gusta X a juan le gusta X si a tomas le gusta X
Dos Corridas:?-le_gusta(juan,baseball) Yes.?-le_g gusta(jony,tenis) Yes
Variables: ab En la regla: le_gusta(juan,x) :- le_gusta(tomas,x). aparece la variable X La variables deben comenzar con letra mayúscula.
Uso del fail Cuando PROLOG tiene una meta interna encuentra solamente una solución para cada 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 solamente una solución. El uso del fail forzará el backtraking (reevaluación) en ambas situaciones i con lo que si se encontrarán todas las soluciones.
EJEMPLO: Versión sin fail padre(leonardo,katherine). padre(carlos,jason). padre(carlos,marilyn). todos :- padre(x,y), write(x), write(" es el padre de "), write(y),nl.?-todos.
Salida: leonardo es el padre de katherine Yes.
EJEMPLO: Versión con fail padre(leonardo,katherine). padre(carlos,jason). padre(carlos,marilyn). todos :- padre(x,y), write(x), write(" es el padre de "), write(y),nl,fail.?-todos.
Salida: leonardo es el padre de katherine carlos es el padre de jason carlos es el padre de marilyn No.
Ejemplo de unificación de variables:?-le_g gusta(persona,tenis),write(persona). ( ) Salida: elena Yes?-le_gusta(Persona,tenis),write(Persona), tenis) write(" "), fail. Salida: elena marco _0 juan No.
Objetos y Relaciones Toda clausula en PROLOG está conformada por relaciones que afectan a objetos. Los nombres de las relaciones y de los objetos deben estar escritos en minúscula.
Ejemplo 2: Metas (Goals) compuestas carro(toyota,130000,3,rojo,12000). 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(" "). Salida: toyota 130000 3 rojo 12000 Yes.
Observación: la, es el AND el ; es el OR P<25000 invoca en realidad d <(P,25000)
Variables ab Anónimas Para variables anónimas se utiliza "_", por ejemplo:?-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: se lee "a toda persona le gusta el tenis le_gusta(_,tenis). tenis)
El mecanismo"backtraking" (reevaluación) Ejemplo 3: alumno(peter,9). alumno(paul,10). 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 ana peter ana susan susan peter susan ana No.
El mecanismo"backtraking" funciona como sigue:
Ejemplo 4: Uso del Not Queremos escribir un programa que le 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 requisitos pedidos por Sofía, a saber, el novio debe ser vegetariano y no fumador.
hombre(jose). hombre(bill). hombre(tom). fumador(jorge). fumador(tom). vegetariano(jose). vegetariano(tom). sofia_ hace_pareja(x) :- hombre(x), not(fumador(x)). ( 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: una posible pareja parasofia es: jose Yes.
Ejemplo 5: un árbol genealógico masculino(alan). masculino(carlos). masculino(luis). masculino(ivan). femenino(ana). femenino(andrea). femenino(eugenia). femenino(damaris). madre(eugenia,ana). madre(alan,damaris). padre(alan,luis). 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 */ padres(x,p), /* los padres de X son P y */ padres(y,p), /*lospadresdeysonpy de son */ 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 */ padres(x,p), /* los padres de X son P y */ padres(y,p), /* los padres de Y son 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 */ 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 */ madre(x,p). */ /* y la madre de X es P. 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 */?-hermana(alan hermana(alan,x), write(x).
La Salida es: andrea Yes.
Simulación de compuertas lógicas en 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(000) cand(0,0,0). cand(0,1,0). cand(010) cand(1,0,0). cand(100) cand(1,1,1). cor(000) cor(0,0,0). cor(0,1,1). cor(011) cor(1,0,1). cor(101) cor(1,1,1). cor(111) cxor(x,y,z) :- cnot(x,n1), cnot(y,n2), cand(x,n2,n3), N3) cand(y,n1,n4), N4) cor(n3,n4,z).?-cxor(i1,i2,s), write(i1), write(" "), write(i2), write(" "), write(s), write(" "), nl, fail.
Una corrida puede ser:?-cxor(i1,i2,s) 1 1 0 101 1 0 1 1 0 0 0 No.
Variables ab Libres y Acotadas 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,ciclismo). le_gusta(leonardo,ciclismo). le_gusta(eric,natacion). le_gusta(eric,lectura). lectura)?-le le_gusta(x,lectura),le_gusta(x,natacion). lectura)
Por ejemplo, en la meta:?-le_gusta(x,lectura), u a), le_gusta(x,natacion). a a en la submeta le_gusta(x,lectura) lectura) la variable X ocurre libre, mientras que en la submeta le_gusta(x,natacion) la variable X ocurre acotada. Pues cuando el mecanismo de backtraking inicia instancia la variable X con elena.
Objetos Compuestos Un Objeto Compuesto consiste de un functor y los subobjetos que lo conforman, esto es: functor(obj 1,obj 2,...,obj n ) Un objeto compuesto puede se vacio: 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 2? "), read(nota2), Promedio = (Nota1 + Nota2)/2, paso(promedio,resultado). paso(promedio,resultado) :- Promedio >= 70, 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 estudiante"),nl,nl,run.?-run. /* VER CORRIDA EJ8.SPJ */
Ejemplo: estudiante es un objeto compuesto V2 lee_estudiante(e(nombre,nota1,nota2,promedio,resultado)) t (N N t N t lt d :- write("cual es su nombre? "), read(nombre), write("nota en examen 1? "), read(nota1), write("nota en examen 2? "), read(nota2), Promedio is (Nota1 + Nota2)/2, paso(promedio,resultado). imprime_estudiante(e(nombre,nota1,nota2,promedio,resultado)) i t (N N t N t d :- write(" Nombre: "), write(nombre), 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 paso(promedio,resultado) d :- Promedio >= 70, Resultado is 'S'; 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), ),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: 16Yes..
Ejemplo 2:
fibonacci(1,1). fibonacci(2,1). fibonacci(n,f) :- N > 2, M is N - 1, KisN- 2, fibonacci(m,g), fibonacci(k,h), i(k F is G + H.?-fibonacci(6,Res), write(res).
Listas en PROLOG OG 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"]
PROLOG divide una lista en dos partes: Head o cabeza (primer elemento de la lista) Tail o resto (una lista menos la cabeza) Ejemplos: Lista Head Tail [1,2,3] 1 [2,3] [[123][78][]] [[1,2,3],[7,8],[]] [123] [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: 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] [1,2] [3 X] falla [caballo Q] [P blanco] P=caballo,,Q=blanco
Ejemplos de programas con listas Imprimir una lista imprime_lista([]). imprime_lista([h T]) :- write(h), write(" "), imprime imprime_lista(t).?-imprime_lista([5,2,8,9,22]).
Pertenece e eceau una lista sa miembro(nombre,[nombre _]). miembro(nombre,[_ Tail]):- miembro(nombre,tail).?-miembro(2,[5,6,2,7,89,0]).
Lectura de una Lista leerlista([x Xr]):- read(x),leerlista(xr). leerlista([]).?-leerlista(x),write(x).
Un ejemplo completo append([],lista,lista). append([x L1], L2, [X L3]) :- append(l1,l2,l3). L2 L3) pares(x,[x _]) :- ZisXmod2 2, Zis0 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).
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),!. burbuja(l,l). b L) imprime([]). imprime([head Tail]) :- write(head),nl,imprime(tail). leerlista([x Xr]):- read(x),leerlista(xr). leerlista([]).
CORRIDAS: (ver ej14.spj) j) %?-leerlista(x),imprime(x). %?-append([4 append([4,5,2,3],[5,62,23,3,0],l),write(l). [5 23 3 %?-pares(x,[3,4,6,9,7]),write(x). %?-ultimo(x[34697])write(x) ultimo(x,[3,4,6,9,7]),write(x). %?-consecutivos(6,9,[3,4,6,9,7]). %?-invierte([34697]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). suma_lista([cabeza COLA], RESULT) :- suma_lista(cola,r1), RESULT is CABEZA + R1. multiplica_lista([],1). multiplica_lista([cabeza COLA], li li RESULT) :- multiplica_lista(cola,r1), RESULT is CABEZA * R1.
Más Ejemplos suma_dos_listas([],[],[]). 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]) :- CABEZA3 is CABEZA1 * CABEZA2, producto_dos_listas(cola1, dos COLA2, COLA3).
Ejemplo: estudiante es un objeto compuesto V3 imprime_lista([]). imprime_lista([cabeza COLA]) :- nl, nl, imprime_estudiante(cabeza), write(" "), imprime_lista(cola). lee_lista([cabeza COLA]) :- datos_estudiante(cabeza), lee_lista(cola). lista(cola) lee_lista([]). invoca_datos_estudiante :- lee_lista(l1), li 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(" Promedio: "), write(promedio), nl, write(" Resultado: "), write(resultado), nl. datos_estudiante(datos(nombre, di (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, resultado(promedio, RESULTADO). resultado(p,r) :- P >= 70, R = 'S'.' resultado(p,r) :- P >= 60, P < 70, R = 'A'. resultado(p,r) :- P < 60, R = 'P'.?-invoca_datos_estudiante.
Ejemplos de sumatorias 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 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 ambos tengan los mismos functores y el mismo número de argumentos, de modo que los términos son unificados dos a dos.