Source: http://www.slideshare.net/uni_fcys_sistemas/programacion-practica-prolog
Timestamp: 2016-05-31 19:30:38+00:00

Document:
by Washington Torres
Federico França
Universidad de Oviedo Escuela Universitaria de Ingeniería Técnica de Informática de Oviedo Programación Práctica en Prolog Jose E. Labra G. http://lsi.uniovi.es/~labraÁrea de Lenguajes y Sistemas Informáticos Departamento de Informática Octubre - 1998
Tabla de Contenidos1 Introducción _________________________________________________________ 32 Hechos ______________________________________________________________ 33 Reglas ______________________________________________________________ 3 3.1 Reglas simples ______________________________________________________ 3 3.2 Reglas con Variables _________________________________________________ 4 3.3 Reglas Recursivas ___________________________________________________ 4 3.4 Utilización de funciones _______________________________________________ 4 3.5 Datos Compuestos ___________________________________________________ 44 Unificación __________________________________________________________ 45 Listas _______________________________________________________________ 6 5.1 Definición _________________________________________________________ 6 5.2 Recorrer una lista ____________________________________________________ 6 5.3 Recorrer una lista tomando elementos de dos en dos___________________________ 7 5.4 Búsqueda de elementos en una lista _______________________________________ 7 5.5 Generación de una lista mediante concatenación de otras dos ____________________ 8 5.6 Descomposición de una lista en partes_____________________________________ 8 5.7 Generación de una lista filtrando elementos de otra lista ________________________ 9 5.8 Aplicación de un predicado a todos los elementos ____________________________ 9 5.9 Permutaciones de una lista _____________________________________________ 96 Aritmética ___________________________________________________________ 97 Aritmética con Listas _________________________________________________ 11 7.1 Obtener un valor a partir de una lista _____________________________________ 11 7.2 Acumulación de Resultados ___________________________________________ 11 7.3 Combinación miembro a miembro de los elementos de dos listas ________________ 11 7.4 Generación de una lista a partir de un valor ________________________________ 11 7.5 Generación de listas por filtrado de elementos ______________________________ 12 7.6 Clasificación de listas________________________________________________ 12 7.7 Creación de otra estructura a partir de una lista______________________________ 13 7.8 Otras Estructuras Recursivas___________________________________________ 138 Predicados Internos __________________________________________________ 14 8.1 Conversión de tipos _________________________________________________ 14 8.2 Chequeo de tipos ___________________________________________________ 14 8.3 Inspección de estructuras _____________________________________________ 15 8.4 Predicados meta-lógicos ______________________________________________ 16 8.4.1 Chequeo de tipo___________________________________________________________ 16 8.4.2 Comparación de términos no básicos ___________________________________________ 16 8.4.3 Conversión de Datos en Objetivos _____________________________________________ 17 8.5 Corte ____________________________________________________________ 18 8.5.1 Aplicaciones del Corte ______________________________________________________ 18 8.6 Predicados Extra-lógicos _____________________________________________ 21 8.6.1 Entrada/Salida ____________________________________________________________ 21 8.6.2 Acceso a la Base de Datos ___________________________________________________ 23 8.7 Predicados de Segundo Orden__________________________________________ 249 Ejercicios Propuestos _________________________________________________ 2510 Bibliografía Comentada _______________________________________________ 2811 Indice ______________________________________________________________ 30
Programación Práctica en Prolog Chequeo de tipo1 IntroducciónCon estos apuntes se muestran las diferentes características del núcleo del lenguaje Prolog mediante sencillosejemplos. Se ha realizado un tratamiento especial a las listas y a los diversos esquemas recursivos para trabajar conlistas. El objetivo es ayudar al lector a identificar esquemas de programación que puedan servirle para resolverproblemas similares. No se ha pretendido realizar una guía detallada sino una presentación práctica informal dellenguaje. El lector que esté interesado en profundizar en el lenguaje, deberá consultar los libros de la bibliografía.Con el fin de facilitar la lectura, se utilizan los siguientes símbolos: Clave: 4 Punto importante a recordar . Posibles ejercicios & Comentarios avanzados ( Notas sobre portabilidadEn la presentación de ejemplos se utiliza una tabla escribiendo el código y las preguntas en la parte izquierda y loscomentarios en la parte derecha.2 Hechos/* Relacion Progenitor */ Se describen una serie de hechos conocidos sobre unaprogenitor(pilar,belen). familia.progenitor(tomas,belen).progenitor(tomas,lucia).progenitor(belen,ana). 4 Sintaxis de Prolog: Constantes y predicadosprogenitor(belen,pedro). empiezan por minúscula. Los hechos acaban en punto.progenitor(pedro,jose). Variables comienzan por mayúscula.progenitor(pedro,maria).El programa anterior debe ser cargado en el sistema. Una vez cargado, es posible realizar preguntas:| ?- progenitor(pilar,belen). El sistema puede responder:Yes 1.-Yes: Se puede deducir y el objetivo no tiene variables. 2.-No: No puede deducir a partir del programa| ?- progenitor(pilar,lucia). La respuesta No indica que no se puede deducir. En laNo vida real, podría ocurrir que pilar fuese madre de lucía (parece lo más lógico) pero el sistema supone que todo lo que no está declarado es falso 1 3.- Substitución de Respuesta: Se puede deducir y el| ?- progenitor(belen,X). objetivo tiene variables. Se indica el valor que toman lasX = ana ; variables en la resolución del objetivo.X = pedro En caso de que haya más de una solución. Cuando el sistema obtiene una solución espera a que el usuario introduzca <; > para solicitar más soluciones o <Enter> para finalizar. La búsqueda de otras soluciones se realiza mediante backtracking3 Reglas3.1 Reglas simples/* Reglas */cuida(belen,pedro):-paro(belen), La regla equivale a: “Belén cuida a Pedro si belén está en bueno(pedro). paro y Pedro es bueno”. En lógica de predicados sería:/* 2 hechos más */paro(belen). paro(belen)∧bueno(pedro)→cuida(belen,pedro)bueno(pedro). El símbolo :- podría interpretarse como: ← (si)1 Presunción de mundo cerrado (CWA-closed world assumption) 3
Programación Práctica en Prolog Chequeo de tipo3.2 Reglas con Variablesmadre(X,Y):-mujer(X), Equivale a: progenitor(X,Y). Para todo X e Y, si X es mujer y X es el progenitor de Y, entonce X es la madre de Ymujer(pilar). mujer(belen).mujer(lucia). mujer(ana).mujer(maria). 4 En lógica de predicados:hombre(tomas). hombre(pedro). ∀x∀y(mujer(x)∧progenitor(x,y)→madre(x,y))hombre(jose).| ?- madre(belen,pedro). La programación lógica basa su modelo en layes utilización de relaciones, lo cual permite que un| ?- madre(X,belen). mismo procedimiento sirva para diferentesX = pilar ; propósitos dependiendo de qué variables estánno instanciadas 2| ?- madre(belen,X). En el ejemplo, una misma regla madre sirve para:X = ana ; Comprobar si belen es madre de pedro.X = pedro Calcular la madre de belén Calcular los hijos de belénno Calcular parejas de madres/hijos| ?- madre(X,Y).X = pilar , 4 Obsérvese que las variables de los objetivosY = belen ; corresponden a cuantificadores existenciales, es decir:X = belen , ?- madre(belen,X) equivale a: ? ∃x (madre(belen,x))Y = ana ;X = belen , Téngase en cuenta que a la hora de resolver la preguntaY = pedro ; madre(belen,X) con la cabeza de la regla madre(X,Y) es necesario renombrar la variable Xno El lenguaje Prolog realiza internamente un proceso de unificación que se describe en la página 4.3.3 Reglas Recursivas En general, en una definición recursiva, es necesario considerar 2 casos:antepasado(X,Y):-progenitor(X,Y). Caso básico: Momento en que se detiene la computaciónantepasado(X,Y):-progenitor(X,Z), Caso Recursivo: Suponiendo que ya se ha antepasado(Z,Y). solucionado un caso más simple, cómo descomponer el caso actual hasta llegar al caso simple. 4 Tanto el caso básico como el caso recursivo no tienen porqué ser únicos (puede haber varios casos básicos y varios casos recursivos) Las definiciones recursivas se resuelven de la misma| ?- antepasado(belen,X).X = ana ; forma que las reglas comunes. En la traza de este tipo de definiciones tiene especial importancia elX = pedro ; renombramiento de variables.X = jose ; & Considerando la relación progenitor como unX = maria ; enlace entre dos nodos de un grafo. La relación antepasado indicaría si hay camino entre dos nodosno del grafo dirigido acíclico formado por la relación| ?- antepasado(X,belen). progenitor. Este tipo de relaciones se utiliza enX = pilar ; diversos contextos como la búsqueda de caminos entre ciudades, la simulación de movimientos de unX = tomas ; autómata, etc.no . Describir en Prolog una serie de caminos entre diversas ciudades y construir un predicado que indique2 Se dice que una variable está instanciada si tiene un valor concreto (en realidad ya no sería una variable) 4
Programación Práctica en Prolog Chequeo de tipo si 2 ciudades están conectadas.3.4 Utilización de funciones Se utiliza la función: cabeza(x)=”cabeza de x”grande(pepe). El programa indica:grande(cabeza(juan)). “Pepe es grande, la cabeza de juan es grande, si X esgrande(X):-mayor(X,Y). mayor que Y, entonces X es grande, además: Lamayor(cabeza(X),cabeza(Y)):- progenitor(X,Y). cabeza de X es mayor que la de Y si X es el progenitor de Y” 4 Prolog no necesita declaraciones de tipos.| ?- grande(X).X = pepe ; 4 Las variables en Prolog no tienen tipo, de ahí que la respuesta X puede ser una persona (pepe) o unaX = cabeza(juan) ; cabeza (cabeza(juan))X = cabeza(pilar) ;X = cabeza(tomas) ;...3.5 Datos Compuestos punto(X,Y) representa un punto de coordenadas (x,y)horizontal(seg(punto(X,Y), seg(p1,p2) representa un segmento cuyos extremos punto(X1,Y))). son los puntos p1 y p2vertical(seg(punto(X,Y), punto(X,Y1))). Los argumentos de una función pueden ser funciones| ?- horizontal(seg(punto(1,2),punto(3,2))). P = punto(_47796,2) indica que P es un puntoYes cuya primera coordenada es una variable sin| ?- horizontal(seg(punto(1,2),P)). instanciar3 y cuya segunda coordenada es 2P = punto(_47796,2) La última respuesta indica que para que un| ?- horizontal(P),vertical(P).P=seg(punto(_29128,_29130),punto(_29128,_29130) segmento sea vertical y horizontal a la vez, sus) coordenadas deben ser las mismas (los números de las variables X e Y coinciden)4 UnificaciónDurante la resolución de objetivos, el sistema Prolog debe realizar la unificación entre los objetivos y las cabezasde las reglas o los hechos. De forma simplificada, el algoritmo de unificación consiste en:1.- Inicializar σ = substitución vacía2.- Si al aplicar σ a las 2 expresiones, éstas son iguales, finalizar y devolver σ3.- Buscar de izquierda a derecha las primeras subexpresiones diferentes: Si dichas subexpresiones están formadas por una variable v y un término t (tal que v∉ t) 4 Actualizar σ con el resultado de substituir v por t Volver a 2 En caso contrario Finalizar indicando que las expresiones no unifican| ?- f(X,X)=f(a,Y). El operador ‘=’ se cumple si sus argumentos unifican.X = aY = a El operador ‘=’ se cumple si sus argumentos no unifican.| ?- f(X,X)=f(a,Y).no Puesto que Prolog no tiene chequeo de ocurrencias,| ?- p(f(X),g(Z,X))=p(Y,g(Y,a)). se produce un error.X = a ,Z = f(a)3 El formato de las variables sin instanciar varía de un sistema Prolog a otro. En estos apuntes, se utiliza unnúmero de 4 dígitos aleatorio precedido del carácter ‘_’4 La condición v∉ t se conoce como chequeo de ocurrencias (occur check ) y no es implementada por la mayoríade los sistemas Prolog debido a su complejidad. Esto hace que en determinadas ocasiones, el sistema se meta enun bucle infinito tratando de unificar 2 términos 5
Programación Práctica en Prolog Chequeo de tipoY = f(a) 4 Se produce error porque Prolog no implementa| ?- p(X,X)=p(Y,f(Y)). chequeo de ocurrencias y el algoritmo de unificaciónError ..., System Stack Full entra en un bucle infinito. En la página 17 se implementa el algoritmo de unificación con chequeo de ocurrencias.5 Listas5.1 DefiniciónLas listas son una de las estructuras de datos más utilizadas en los programas en lenguaje Prolog y responden a lasiguiente definición:[] es una lista [] denota la lista vacíaSi Xs es una lista entonces [X|Xs] es una lista [X|Xs] denota una lista de cabeza X y cola Xs| ?- [1,2,3] = [1|[2|[3|[]]]].yes El sistema convierte internamente entre: [X,Y,Z] y [X|[Y|[Z|[]]]]| ?- [X|Xs]=[1,2,3]. [X,Y|Z] y [X|[Y|Z]]X = 1 ,Xs = [2,3]| ?- [X|Xs]=[1].X = 1 ,Xs = []| ?- [X,Y|Ys]=[1,2,3].X = 1 ,Y = 2 ,Ys = [3] 4 Se utiliza una sintaxis especial para las listas de caracteres del tipo “abc” que se convierten| ?- X = "abc". internamente en listas de los códigos ASCIIX = [97,98,99] correspondientes. Puesto que las listas son una estructura de datos definida delista([]).lista([X|Xs]):-lista(Xs). forma recursiva. La mayoría de las definiciones identificarán el caso básico con la lista vacía y el caso recursivo con [X|Xs]| ?- lista([1,2]). No todas las definiciones recursivas con listas utilizan esos dosyes casos| ?- lista(X).X = [] ; Como convenio, los nombres de variables en singular (X, Y,...) indican elementos, mientras que en plural indican listasX = [_2440] ; (Xs,Ys,...). Las listas de listas se suelen representar como XssX = [_2440,_4572] ; 4La llamada lista(X) genera por backtracking listas deX = [_2440,_4572,_6708] ; cualquier tipo de elementos.X = [_2440,_4572,_6708,_8848]...5.2 Recorrer una lista hombres(Xs):- Todos los X de Xs cumplenhombres([]).hombres([X|Xs]):-hombre(X), hombre(X) hombres(Xs). noPertenece(X,Xs):- El elemento X no pertenecenoPertenece(X,[]). a la lista Xs (se comprueba que no unifica connoPertenece(X,[Y|Ys]):-X=Y, noPertenece(X,Ys). ningún elemento de Xs| ?- hombres([jose,tomas,pedro]). En las definiciones recursivas, conviene escribiryes el caso básico antes que el caso recursivo ya que| ?- hombres([jose,pilar,tomas]). si la definición unifica con ambos casos y 6
Programación Práctica en Prolog Chequeo de tipono estuviese pusiese el caso recursivo antes, el| ?- noPertenece(pilar,[jose,pilar,tomas]). sistema entraría en un bucle infinito.no De la misma forma, es conveniente que la| ?- noPertenece(luis,[jose,pilar,tomas]). llamada recursiva sea la última llamada de layes definición recursiva (muchos sistemas optimizan las definiciones así escritas)5.3 Recorrer una lista tomando elementos de dos en dostodosIguales([]).todosIguales([X]). todosIguales(Xs):- Los elementos de Xs sontodosIguales([X,X|Xs]):-todosIguales([X|Xs]). todos iguales| ?- todosIguales([1,2,3]). Obsérvese que hay dos casos básicos y que elno caso recursivo no es de la forma [X|Xs].| ?- todosIguales([1,1,1]).yes Obsérvese que los tres casos se excluyen. Como regla general, conviene que los casos de una| ?- todosIguales(X).X = [] ; definición se excluyan. Cuando los casos no se excluyen, al realizar backtracking el sistemaX = [_25576] ; puede obtener respuestas distintas de lasX = [_27704,_27704] ; esperadas.X = [_27704,_27704,_27704] ; . Describir la respuesta ante: ?- todosIguales([2,X,Y]).X = [_27704,_27704,_27704,_27704]5.4 Búsqueda de elementos en una lista pertenece(X,Xs):- X está en la lista Xspertenece(X,[X|Xs]).pertenece(X,[Y|Ys]):- pertenece(X,Ys). El caso básico no es la lista vacía. Además, los casos| ?- pertenece(pedro,[jose,pedro,tomas]). no se excluyen. Una lista que encaje con la primerayes definición, lo hará con la segunda.| ?- pertenece(jose,[]).no La relación pertenece es un claro ejemplo de la flexibilidad de las definiciones en Prolog ya que se| ?- pertenece(X,[jose,pedro,tomas]). puede utilizar para:X = jose ;X = pedro ; 1.- Chequear si un elemento pertenece a una listaX = tomas ; 2.- Obtener todos los elementos de una lista porno backtracking| ?- pertenece(jose,X). 3.- Obtener listas con un elemento X en primera,X = [jose|_6617] ; segunda, ... n-ésima posición.X = [_8808,jose|_8817] ;X = [_8808,_11012,jose|_11021] ;X = [_8808,_11012,_13230,jose|_13239]... eliminna(X,Ys,Zs):-Zs contiene todas laselimina(X,[X|Xs],Xs).elimina(X,[Y|Ys],[Y|Zs]):-elimina(X,Ys,Zs). listas resultantes de eliminar el elemento X de Ys| ?- elimina(1,[1,2,1,3],V).V = [2,1,3] ; 4El predicado selecciona sirve tambiénV = [1,2,3] ; para diversos propósitos: Borrar elementos de una listano Insertar un elemento en diferentes posiciones de una lista| ?- elimina(1,V,[2,3]). 7
Programación Práctica en Prolog Chequeo de tipoV = [1,2,3] ; . Describir el comportamiento delV = [2,1,3] ; predicado si se añade X=Y en la segunda definición.V = [2,3,1] ;noalgunHombre(Xs):-pertenece(X,Xs), hombre(X). algunHombre(Xs):- alguno de los elementos X de Xs cumple la relación hombre(X)| ?- algunHombre([jose,pilar,tomas]).yes5.5 Generación de una lista mediante concatenación de otras dosconcat([],Ys,Ys).concat([X|Xs],Ys,[X|Zs]):-concat(Xs,Ys,Zs). concat(Xs,Ys,Zs):- Zs es el resultado de concatenar las listas Xs e Ys| ?- concat([1,2],[3,4],V).V = [1,2,3,4]| ?- concat([1,2],X,[1,2,3,4]). 4 Obsérvese la flexibilidad de laX = [3,4] definición de concat que permite una gran variedad de usos dependiendo de| ?- concat(X,Y,[1,2,3,4]). qué variables están instanciadas en laX = [] ,Y = [1,2,3,4] ; llamada.X = [1] ,Y = [2,3,4] ;X = [1,2] ,Y = [3,4] ;X = [1,2,3] ,Y = [4] ;X = [1,2,3,4] ,Y = [] ;no5.6 Descomposición de una lista en partesGracias a la flexibilidad de las relaciones lógicas, el predicado concat se utiliza en la definición de una grancantidad de predicados. Definir los predicados prefijo, sufijo y sublista deprefijo(Xs,Ys):- concat(Xs,Bs,Ys).sufijo(Xs,Ys):- concat(As,Xs,Ys). forma recursiva sin la ayuda del predicado concatsublista(Xs,Ys):- concat(AsXs,Bs,Ys), concat(As,Xs,AsXs). Definir mediante concat los predicados: pertenece(X,Xs):-X es un elemento de Xs| ?- prefijo([1,2],[1,2,3,4]).yes reverse (Xs,Ys):-Ys es Xs con los elementos en orden inverso| ?- sufijo([3,4],[1,2,3,4]). adyacentes(X,Y,Xs):-X e Y están en posicionesyes consecutivas en Xs| ?- pertenece1(1,[2,1,3]). ultimo(Xs,X):- X es el último elemento de Xsyes primeros(Xs,Ys):-Ys es el resultado de eliminar el último elemento a Xs| ?- sublista([2,3],[1,2,3,4]).yes 8
Programación Práctica en Prolog Chequeo de tipo5.7 Generación de una lista filtrando elementos de otra lista filtraHombres(Xs,Ys):- Ys contiene todosfiltraHombres([],[]).filtraHombres([X|Xs],[X|Ys]):-hombre(X), los hombres de la lista Xs.filtraHombres(Xs,Ys).filtraHombres([X|Xs],Ys):- mujer(X), . Obsérvese qué ocurre cuando sefiltraHombres(Xs,Ys). solicitan más soluciones por backtracking o cuando se pregunta:| ?- filtraHombres([jose,pilar,tomas],V). ?- filtraHombres(V,[jose,pilar]).V = [jose,tomas] sinDuplicados(Xs,Ys):-Ys contiene lossinDuplicados([],[]). elementos de Xs eliminando elementossinDuplicados([X|Xs],[X|Ys]):-noPertenece(X,Xs), duplicados. sinDuplicados(Xs,Ys).sinDuplicados([X|Xs],Ys):- pertenece(X,Xs), sinDuplicados(Xs,Ys). 4Ambas definiciones son poco eficientes| ?- sinDuplicados([1,1,2,3,2,1,4],V).V = [3,2,1,4] ; . Construir el predicado sinDuplicados para que la lista resultado contenga los elementos en el mismo orden en que aparecen5.8 Aplicación de un predicado a todos los elementosedad(pilar,85). edad(tomas,90).edad(belen,67). edad(lucia,64).edad(ana,34). edad(pedro,36). edades(Xs,Ys):- Ys contiene las edadesedad(jose,10). de los elementos de Ysedades([],[]).edades([X|Xs],[Y|Ys]):-edad(X,Y), edades(Xs,Ys).| ?- edades([jose,pilar,tomas],V). 4Si alguno de los elementos no tieneV = [10,85,90] edad, el predicado falla.| ?- edades([jose,dedo,tomas],V).no| ?- edades(V,[10,85]).V = [jose,pilar]5.9 Permutaciones de una listapermutacion([],[]).permutacion(Xs,[X|Ys]):-elimina(X,Xs,Zs), permutacion(Zs,Ys). permutacion(Xs,Ys):- Ys es una permutación de la lista Xs| ?- permutacion([1,2,3],V).V = [1,2,3] ;V = [1,3,2] ;V = [2,1,3] ;V = [2,3,1] ;V = [3,1,2] ;V = [3,2,1] ;no6 AritméticaCon el fin de aprovechar las posibilidades aritméticas de los computadores convencionales, el lenguaje Prologcontiene una serie de predicados de evaluación aritmética.Al encontrar un objetivo de la forma “? X is E“ el sistema: Evalúa la expresión E hasta obtener un valor aritmético v (si no puede, devuelve un error) El objetivo se cumple si X unifica con v 9
Programación Práctica en Prolog Chequeo de tipoLa expresión E puede contener los operadores aritméticos clásicos (+, -, *, mod, etc.) y valores numéricos. Sicontiene variables, éstas deben estar instanciadas a un valor numérico en el momento de la evaluación.| ?- X is 3+5. La evaluación de 3+5 se realiza internamente enX = 8 una instrucción del procesador.| ?- X is pepe.Error al evaluar Si la expresión no resulta en un valor aritmético, se obtiene un error.| ?- 8 is 3+5.yes| ?- 4 is 3+5.no Al evaluar pueden producirse errores.| ?- X is 4/0.Error aritmético El operador “is” no es nunca un operador de| ?- X is X + 1.Error al evaluar asignación como el := de Pascal. En general, una expresión del tipo X is X+1 no tiene sentido en Prolog .| ?- X = 3, Y is X + 5.X = 3 ,Y = 8 Describir en qué situaciones “X is X + 1” es un error y en qué situaciones falla sin más.| ?- X=0, X is X + 1.no 4 El operador = unifica sus argumentos pero no| ?- X = 3 + 5. evalúa.X = 3 + 5par(X) :- 0 is X mod 2.impar(X) :- 1 is X mod 2.suma(X,Y,Z):- Z is X + Y.| ?- par(3). Con el operador is se pierde la flexibilidad de lasno relaciones lógicas. Lo ideal es que al evaluar| ?- par(4). suma(2,V,5) , el sistema devolviese V=3yes . ¿Por qué se obtiene error al evaluar| ?- suma(2,3,V).V = 5 suma(2,V,5) y no se obtiene error al evaluar par(4)?| ?- suma(2,V,5).Error al evaluarAdemás del predicado is, los predicados de comparación realizan una evaluación aritmética de sus argumentos yse cumplen si los valores obtenidos cumplen las relaciones correspondientes:| ?- 3+5 > 2+6.no & Para la comparación se utiliza el operador “=<” en lugar del más habitual “<=” debido a que éste| ?- 3+5 >= 2+6. último se asemeja a una doble flecha y se reservayes para otros propósitos| ?- 3+5 < 2+6.yes . Describir la diferencia entre el comportamiento de los operadores: “=”, “is ” y “=:=”| ?- 3+5 =< 2+6.yes| ?- 3+5 =:= 2+6.yes| ?- 3+5==2+6.nofact(0,1).fact(N,F):-N > 0, fact(N,F):-F es el factorial de N N1 is N - 1, fact(N1,F1), 4 La versión de factorial aquí presentada es poco F is N * F1. eficiente. 10
Programación Práctica en Prolog Chequeo de tipo| ?- fact(5,V).V = 1207 Aritmética con Listas7.1 Obtener un valor a partir de una listasum([],0).sum([X|Xs],S):-sum(Xs,Sc), S is Sc + X. & Obsérvese la similitud entre las treslong([],0). definiciones. En algunos lenguajes se utilizanlong([X|Xs],L):-long(Xs,Lc), L is Lc + 1. construcciones de orden superior que permiten utilizar una única definición parametrizada por lasprod([],1).prod([X|Xs],P):-prod(Xs,Pc), P is Pc * X. operaciones y constantes5 .| ?- sum([1,2,3,4],V). 4Las definiciones ofrecidas no aprovechan laV = 10 optimización de la recursividad de cola. Consiste| ?- long([1,2,3,4],V). en que el último objetivo de una definiciónV = 4 recursiva sea el predicado que se está definiendo. Los sistemas con dicha optimización permiten que| ?- prod([1,2,3,4],V).V = 24 las definiciones recursivas se comporten de forma similar a un bucle en un lenguaje imperativo. sum1 es una versión optimizada de sum%% Version optimizada de sumsum1(Xs,S):-sumAux(Xs,0,S). 4 La definición de sum1 sigue el patrón desumAux([],S,S). acumulación de resultados que se ve a continuaciónsumAux([X|Xs],Sa,S):-Sn is X + Sa,sumAux(Xs,Sn,S).7.2 Acumulación de ResultadosA diferencia de los lenguajes imperativos, Prolog utiliza variables lógicas. En el momento en que una variablelógica es instanciada, dicho valor no puede modificarse. De esta forma, no es posible utilizar variables globalescuyo valor se modifique durante la resolución del objetivo. Existen ciertos algoritmos que requieren la utilizaciónde un estado que almacena resultados intermedios. Para implementar dichos algoritmos es necesario utilizar unpredicado auxiliar con un argumento extra que almacenará el estado que se modifica.La definición de sum1 de la sección anterior sigue el patrón mencionado.sumAcum(Xs,Ys):-sumAc(Xs,0,Ys). jsumAc([],S,[]). sumAcum(Xs,Ys):- y j = ∑x i=1 i para cada y j ∈ YssumAc([X|Xs],Sa,[Sp|Ys]):-Sp is X + Sa, sumAc(Xs,Sp,Ys). . Construir la definición del predicado| ?- sumAcum([1,2,3,4],V). maximo(Xs,M) que se cumple si M es elV = [1,3,6,10] máximo de los elementos de Xs7.3 Combinación miembro a miembro de los elementos de dos listasprodEscalar(Xs,Ys,P):- pEsc(Xs,Ys,0,P). prodEscalar(Xs,Ys,P) :-P es el productopEsc([],[],P,P).pEsc([X|Xs],[Y|Ys],Pa,Pr):-Pn is Pa + X * Y, escalar de los vectores Xs e Ys (P = Σ xi y i ) pEsc(Xs,Ys,Pn,Pr). 4En esta definición se utiliza además el| ?- prodEscalar([1,2,3],[4,5,6],P). patrón de acumulación de resultadosP = 32 anterior.7.4 Generación de una lista a partir de un valorEs posible generar una lista mediante la descomposición de un valor. En el primer ejemplo, se descompone unnúmero natural hasta llegar a cero, en el segundo, se descompone un intervalo hasta que los extremos son iguales.5 En este sentido, los lenguajes funcionales se caracterizan por utilizar funciones de orden superior, permitiendouna mayor reutilización de código. 11
Programación Práctica en Prolog Chequeo de tiporepite(0,X,[]).repite(N,X,[X|Xs]):-N > 0, N1 is N - 1, repite(N,X,Xs):- Xs con N elementos de valor X repite(N1,X,Xs).intervalo(X,X,[X]).intervalo(X,Y,[X|Xs]):-X < Y, Z is X + 1, intervalo(X,Y,Xs):-Xs es una lista creciente cuyo intervalo(Z,Y,Xs). primer valor es X y su último valor Y| ?- repite(3,a,V).V = [a,a,a] ;| ?- intervalo(1,5,V).V = [1,2,3,4,5] ;7.5 Generación de listas por filtrado de elementosLos siguientes ejemplos muestran cómo se puede generar una o varias listas filtrando los elementos de otras listas.- En pares, la condición de filtrado (ser par) indica si se inserta o no el elemento- En inserta la condición de filtrado (ser menor o mayor que el valor X) indica si se selecciona el elemento Y de la lista que se recorre o el elemento X a insertar- En particion la condición de filtrado indica en qué lista se inserta- En el último caso, se recorren dos listas y la condición indica de cuál de las listas seleccionar el valorpares([],[]).pares([X|Xs],[X|Ys]):-par(X), pares(Xs,Ys). pares(Xs,Ys):-Ys contiene lospares([X|Xs],Ys):- impar(X),pares(Xs,Ys). elementos pares de Xs. Se filtran los elementos pares| ?- intervalo(1,5,V), pares(V,P).V = [1,2,3,4,5] ,P = [2,4] ;inserta(X,[],[X]). inserta(X,Xs,Ys):-Ys es el resultadoinserta(X,[Y|Ys],[X,Y|Ys]):-X < Y.inserta(X,[Y|Ys],[Y|Zs]) :-X >= Y, de insertar X en la posición adecuada inserta(X,Ys,Zs). de la lista ordenada Xs de forma que Ys se mantenga ordenada.| ?- inserta(3,[1,2,4],V).V = [1,2,3,4] ;particion(X,[Y|Ys],[Y|Ps],Gs):- Y < X, particion(X,Ys,Ps,Gs).particion(X,[Y|Ys],Ps,[Y|Gs]):- Y >= X, particion(X,Xs,Ps,Gs):-Ps contiene particion(X,Ys,Ps,Gs). los elementos de Xs más pequeñosparticion(X,[],[],[]). que X y Gs los elementos de Xs más grandes o iguales que X.| ?- particion(3,[2,4,1,5],X,Y).X = [2,1] ,Y = [4,5] ;mezcla(Xs,[],Xs). mezcla(Xs,Ys,Zs):-Zs es una listamezcla([],[Y|Ys],[Y|Ys]).mezcla([X|Xs],[Y|Ys],[X|Zs]):-X < Y, ordenada formada a partir de las listas mezcla(Xs,[Y|Ys],Zs). ordenadas Xs e Ysmezcla([X|Xs],[Y|Ys],[Y|Zs]):-X >= Y, mezcla([X|Xs],Ys,Zs). 4Obsérvese que esta definición| ?- mezcla([1,3,5],[2,4,6],V). consta de dos casos básicos y dosV = [1,2,3,4,5,6] ; recursivos. El segundo caso básico podría haber sido: mezcla([],Ys,Ys) pero no sería excluyente con el primero cuando Xs e Ys están vacías.7.6 Clasificación de listasordenada([]). ordenada(Xs):- Los elementos de Xs están enordenada([X]). 12
Programación Práctica en Prolog Chequeo de tipoordenada([X,Y|Ys]):-X<Y, ordenada([Y|Ys]). orden ascendenteordenaBruto(Xs,Ys):-permutacion(Xs,Ys), . ¿qué patrón sigue la definición de ordenada? ordenada(Ys). ordenaBruto(Xs,Ys):-Ys contiene los elementos de Xs en orden ascendente (utiliza el famoso algoritmo de la fuerza bruta)ordenaIns([],[]). ordenaIns(Xs,Ys):-Ys contiene los elementos deordenaIns([X|Xs],Ys):-ordenaIns(Xs,XsO), Xs en orden ascendente (utiliza el algoritmo de inserta(X,XsO,Ys). inserción)quicksort([],[]).quicksort([X|Xs],Ys):-particion(X,Xs,Ps,Gs), quicksort(Xs,Ys):-Ys contiene los elementos de Xs quicksort(Ps,PsO), en orden ascendente (algoritmo quicksort6 ) quicksort(Gs,GsO), concat(PsO,[X|GsO],Ys). . Escribir la definición del algoritmo de clasificación mergesort (de forma similar a| ?- quicksort([3,1,2,4],V). quicksort, divide la lista en dos mitades de igualV = [1,2,3,4] ; tamaño, las clasifica y las mezcla).7.7 Creación de otra estructura a partir de una listaEn muchas ocasiones puede ser necesario convertir una lista en otra estructura.Supóngase que se desea comprimir una lista con muchos valores repetidos en una estructura que informe del tipode valor y del número de veces que aparece7 . Para ello, se utiliza un término estructurado de la forma “cod(X,N)”indicando que el término X aparece N veces.comprime([],[]).comprime([X|Xs],Ys):-comp(Xs,X,1,Ys). comprime(Xs,Ys):-Ys es una lista cuyos elementos tienen la forma cod(X,N) donde Xcomp([],C,N,[cod(C,N)]). indica un elemento de Xs y N indica el númerocomp([X|Xs],X,N,Ys):-N1 is N+1, de veces que se repite. comp(Xs,X,N1,Ys).comp([X|Xs],Y,N,[cod(Y,N)|Ys]):- X=Y, . Construir un predicado que calcule la comp(Xs,X,1,Ys). frecuencia de cada elemento de una lista| ?- comprime([a,a,b,b,b,c,b,b],V).V = [cod(a,2),cod(b,3),cod(c,1),cod(b,2)]7.8 Otras Estructuras RecursivasLas estructuras recursivas forman una parte fundamental de los lenguajes de programación8 .A continuación se definen unos predicados de conversión entre una lista y árbol binario de búsqueda.Los árboles binarios se definen por inducción de la siguiente forma: vacio ∈ArbolesBinarios Si A1 y A2 ∈ ArbolesBinarios entonces rama(X,A1,A2)∈ArbolesBinarios Ejemplo: rama(2,rama(1,vacio,vacio),vacio).Los árboles de búsqueda se caracterizan porque el valor de cualquier nodo del árbol es mayor que el valor de losnodos a su izquierda y menos que el valor de los nodos a su derecha.insertArbol(X,vacio,rama(X,vacio,vacio)). insertArbol(X,A,An):-An es el árbol de6 El algoritmo quicksort se caracteriza porque, aunque en el caso peor tiene complejidad O(n 2 ), en el caso mediotiene complejidad O(n log2 n)7 Este esquema de codificación se conoce como run-length encoded y es muy utilizado para comprimir imágenes8 Las listas son un caso especial de estructura recursiva 13
Programación Práctica en Prolog Chequeo de tipoinsertArbol(X,rama(X,A1,A2),rama(X,A1,A2)). búsqueda resultante de insertar X en AinsertArbol(X,rama(Y,A1,A2),rama(Y,A1n,A2)):- X < Y, insertArbol(X,A1,A1n).insertArbol(X,rama(Y,A1,A2),rama(Y,A1,A2n)):- listaArbol(Xs,A):- A es el árbol de búsqueda X > Y, insertArbol(X,A2,A2n). creado a partir de la lista XslistArbol(Xs,A):-creaArbol(Xs,vacio,A). . Indicar qué patrón de recursividad se utilizacreaArbol([],A,A). en la definición de listArbolcreaArbol([X|Xs],Ao,Ar):-insertArbol(X,Ao,An), creaArbol(Xs,An,Ar). busca(X,A):-Se cumple si X está en el árbol A| ?- listArbol([2,1,3],V). nodos(A,Xs):- Xs son los nodos del árbol A.V = rama(2,rama(1,vacio,vacio),rama(3,vacio,vacio))busca(X,rama(X,_,_)). & El predicado nodos realiza el recorrido delbusca(X,rama(Y,A1,A2)):-X < Y, busca(X,A1). árbol empezando por los nodos de la izquierda,busca(X,rama(Y,A1,A2)):-X > Y, busca(X,A2). luego el nodo central y finalmente los de la derecha. Este recorrido se conoce comonodos(vacio,[]).nodos(rama(X,A1,A2),Xs):-nodos(A1,Xs1), recorrido inorden. Existen otros recorridos nodos(A2,Xs2), como preorden y postorden concat(Xs1,[X|Xs2],Xs). 4Obsérvese que con los árboles podríanordenArbol(Xs,XsO):-listArbol(Xs,A), nodos(A,XsO). definirse patrones recursivos similares a los definidos para las listas9 .| ?- ordenArbol([2,1,3,4],V).V = [1,2,3,4] ;8 Predicados Internos8.1 Conversión de tiposEn general, Prolog no contiene chequeo de tipos en tiempo de compilación, siendo necesario utilizar una serie depredicados predefinidos que chequean el tipo de sus argumentos. Predicado Condición para que se cumpla Preguntas Simples atom_chars(A,Cs) Cs es la lista de caracteres que | ?- atom_chars(abc,V). representa el átomo A V = [97,98,99] | ?- atom_chars(V,"abc"). V = abc number_chars(N,Cs) Cs es la lista de caracteres que | ?- number_chars(123,V). representa el número N V = [49,50,51] | ?- number_chars(V,"123"). V = 123 number_atom(N,A) A es el átomo que representa el | ?- number_atom(123,V). número N V = 123 | ?- number_atom(V,123). V = 1238.2 Chequeo de tiposEn general, Prolog no contiene chequeo de tipos en tiempo de compilación, siendo necesario utilizar una serie depredicados predefinidos que chequean el tipo de sus argumentos. Predicado Condición para que se cumpla Ejemplos integer( X) X es un entero. 49 Actualmente, se investiga la posibilidad de utilizar lenguajes que definan automáticamente dichos patrones derecursividad para los diferentes tipos de datos definidos por el usuario. 14
Programación Práctica en Prolog Chequeo de tipo float(X) X es un flotante. 4.5 number(X) X es un número. 4 4.5 atom(X) X es un átomo. pepe [] atomic(X) X es un átomo o un número. pepe 4 4,5 [] compound(X) X es un término compuesto. padre(luis,juan) [3] list(X) X es una lista. [] [3] “3,2”sumaLogica(X,Y,Z):-integer(X), integer(Y), sumaLogica(X,Y,Z):-Z es igual a X + Y Z is X + Y. Define un predicado aritmético que admite lasumaLogica(X,Y,Z):-integer(Y), flexibilidad de las relaciones lógicas. integer(Z), X is Z - Y.sumaLogica(X,Y,Z):-integer(X), integer(Z), Y is Z - X.| ?- sumaLogica(2,3,V).V = 5 ;| ?- sumaLogica(3,V,5).V = 2alisar([],[]).alisar([X|Xs],Ls):-list(X), alisar(Xs,Ys):-Ys contiene una lista con los alisar(X,Ls1), elementos de las listas de Xs alisar(Xs,Ls2), concat(Ls1,Ls2,Ls). 4Obsérvese que se utiliza el patrón dealisar([X|Xs],[X|Ls]):- atomic(X), alisar(Xs,Ls). generación de una lista por filtrado de elementos.| ?- alisar([[1,2],[3],[[4]]],V).V = [1,2,3,4]8.3 Inspección de estructuras Predicado Condición para que se cumpla Ejemplos functor(T,F,A) T es un término compuesto de | ?- functor(f(a,b),F,A). functor F y aridad A F=f, A=2 | ?- functor(T,f,2). T = f(_4648,_4650) arg(N,T,A) A es el argumento N-ésimo del | ?- arg(2,f(a,b,c),A). término T A=b | ?- arg(2,f(a,X,c),b). X=b T =.. Ls Ls es una lista cuyo primer | ?- f(a,b) =.. Ls. elemento es el functor de T y Ls = [f,a,b] cuyo resto de elementos son los argumentos de T | ?- T =.. [f,a,b]. T = f(a,b)subTer(T,T).subTer(S,T):-compound(T), subTer(S,T):- Se cumple si S es un T =.. [F|Args], subtérmino de T subTerL(S,Args). & El predicado ‘=..’ también se conoce 15
Programación Práctica en Prolog Chequeo de tiposubTerL(S,[A|As]):- subTer(S,A). como ‘univ’subTerL(S,[A|As]):- subTerL(S,As).| ?- subTer(g(b),f(a,g(b),c)).yes| ?- subTer(X,f(a,g(b))).X = f(a,g(b)) ;X = g(b) ; subTerm(S,T):-Se cumple si S es unX = b ; subtérmino de T.X = a ; 4 En general el predicado ‘=..’ proporcionasubTerm(T,T).subTerm(S,T):-compound(T), la misma expresividad que los predicados functor(T,F,A), ‘functor’ y ‘arg’ juntos. Sin embargo, subTermA(A,S,T). aunque los programas con ‘=..’ son más legibles, también son menos eficientes, puessubTermA(N,S,T):-arg(N,T,Ta), subTerm(S,Ta). necesitan construir una lista auxiliar.subTermA(N,S,T):-N > 1, N1 is N - 1, subTermA(N1,S,T).8.4 Predicados meta-lógicosLos predicados meta-lógicos permiten controlar el algoritmo de resolución facilitando la meta-programación. Éstaconsiste en construir programas que manipulan otros programas proporcionando una mayor expresividad allenguaje.8.4.1 Chequeo de tipo Predicado Condición para que se cumpla Ejemplos var(X) X es una variable no instanciada | ?- var(X). X = _ | ?- X = 1, var(X). no nonvar( X) X no es una variable o es una | ?- nonvar(X). no variable instanciada | ?- X = 1, nonvar(X). X = 1La utilización de estos predicados permite al programador chequear si una variable está instancia o no paraproporcionar programas más flexibles y eficientes. abuelo(X,Y):- X es abuelo de Yabuelo(X,Y):-nonvar(X), hombre(X), progenitor(X,Z), progenitor(Z,Y).abuelo(X,Y):-nonvar(Y), progenitor(Z,Y), progenitor(X,Z), hombre(X).8.4.2 Comparación de términos no básicos Predicado Condición para que se cumpla Ejemplos X==Y X e Y son iguales (no unifica | ?- f(X,2) = f(1,Y). X = 1 , las variables) Y = 2 | ?- f(X,2) == f(1,Y). no X == Y X e Y no son iguales (no | ?- f(X,2) == f(1,Y). yes 16
Programación Práctica en Prolog Conversión de Datos en Objetivos unifica las variables) unifica(X,Y):- Se cumple si X e Y sonunifica(X,Y):-var(X),var(Y), X = Y.unifica(X,Y):-var(X), nonvar(Y), noOcurre(X,Y),X=Y. unificables utilizando chequeo deunifica(X,Y):-var(Y), nonvar(X), noOcurre(Y,X),Y=X. ocurrencias.unifica(X,Y):-nonvar(X), nonvar(Y), atomic(X), atomic(Y), X = Y. | ?- unifica(f(1,X),f(Y,2)).unifica(X,Y):-nonvar(X), nonvar(Y), compound(X), compound(Y), X = 2 , unifTerm(X,Y). Y = 1 ;unifTerm(X,Y):- functor(X,F,A), | ?- f(X,X)=f(Y,g(Y)). functor(Y,F,A), Error ... Stack Full, unifArgs(A,X,Y). | ?- unifica(f(X,X),f(Y,g(Y))).unifArgs(N,X,Y):- N > 0, unifArg(N,X,Y), no N1 is N - 1, unifArgs(N1,X,Y).unifArgs(0,X,Y).unifArg(N,X,Y):- arg(N,X,Ax), arg(N,Y,Ay), unifica(Ax,Ay). noOcurre(X,T):- se cumple si la variable X no aparece en el término TnoOcurre(X,Y):-var(Y), X == Y.noOcurre(X,Y):-nonvar(Y), atomic(Y).noOcurre(X,Y):-nonvar(Y), compound(Y), functor(Y,F,A), noOcurreArgs(A,X,Y).noOcurreArgs(N,X,Y):- N > 0, arg(N,Y,An), noOcurre(X,An), N1 is N - 1, noOcurreArgs(N1,X,Y).noOcurreArgs(0,X,Y).8.4.3 Conversión de Datos en ObjetivosEl predicado call(X) se cumple si se cumple el objetivo X.o(X,Y):-call(X). o(X,Y):- se cumple si se cumple X o sio(X,Y):-call(Y). se cumple Y| ?- o(progenitor(belen,tomas), progenitor(tomas,belen)).yes 4 El predicado o(X,Y) está predefinido como el operador ‘;’| ?- progenitor(belen,tomas) ; progenitor(tomas,belen).yesfor(0,X).for(N,X):-call(X),N1 is N - 1, for(N1,X). 4 El Prolog Standard sustituye| ?- for(5,write(*)). automáticamente una objetivo en forma*****yes de variable X por call(X)| ?- T =.. [progenitor, tomas, belen], T.T = progenitor(tomas,belen) ; 17
Programación Práctica en Prolog Conversión de Datos en Objetivos8.5 CorteEl corte es uno de los predicados internos más polémicos del lenguaje Prolog. Se utiliza para “podar” ramas delárbol de resolución consiguiendo que el sistema vaya más rápido. Un mal uso del corte puede podar ramas delárbol de resolución que contengan soluciones impidiendo que el sistema encuentre algunas soluciones (o todas) aun problema dado. De esta forma se aconseja utilizar el corte con precaución y únicamente en el lugar necesario,Ni antes ni después.El predicado corte se representa mediante el símbolo ‘!’ y su efecto es:- El predicado siempre se cumple.- Si se intenta re-ejecutar (al hacer backtracking) elimina las alternativas restantes de los objetivos que hay desde su posición hasta la cabeza de la regla donde aparece. En la figura puede observarse que el corte afecta a las solucionesq(X):-p(X).q(0). alternativas del predicado ‘p(X)’ y del predicado ‘a(X)’. ? q(X).p(X):-a(X),!,b(X). {X/0}p(1). ? p(X). pa(2). a(3). X=0 {X/1}b(2). b(2). b(3). ? a(X),!,b(X). p X=1<Con el corte> {X/2} {X/3}| ?- q(X).X = 2 ; ? !,b(2). ? !,b(3).X = 2 ; ? b(2). ? b(3).X = 0<Sin se quita el corte> p p p| ?- q(X). X=2 X=2 X=3X = 2 ;X = 2 ;X = 3 ;X = 1 ;X = 0padre(X,Y):-progenitor(X,Y),hombre(X). padre(X,Y):-X es el padre de Y.| ?- padre(X,belen).X = tomas ; Se encuentra el primer progenitor hombre de belen (tomas) y el sistema busca más progenitores medianteno backtracking. Como no los encuentra, devuelve no.| ?- En este ejemplo particular, suponiendo que cualquierpadre(X,Y):-progenitor(X,Y), hombre(X), !. persona tiene un único padre, podría ser interesante podar las alternativas que se encuentren.| ?- padre(X,belen).X = tomas Sería como declarar:| ?- “X es padre de Y si es su progenitor, es hombre y además, es único”: 4 Un buen uso del corte puede permitir la construcción de programas Prolog eficientes. orgulloso(X):-X está orgulloso (cuando es padre de unorgulloso(X):-padre(X,Y), recien_nacido(Y). recién nacido).recien_nacido(maria). Si se suprime el corte en la definición de padre? orgulloso(X). devolvería a Pedro. Sin embargo, tal y como se hano definido, en cuanto se encuentra que pedro es padre de 18
Programación Práctica en Prolog Aplicaciones del Corte ana y que ana no es un recién nacido, el Prolog poda la alternativa de que Pedro también es padre de María 4 La inclusión de cortes puede hacer que el sistema no encuentre algunas soluciones. 4 El exceso de cortes en un programa dificulta la legibilidad.8.5.1 Aplicaciones del CorteEn general, la utilización del corte debe ser examinada con precaución. En muchas ocasiones conviene sustituir elcorte por construcciones que encapsulen su utilización.8.5.1.1 Indicar al Sistema que ha escogido la regla correcta (if-then-else)soloMujeres([],[]).soloMujeres([X|Xs],[X|Ys]) :- mujer(X), soloMujeres(Xs,Ys):-Ys contiene las mujeres de Xs soloMujeres(Xs,Ys).soloMujeres([X|Xs],Ys) :- hombre(X), soloMujeres(Xs,Ys).| ?- soloMujeres3([ana,pedro,maria],V). Si se hace backtracking, el predicado chequearáV = [ana,maria] ; más alternativas comprobando si las mujeres son, a su vez, hombres.nosoloMujeres1([],[]).soloMujeres1([X|Xs],[X|Ys]) :- mujer(X), !, soloMujeres1: Si se inserta un corte tras la soloMujeres1(Xs,Ys). condición mujer se le indica al sistema que nosoloMujeres1([X|Xs],Ys) :- hombre(X), busque más alternativas cuando encuentra una soloMujeres1(Xs,Ys). mujer.soloMujeres2([],[]).soloMujeres2([X|Xs],[X|Ys]) :- mujer(X), !, soloMujeres2: Utilizando el corte, si el sistema soloMujeres2(Xs,Ys). encuentra una mujer, no va a chequear si es unsoloMujeres2([X|Xs],Ys) :- soloMujeres2(Xs,Ys). hombre. La condición de que sea un hombre, podría suprimirse.ifThenElse(Cond,X,Y):-call(Cond)!,call(X).ifThenElse(Cond,X,Y):-call(Y). El esquema conseguido puede generalizarse.soloMujeres3([],[]).soloMujeres3([X|Xs],Ys1) :- ifThenElse(mujer(X), ifthenelse (Cond,X,Y) :-Si Cond entonces ejecuta Ys1 = [X|Ys], X sino, ejecuta Y. Ys1 = Ys), soloMujeres3(Xs,Ys).soloMujeres4([],[]).soloMujeres4([X|Xs],Ys1) :- (mujer(X) -> Ys1 = [X|Ys] ; Ys1 = Ys), El predicado ifThenElse está predefinido mediante soloMujeres4(Xs,Ys). el operador ‘->’.8.5.1.2 Negación por falloEl lenguaje Prolog utilice un subconjunto de la lógica de predicados de primer orden (cláusulas Horn) lo queimpide modelizar ciertas situaciones con conocimiento negativo. La negación por fallo es una aproximación a lastécnicas de representación de conocimiento negativo. La idea intuitiva es, si se detecta que algo no se cumple,entonces, se supone que es falso. Se desea representar el siguiente conocimiento:animal(X):-perro(X).animal(X):-serpiente(X). “A Ana le gustan todos los animales salvo lasserpiente(kika). serpientes”perro(kiko). fail es un predicado interno que siempre falla. 19
Programación Práctica en Prolog Aplicaciones del Cortele_gusta(ana,X):-serpiente(X),!,fail.le_gusta(ana,X):-animal(X).| ?- le_gusta(ana,kika).no Se puede generalizar el patrón de negación por fallo.| ?- le_gusta(ana,kiko).yes falla_si(X):- falla si el objetivo X se cumple y se cumplefalla_si(X):-call(X),!,fail. si X falla.falla_si(X). 4 El predicado falla_si está predefinido en Prolog Standard como el operador: ‘+’.le_gusta2(ana,X):-falla_si(serpiente(X)), animal(X). & En muchos sistemas, el predicado ‘+’ se conoce| ?- le_gusta2(ana,kika). como not. En la definición Standard se decidió evitar elno predicado not para que los usuarios no lo confundiesen| ?- le_gusta2(ana,kiko). con una negación común.yes El símbolo ‘+’ pretende ser una representación del símbolo matemático ? (no demostrable)| ?- le_gusta2(ana,X).no Con variables sin instanciar no funciona. En cuanto encuentra una serpiente, falla y no busca más| ?- le_gusta2(ana,X). alternativas.no En esta caso, puede corregirse cambiendo de orden losle_gusta3(ana,X):- animal(X), falla_si(serpiente(X)). objetivos. 4 Al introducir negación por fallo el orden de los objetivos influye en los resultados. & La raíz del problema es que la frase “A Ana le gustan todos los animales salvo las serpientes”, se formalizaría en lógica como ∀x (animal(x) ∧ ¬ serpiente(x) → le_gusta(ana,x) ) y al pasarla a forma clausal se obtendría una cláusula con dos literales positivos (no Horn)8.5.1.3 Reglas por defectopension(X,invalidez):- invalido(X),!.pension(X,jubilacion):- jubilado(X),!. pension(P,Tp):- Tp es el tipo de pension que lepension(X,nada). corresponde a la persona Pinvalido(pedro).jubilado(tomas).jubilado(pilar).| ?- pension(tomas,X).X = jubilado J Con preguntas sencillas funciona| ?- pension(ana,X).X = nada| ?- pension(tomas,nada).yes K No funciona, debería responder que no!| ?- pension(X,jubilacion). L Tampoco funciona, le ha quitado la pensión a PilarX = tomas| ?- 4 La introducción de cortes puede hacer que al plantear al sistema preguntas no contempladas, las respuestas sean erróneas.pension2(X,invalidez) :- invalido(X). La solución sería quitar el corte y utilizar dos niveles.pension2(X,jubilacion):- jubilado(X). 20
Programación Práctica en Prolog Entrada/Salidaasigna(X,P) :- pension2(X,P).asigna(X,nada):- + pension2(X,P). pension2(P,Tp):- Tp es el tipo de pension que le corresponde a la persona P| ?- asigna(X,jubilacion).X = tomas ; asignacion(P,Ta):-Ta es el tipo de asignación que leX = pilar ; corresponde a Pno8.5.1.4 Finalizar generación de alternativas (once)En algunas ocasiones, puede ser necesario finalizar la generación de alternativas devolviendo únicamente laprimera solución encontrada. Las razones pueden ser, porque se conoce que el problema sólo va a tener unasolución, o porque no tiene importancia devolver una solución u otra y se opta por devolver la primera. Medianteun corte, puede finalizarse la generación de otras soluciones. hayPadresJubilados:-Se sumple si en la basehayProgJubilados:-progenitor(X,Y),jubilado(X),!. de conocimiento existe algun progenitor jubilado. once(X):- Se cumple si se cumple el objetivoonce(X):-call(X),!. X, pero no intenta re-ejecutar X. 4 Los dobles paréntesis son necesarios parahayProgenitoresJubilados:-once( (progenitor(X,Y), jubilado(X) )). que el sistema reconozca la sintaxis. ( El predicado once está predefinido en el Prolog Standard, sin embargo, muchos sistemas comerciales no lo utilizan o utilizan el predicado one8.6 Predicados Extra-lógicos8.6.1 Entrada/SalidaEn Prolog la Entrada/Salida (E/S) se realiza mediante efectos laterales. Los predicados de E/S tienen un escasovalor lógico, pero, al ser encontrados por el sistema, ejecutan las acciones correspondientes.( El principal cambio producido al standarizar el lenguaje Prolog ha sido la redefinición de los predicadosclásicos de E/S. Sin embargo, muchas implementaciones continúan ofreciendo el repertorio anterior. Se indicamediante el símbolo ( aquellos predicados que no son standard.8.6.1.1 E/S a nivel de términosLos siguientes predicados leen y escriben términos Prolog completos Predicado Se cumple cuando: Efecto lateral Ejemplos Sencillos Standard write(X) Siempre Escribe el valor del término X | ?- write(f(x,3+4)). write f(x,3+4). yes read(X) Si es posible unificar X con el Lee un término Prolog | ?- read(X). read |:<usuario> f(x,3+4). valor leído X = f(x,3 + 4) 4No se hace backtracking. 4 Los términos Prolog deben | ?- read(X), X = 2. Analiza los caracteres de acabar en punto |:<usuario> 3. no entrada hasta encontrar un término y, si unifica, se cumple, sino, falla. display(X) Siempre Escribe el valor del término X |?- display(f(x,3+4)). write_canonical f(x,(+)(3,4)) en notación functor yes nl Siempre Escribe un salto de línea nl 21
Programación Práctica en Prolog Entrada/Salidasaludo:-write(‘Tu nombre?’), saludo: Pide al usuario un nombre (término Prolog), lo lee read(N), write(‘Hola ‘), write(N). y lo muestra por pantalla.| ?- saludo.Tu nombre?|:<usuario> juan.Hola juanyeswriteln([X|Xs]):-write(X), writeln(Xs).writeln([]):-nl.% Predefinidorepeat. repeat: Predicado que siempre se cumple y que tiene unrepeat:-repeat. infinito número de soluciones., cuadrados:-Solicita numeros al usuario hasta que éstecuadrados:- repeat, leeNumero(X), teclea 0. Para cada número, imprime su cuadrado. procesa(X), !.leeNumero(X):-repeat, write(Numero?), 4 Los bucles Prolog con repeat tienen siempre un mismo read(X), esquema: number(X), !. bucle:- repeat, <cuerpo del bucle>,procesa(0):-!. <condición de salida, si se cumple ⇒ fin>,procesa(X):- R is X*X, !. writeln([X, ^2 = ,R]), fail. El corte al final es necesario para que el predicado no intente re-ejecutarse de nuevo.8.6.1.2 E/S a nivel de caracteres Predicado Se cumple cuando: Efecto lateral Standard get0(X) Si es posible unificar el Lee un caracter del teclado get_char caracter leido con X get(X) Si es posible unificar el Lee el siguiente caracter caracter leido con X distinto de blanco. put(X) Siempre Escribe el caracter X put_charleeLsPals(Pals):- once((get0(C), leePals(C,Pals))). leeLsPals (X):- Obtiene una lista de Atomos de laleePals(C,[]):-punto(C),!. entradaleePals(C,[Pal|Pals]):-alfaNum(C),!, leePal(C,Pal,Csig), leePals(Csig,Pals). | ?- leeLsPals(X). |: Esta es una cadena con 1 numero.leePals(C,Pals):- get0(Csig), X = [Esta,es,una,cadena,con,1,numero] leePals(Csig,Pals).leePal(C1,Pal,Csig):-cogerCodsPal(C1,Cods,Csig), atom_chars(Pal,Cods).cogerCodsPal(C1,[C1|Cars],Cfin):-alfaNum(C1), get0(Csig),cogerCodsPal(Csig,Cars,Cfin). ( La forma de obtener el código ASCII de uncogerCodsPal(C,[],C):- + alfaNum(C). caracter varía de un sistema a otro. En LPA, 0’aalfaNum(C):- (C>=0a, C=<0z) representa el código ASCII del caracter ‘a’. ; (C>=0A, C=<0Z) ; (C>=00, C=<09).punto(0.).espacio(0 ). 22
Programación Práctica en Prolog Acceso a la Base de Datos8.6.1.3 E/S con ficherosEsta parte es una de las que más difiere con el Prolog Stándar donde se utilizan manejadores para trabajar constreams o flujos de E/S. Predicado Se cumple cuando: Efecto lateral Standard tell(F) Si no hay errores de Abre F como stream de salida open apertura actual see(F) Si no hay errores de Abre F como stream actual de open apertura entrada. told Siempre Cierra stream de salida actual close seen Siempre Cierra stream de entrada actual close telling(F) Unifica F con el nombre del Ninguno stream de salida actual seeing(F) Unifica F con el nombre del Ninguno stream de salida actualverFich:-write(Nombre fichero?), read(N), seeing(Antes), verFich:-Pregunta un nombre de fichero al usuario, lo see(N), abre y visualiza su contenido en mayúsculas. bucle, seen, see(Antes).bucle:-repeat, get0(C), minMay(C,Cm), put(Cm), at_end_of_file, !.minMay(C,Cm):-minuscula(C),!, Cm is C - 0a + 0A.minMay(C,C).minuscula(C):- C >= 0a, C =< 0z.8.6.2 Acceso a la Base de DatosLos sistemas Prolog ofrecen la posibilidad de modificar en tiempo de ejecución el contenido de la base deconocimiento. Predicado Se cumple cuando: Efecto lateral asserta(T) Siempre Añade al principio de la base de conocimiento el término T assertz(T) Siempre Añade al final de la base de conocimiento el término T. retract(T) Si T unifica con el término Elimina de la base de eliminado. conocimiento el término T:-dynamic(fib/2). fib(X,Y):- Y es el X-ésimo número de la sucesión defib(0,1). Fibonacci. Se memorizan resultados intermedios.fib(1,1).fib(X,Y):-X>1, X1 is X - 1, fib(X1,Y1), 4 Para poder insertar dinámicamente un predicado en la X2 is X - 2, fib(X2,Y2), Y is Y1 + Y2, base de conocimiento, debe utilizarse la directiva asserta((fib(X,Y):-!)). :-dynamic(P/A). que indica al sistema que el predicado P de aridad A es dinámico. 23
Programación Práctica en Prolog Acceso a la Base de Datos8.7 Predicados de Segundo OrdenSupóngase que se desea construir un programa que busque todas las soluciones para un objetivo dado. Con lospredicados considerados hasta ahora, la tarea no es sencilla. El problema es que Prolog devuelve las soluciones alrealizar backtracking. Sería necesario forzar el backtracking para cada solución e ir recogiendo las solucionesencontradas. El problema es que la pregunta está fuera del modelo lógico (toda la información de unacomputación, se pierde al realizar backtracking). La solución es utilizar los siguientes predicados: Predicado Se cumple cuando: findall(T,C,L) L es la lista de todas las instancias del término T tales que el objetivo C se cumple. La lista de soluciones no se ordena (se insertan en el orden en que aparecen) y puede contener elementos repetidos. Si no hay soluciones, se obtiene la lista vacía Tras el objetivo, las variables de T y C permanecen sin instanciar. bagof(T,C,L) Se cumple si L es la lista de todas las instancias de T tales que el objetivo C se cumple. C puede tener la forma: V1^V2^…^Vn^Objetivo indicando que las variables V1,V2,…,Vn están cuantificadas existencialmente. Si no se cumple C el predicado falla L no se clasifica y puede contener elementos duplicados. setof(T,C,L) Similar a bagof salvo que la lista de resultados se clasifica y se eliminan elementos duplicados.hijos(Xs):-findall(X,progenitor(Y,X),Xs). hijos(L):- se obtiene la lista de hijos| ?- hijos(V).V = [belen,belen,lucia,ana,pedro,jose,maria] Con findall la lista puede contener duplicados y no está ordenada.hijos1(Xs):- bagof(X,progenitor(Y,X),Xs). Con bagof las variables no cuantificadas, indican| ?- hijos1(V). posibles soluciones. Para cada posible valor de laV = [ana,pedro] ; variable (en el ejemplo, para cada progenitor), se devuelve la lista de sus hijos.V = [jose,maria] ;V = [belen] ;V = [belen,lucia] ;nohijos2(Xs):-bagof(X,Y^progenitor(Y,X),Xs). Las variables pueden cuantificarse existencialmente| ?- hijos2(V). mediante ^, actuando de forma similar a findallV = [belen,belen,lucia,ana,pedro,jose,maria]hijos3(Xs):-setof(X,Y^progenitor(Y,X),Xs). setof elimina ordena la lista y elimina duplicados.| ?- hijos3(V).V = [ana,belen,jose,lucia,maria,pedro]El efecto de estos predicados se podría simular mediante efectos laterales, almacenando las soluciones en la basede datos con los predicados definidos en la sección 8.6.2.8.8 DirectivasEl Prolog Standard define una serie de directivas que indican al sistema tareas a realizar u opciones decompilación.:-ensure_loaded(F). Indica al sistema que cargue el fichero F:-multifile(P/N). Indica que el predicado P de aridad N puede definirse en varios ficheros. Por defecto, las definiciones deben estar en un solo fichero.:-dynamic(P/N). Indica al sistema que la definición del predicado P de aridad N puede modificarse de forma dinámica:-initialization(C). Declara que el objetivo C debe ser ejecutado tras cargar el fichero.:-op(Prioridad,Asociatividad,Atomo). Define Atomo como un operador con la Prioridad y Asociatividad dadas 24
Programación Práctica en Prolog Acceso a la Base de Datos9 Ejercicios Propuestos Clave: . Muy Fácil .. Fácil ... Medio .... Largo (proyectos de programación) n1.- cambia(Xs,Ys):- Si Xs=[x1 ,x2 ,...xn ], entonces Ys=[y 1 ,y 2 ,...,y n ] de forma que yi = xi + ∑x i =1 i para i = 1..n (.) ? cambia ([1,3,2],Xs). Xs = [7,9,8]2.- sucesion(N,Xs):- Xs es de la forma [x1 ,x2 ,...xn ] donde X 1 = 0, X2 = 1 y x i+2 = 2*xi + xi+1 (.)Ejemplo: ? sucesion(8,V). V = [0,1,1,3,5,11,21,43]3.- diferentes(Xs,N):-N es el numero de elementos diferentes de la lista Xs (.)Ejemplo: ? diferentes([1,2,2,1,1,3,2,1],V). V = 44.- Supóngase que se ha cargado el siguiente programa en un sistema Prolog. a(X,Y):-b(X,Y). a(X,Y):-c(X,Y). b(X,Y):-d(X),!,e(X,Y). b(X,Y):-f(X,Y). c(1,2). c(1,3). d(1). d(2). e(2,3). f(3,4). f(3,5).Indicar cuales son las respuestas del sistema (suponer que se solicitan todas por backtracking) al ejecutar: (.)a. ? a(1,X).b. ? a(2,X).c. ? a(3,X).5.- rep(Xs,V) :- V es el representante decimal equivalente a la lista de enteros Xs. (.)Ejemplo:? rep([1,4,6],V).V = 1466.- monte(Xs) :-Se cumple si Xs tiene forma de monte. Es decir, es creciente hasta un elemento y decreciente desdeese elemento hasta el final.(.)Ejemplo: ? monte([1,3,5,6,4,3,0]). yes7.- cambio(X,Xs) :- Xs es la lista monedas de 1,5,25 ó 100 necesarias para alcanzar la cantidad X (.) ? cambio 156 [100,25,25,5,1]8.- decBin(D,B):- B es el valor binario de D (..) ? decBin(13,V). V = [1,1,0,1] ? decBin(V,[1,0,1,1]). 139.- combs(Xss,Ys):- Se cumple si Ys es una lista en la que el primer elemento es alguno de los elementos de laprimer lista de Xss, el segundo elemento es alguno de los elementos de la segunda lista de Xss y...el n-ésimoelemento de cada sublista es alguno de los elementos de la n-ésima lista de Xss. Mediante backtracking, debedevolver todas las posibles listas Ys que satisfagan dicha condición. (..)Ejemplo:? combs([[1,2,3],[4,5],[6]],V).V = [1,4,6] ;V = [1,5,6] ;V = [2,4,6] ;V = [2,5,6] ; 25
Programación Práctica en Prolog Acceso a la Base de DatosV = [3,4,6] ;V = [3,5,6] ;No10.- triangulo(N):- muestra por pantalla un triangulo de N filas (..)Ejemplo: ? triangulo(4). * *** ***** *******11.- sumCombs(Xss,V):- V es la suma de todas las representaciones decimales de las listas obtenidas mediante lascombinaciones del ejercicio (..) ? sumCombs([[1,2,3],[4,5],[6]],V). V = 150612.- decBin(D,B):- B es el valor binario de D (..) ? decBin(13,V). V = [1,1,0,1] ? decBin(V,[1,0,1,1]). V = 1313.- varsRep(N,Xs,Vs):- Vs son las variaciones con repetición de los elementos de Xs tomados de N en N? varsRep(3,[0,1],Vs). (..)Vs = [[0,0,0],[0,0,1],[0,1,0],[0,1,1].[1,0,0],[1,0,1],[1,1,0],[1,1,1]]? varsRep(2,[0,1,2],Vs). Vs = [[0,0],[0,1],[0,2],[1,0],[1,1],[1,2],[2,0],[2,1],[2,2]]14.- palabras(Cad,Pals):- Pals es una lista de estructuras de la forma: c(P,N), donde P es una palabra de Cad y N esel número de veces que se repite dicha palabra en Cad. Se deben ignorar las diferencias entre mayúsculas yminúsculas y los caracteres de puntuación. (...) ? palabras ("¿No duerme nadie por el mundo?. No, no duerme nadie.",Ps). Ps = [c(no,3), c(duerme,2), c(nadie, 2), c(por,1), c(el,1), c(mundo,1)]15.- busca(Exp, Cad, Ps):- Ps es una lista de palabras de Cad que encajen con la expresión regular Exp. Se debenignorar las diferencias entre mayúsculas y minúsculas y los caracteres de puntuación. (...) ? busca (“*e”, "¿No duerme nadie por el mundo?. No, no duerme nadie.",Ps). Ps = [duerme, nadie, duerme, nadie]16.- tartaglia(N):- muestra por pantalla las N primeras filas del triángulo de Tartaglia. (...)Ejemplo: ? tartaglia(5) 1 1 1 1 2 1 1 3 3 1 1 4 6 4 117.- Desarrollar un programa que calcule y simplifique derivadas de funciones de forma simbólica. (...)18.- Construir un programa de gestión de una agencia matrimonial. El programa debe almacenar datos depersonas, así como sus preferencias y, buscar las mejores combinaciones de parejas. (...)19.- Construir un programa que maneje polinomios. El programa será capaz de leer polinomios a a partir de laentrada del usuario, sumarlos, multiplicarlos y restarlos. Además, el programa buscará raíces de forma analítica onumérica. El programa no se restringirá a polinomios cuadráticos y se puede considerar el cálculo de raícescomplejas. (....)20.- Escribir un programa interactivo que juegue finales de partidas de ajedrez. Se pueden tomar finales de unareina contra dos torres, por ejemplo. (....)21.- Escribir un programa que tome una representación de una matriz de puntos cuadrada (de tamaño 10x10, porejemplo) y decida qué letra del alfabeto representa. El patrón podría tener alguna distorsión o ambigüedad que elprograma debe ser capaz de afrontar. (....)22.- Escribir un algoritmo que tome como entrada un mapa dividido en regiones (se almacena información de quéregiones tienen frontera en común entre sí) y asigne un color a cada región de forma que no haya dos regionesadyacentes con frontera común. (....) 26
Programación Práctica en Prolog Acceso a la Base de Datos23.- Constuir un programa interactivo que muestre un prompt por pantalla y reconozca los siguientes comandos: Fin Fin del programa Ver Var Muestra el valor de ‘Var’ en pantalla Var = Expresión Asigna a Var el valor de ‘Expresión’ Expresión Evalúa la ‘expresión’ y muestra el resultado en pantallaDonde Expresión es una expresión aritmética formada por sumas, restas, multiplicaciones, divisiones, constantesnuméricas y variables. Un ejemplo de sesión podría ser: (....) $ x = 3 * 2 + 4 * (6 + 2). OK $ x + 1. 39 $ y = x + 1. OK $ y + 2. 40 $ x = 2 * 3. OK $ y + 2. 8 $ V(y). x+1 $ fin. Adios! 27

References: resolución 
 resolución 
 resolución 
 resolución 
 resolución 
 resolución