



























Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity
Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium
Prepara tus exámenes
Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity
Prepara tus exámenes con los documentos que comparten otros estudiantes como tú en Docsity
Encuentra los documentos específicos para los exámenes de tu universidad
Estudia con lecciones y exámenes resueltos basados en los programas académicos de las mejores universidades
Responde a preguntas de exámenes reales y pon a prueba tu preparación
Consigue puntos base para descargar
Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium
Comunidad
Pide ayuda a la comunidad y resuelve tus dudas de estudio
Ebooks gratuitos
Descarga nuestras guías gratuitas sobre técnicas de estudio, métodos para controlar la ansiedad y consejos para la tesis preparadas por los tutores de Docsity
Apuntes del curso universitario de Fundamentos de Programación sobre la Programación Práctica - Teoría y Hechos
Tipo: Apuntes
1 / 35
Esta página no es visible en la vista previa
¡No te pierdas las partes importantes!




























8.6.1 Entrada/Salida ____________________________________________________________ 21 8.6.2 Acceso a la Base de Datos ___________________________________________________ 23
Programación Práctica en Prolog Chequeo de tipo 3
1 Introducción Con estos apuntes se muestran las diferentes características del núcleo del lenguaje Prolog mediante sencillos ejemplos. Se ha realizado un tratamiento especial a las listas y a los diversos esquemas recursivos para trabajar con listas. El objetivo es ayudar al lector a identificar esquemas de programación que puedan servirle para resolver problemas similares. No se ha pretendido realizar una guía detallada sino una presentación práctica informal del lenguaje. 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 portabilidad En la presentación de ejemplos se utiliza una tabla escribiendo el código y las preguntas en la parte izquierda y los comentarios en la parte derecha.
2 Hechos /* Relacion Progenitor */ progenitor(pilar,belen). progenitor(tomas,belen). progenitor(tomas,lucia). progenitor(belen,ana). progenitor(belen,pedro). progenitor(pedro,jose). progenitor(pedro,maria). Se describen una serie de hechos conocidos sobre una familia. 4 Sintaxis de Prolog: Constantes y predicados empiezan por minúscula. Los hechos acaban en punto. Variables comienzan por mayúscula. El programa anterior debe ser cargado en el sistema. Una vez cargado, es posible realizar preguntas: | ?- progenitor(pilar,belen). Yes El sistema puede responder: 1.-Yes: Se puede deducir y el objetivo no tiene variables. | ?- progenitor(pilar,lucia). No 2.-No: No puede deducir a partir del programa La respuesta No indica que no se puede deducir. En la 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 | ?- progenitor(belen,X). X = ana ; X = pedro 3.- Substitución de Respuesta: Se puede deducir y el objetivo tiene variables. Se indica el valor que toman las variables en la resolución del objetivo. En caso de que haya más de una solución. Cuando el
Téngase en cuenta que a la hora de resolver la pregunta madre(belen,X) con la cabeza de la regla madre(X,Y) es necesario renombrar la variable X El lenguaje Prolog realiza internamente un proceso de unificación que se describe en la página 4.
antepasado(X,Y):-progenitor(X,Y). antepasado(X,Y):-progenitor(X,Z), antepasado(Z,Y). En general, en una definición recursiva, es necesario considerar 2 casos: Caso básico : Momento en que se detiene la computación Caso Recursivo : Suponiendo que ya se ha 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) | ?- antepasado(belen,X). X = ana ; X = pedro ; X = jose ; X = maria ; no | ?- antepasado(X,belen). X = pilar ; X = tomas ; no Las definiciones recursivas se resuelven de la misma forma que las reglas comunes. En la traza de este tipo de definiciones tiene especial importancia el renombramiento de variables. Considerando la relación progenitor como un enlace entre dos nodos de un grafo. La relación antepasado indicaría si hay camino entre dos nodos del grafo dirigido acíclico formado por la relación progenitor. Este tipo de relaciones se utiliza en diversos contextos como la búsqueda de caminos entre ciudades, la simulación de movimientos de un autómata, etc.
. Describir en Prolog una serie de caminos entre diversas ciudades y construir un predicado que indique 2 Se dice que una variable está instanciada si tiene un valor concreto (en realidad ya no sería una variable) Programación Práctica en Prolog Chequeo de tipo 5 si 2 ciudades están conectadas.
grande(pepe). grande(cabeza(juan)). grande(X):-mayor(X,Y). mayor(cabeza(X),cabeza(Y)):- progenitor(X,Y). Se utiliza la función: cabeza(x)=”cabeza de x” El programa indica: “Pepe es grande, la cabeza de juan es grande, si X es mayor que Y, entonces X es grande, además: La 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 ; X = cabeza(juan) ; X = cabeza(pilar) ; X = cabeza(tomas) ; ... 4 Las variables en Prolog no tienen tipo, de ahí que la respuesta X puede ser una persona ( pepe ) o una cabeza ( cabeza(juan) )
horizontal(seg(punto(X,Y), punto(X1,Y))). vertical(seg(punto(X,Y), punto(X,Y1))). punto(X,Y) representa un punto de coordenadas (x,y) seg(p1,p2) representa un segmento cuyos extremos son los puntos p1 y p Los argumentos de una función pueden ser funciones | ?- horizontal(seg(punto(1,2),punto(3,2))). Yes | ?- horizontal(seg(punto(1,2),P)). P = punto(_47796,2) | ?- horizontal(P),vertical(P). P=seg(punto(_29128,_29130),punto(_29128,_29130) ) P = punto(_47796,2) indica que P es un punto cuya primera coordenada es una variable sin instanciar 3 y cuya segunda coordenada es 2 La última respuesta indica que para que un 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ón
Durante la resolución de objetivos, el sistema Prolog debe realizar la unificación entre los objetivos y las cabezas de las reglas o los hechos. De forma simplificada, el algoritmo de unificación consiste en: 1.- Inicializar = substitución vacía 2.- 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). X = a Y = a | ?- f(X,X)=f(a,Y). no | ?- p(f(X),g(Z,X))=p(Y,g(Y,a)). X = a , Z = f(a) El operador ‘=’ se cumple si sus argumentos unifican. El operador ‘=’ se cumple si sus argumentos no unifican. Puesto que Prolog no tiene chequeo de ocurrencias, se produce un error. 3 El formato de las variables sin instanciar varía de un sistema Prolog a otro. En estos apuntes, se utiliza un nú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ía
4 La llamada lista(X) genera por backtracking listas de cualquier tipo de elementos.
hombres([]). hombres([X|Xs]):-hombre(X), hombres(Xs). noPertenece(X,[]). noPertenece(X,[Y|Ys]):-X=Y, noPertenece(X,Ys). | ?- hombres([jose,tomas,pedro]). yes | ?- hombres([jose,pilar,tomas]). hombres(Xs) :- Todos los X de Xs cumplen hombre(X) noPertenece(X,Xs) :- El elemento X no pertenece a la lista Xs (se comprueba que no unifica con ningún elemento de Xs En las definiciones recursivas, conviene escribir el caso básico antes que el caso recursivo ya que si la definición unifica con ambos casos y Programación Práctica en Prolog Chequeo de tipo 7 no | ?- noPertenece(pilar,[jose,pilar,tomas]). no | ?- noPertenece(luis,[jose,pilar,tomas]). yes estuviese pusiese el caso recursivo antes, el sistema entraría en un bucle infinito. De la misma forma, es conveniente que la llamada recursiva sea la última llamada de la definición recursiva (muchos sistemas optimizan las definiciones así escritas)
todosIguales([]). todosIguales([X]). todosIguales([X,X|Xs]):-todosIguales([X|Xs]). | ?- todosIguales([1,2,3]). no | ?- todosIguales([1,1,1]). yes | ?- todosIguales(X). X = [] ; X = [_25576] ; X = [_27704,_27704] ; X = [_27704,_27704,_27704] ; X = [_27704,_27704,_27704,_27704] todosIguales(Xs):- Los elementos de Xs son todos iguales Obsérvese que hay dos casos básicos y que el caso recursivo no es de la forma [X|Xs]. Obsérvese que los tres casos se excluyen. Como regla general, conviene que los casos de una definición se excluyan. Cuando los casos no se excluyen, al realizar backtracking el sistema puede obtener respuestas distintas de las esperadas.
. Describir la respuesta ante: ?- todosIguales([2,X,Y]).
pertenece(X,[X|Xs]). pertenece(X,[Y|Ys]):- pertenece(X,Ys). | ?- pertenece(pedro,[jose,pedro,tomas]). yes | ?- pertenece(jose,[]). no | ?- pertenece(X,[jose,pedro,tomas]). X = jose ; X = pedro ; X = tomas ; no | ?- pertenece(jose,X). X = [jose|_6617] ; X = [_8808,jose|_8817] ; X = [_8808,_11012,jose|_11021] ; X = [_8808,_11012,_13230,jose|_13239] ... pertenece(X,Xs) :- X está en la lista Xs El caso básico no es la lista vacía. Además, los casos no se excluyen. Una lista que encaje con la primera definición, lo hará con la segunda. La relación pertenece es un claro ejemplo de la flexibilidad de las definiciones en Prolog ya que se puede utilizar para: 1.- Chequear si un elemento pertenece a una lista 2.- Obtener todos los elementos de una lista por backtracking 3.- Obtener listas con un elemento X en primera, segunda, ... n-ésima posición. elimina(X,[X|Xs],Xs). elimina(X,[Y|Ys],[Y|Zs]):-elimina(X,Ys,Zs). | ?- elimina(1,[1,2,1,3],V). V = [2,1,3] ; V = [1,2,3] ; no | ?- elimina(1,V,[2,3]). eliminna(X,Ys,Zs):-Zs contiene todas las listas resultantes de eliminar el elemento X de Ys 4 El predicado selecciona sirve también para diversos propósitos: Borrar elementos de una lista Insertar un elemento en diferentes posiciones de una lista Programación Práctica en Prolog Chequeo de tipo 8 V = [1,2,3] ; V = [2,1,3] ; V = [2,3,1] ; no
. Describir el comportamiento del predicado si se añade X=Y en la segunda definición. algunHombre(Xs):-pertenece(X,Xs), hombre(X). | ?- algunHombre([jose,pilar,tomas]). yes algunHombre(Xs):- alguno de los elementos X de Xs cumple la relación hombre(X)
concat([],Ys,Ys).
sinDuplicados(Xs,Ys). sinDuplicados([X|Xs],Ys):- pertenece(X,Xs), sinDuplicados(Xs,Ys). | ?- sinDuplicados([1,1,2,3,2,1,4],V). V = [3,2,1,4] ; filtraHombres(Xs,Ys):- Ys contiene todos los hombres de la lista Xs.
. Obsérvese qué ocurre cuando se solicitan más soluciones por backtracking o cuando se pregunta: ?- filtraHombres(V,[jose,pilar]). sinDuplicados(Xs,Ys) :-Ys contiene los elementos de Xs eliminando elementos duplicados. 4 Ambas definiciones son poco eficientes . Construir el predicado sinDuplicados para que la lista resultado contenga los elementos en el mismo orden en que aparecen
edad(pilar,85). edad(tomas,90). edad(belen,67). edad(lucia,64). edad(ana,34). edad(pedro,36). edad(jose,10). edades([],[]). edades([X|Xs],[Y|Ys]):-edad(X,Y), edades(Xs,Ys). | ?- edades([jose,pilar,tomas],V). V = [10,85,90] | ?- edades([jose,dedo,tomas],V). no | ?- edades(V,[10,85]). V = [jose,pilar] edades(Xs,Ys):- Ys contiene las edades de los elementos de Ys 4 Si alguno de los elementos no tiene edad , el predicado falla.
permutacion([],[]). permutacion(Xs,[X|Ys]):-elimina(X,Xs,Zs), permutacion(Zs,Ys). | ?- 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] ; no permutacion(Xs,Ys):- Ys es una permutación de la lista Xs
6 Aritmética
Con el fin de aprovechar las posibilidades aritméticas de los computadores convencionales, el lenguaje Prolog contiene 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 Programación Práctica en Prolog Chequeo de tipo 10 La expresión E puede contener los operadores aritméticos clásicos (+, -, *, mod, etc.) y valores numéricos. Si
contiene variables, éstas deben estar instanciadas a un valor numérico en el momento de la evaluación. | ?- X is 3+5. X = 8 | ?- X is pepe. Error al evaluar | ?- 8 is 3+5. yes | ?- 4 is 3+5. no | ?- X is 4/0. Error aritmético | ?- X is X + 1. Error al evaluar | ?- X = 3, Y is X + 5. X = 3 , Y = 8 | ?- X=0, X is X + 1. no | ?- X = 3 + 5. X = 3 + 5 La evaluación de 3+5 se realiza internamente en una instrucción del procesador. Si la expresión no resulta en un valor aritmético, se obtiene un error. Al evaluar pueden producirse errores. El operador “ is” no es nunca un operador de asignación como el := de Pascal. En general, una expresión del tipo X is X+1 no tiene sentido en Prolog. Describir en qué situaciones “X is X + 1” es un error y en qué situaciones falla sin más. 4 El operador = unifica sus argumentos pero no evalúa. par(X) :- 0 is X mod 2. impar(X) :- 1 is X mod 2. suma(X,Y,Z):- Z is X + Y. | ?- par(3). no | ?- par(4). yes | ?- suma(2,3,V). V = 5 | ?- suma(2,V,5). Error al evaluar Con el operador is se pierde la flexibilidad de las relaciones lógicas. Lo ideal es que al evaluar suma(2,V,5), el sistema devolviese V=
. ¿Por qué se obtiene error al evaluar suma(2,V,5) y no se obtiene error al evaluar par(4)? Además del predicado is , los predicados de comparación realizan una evaluación aritmética de sus argumentos y se cumplen si los valores obtenidos cumplen las relaciones correspondientes: | ?- 3+5 > 2+6. no | ?- 3+5 >= 2+6. yes | ?- 3+5 < 2+6. yes | ?- 3+5 =< 2+6. yes | ?- 3+5 =:= 2+6. yes
cuyo valor se modifique durante la resolución del objetivo. Existen ciertos algoritmos que requieren la utilización de un estado que almacena resultados intermedios. Para implementar dichos algoritmos es necesario utilizar un predicado 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). sumAc([],S,[]). sumAc([X|Xs],Sa,[Sp|Ys]):-Sp is X + Sa, sumAc(Xs,Sp,Ys). | ?- sumAcum([1,2,3,4],V). V = [1,3,6,10]
sumAcum(Xs,Ys):- j i y j xi 1 para cada y j Ys
. Construir la definición del predicado maximo(Xs,M) que se cumple si M es el máximo de los elementos de Xs
prodEscalar(Xs,Ys,P):- pEsc(Xs,Ys,0,P). pEsc([],[],P,P). pEsc([X|Xs],[Y|Ys],Pa,Pr):-Pn is Pa + X * Y, pEsc(Xs,Ys,Pn,Pr). | ?- prodEscalar([1,2,3],[4,5,6],P). P = 32 prodEscalar(Xs,Ys,P):-P es el producto escalar de los vectores Xs e Ys (P = xiyi) 4 En esta definición se utiliza además el patrón de acumulación de resultados anterior.
Es posible generar una lista mediante la descomposición de un valor. En el primer ejemplo, se descompone un nú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, permitiendo una mayor reutilización de código. Programación Práctica en Prolog Chequeo de tipo 12 repite(0,X,[]). repite(N,X,[X|Xs]):-N > 0, N1 is N - 1, repite(N1,X,Xs). intervalo(X,X,[X]). intervalo(X,Y,[X|Xs]):-X < Y, Z is X + 1, intervalo(Z,Y,Xs). | ?- repite(3,a,V). V = [a,a,a] ; | ?- intervalo(1,5,V). V = [1,2,3,4,5] ; repite(N,X,Xs):- Xs con N elementos de valor X intervalo(X,Y,Xs) :- Xs es una lista creciente cuyo primer valor es X y su último valor Y
Los siguientes ejemplos muestran cómo se puede generar una o varias listas filtrando los elementos de otras listas.
ordenada([]). ordenada([X]). ordenada(Xs):- Los elementos de Xs están en
Los árboles de búsqueda se caracterizan porque el valor de cualquier nodo del árbol es mayor que el valor de los nodos 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 de 6 El algoritmo quicksort se caracteriza porque, aunque en el caso peor tiene complejidad O(n 2 ), en el caso medio tiene complejidad O(n log 2 n) 7 Este esquema de codificación se conoce como run-length encoded y es muy utilizado para comprimir imágenes 8 Las listas son un caso especial de estructura recursiva Programación Práctica en Prolog Chequeo de tipo 14 insertArbol(X,rama(X,A1,A2),rama(X,A1,A2)). insertArbol(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)):- X > Y, insertArbol(X,A2,A2n). listArbol(Xs,A):-creaArbol(Xs,vacio,A). creaArbol([],A,A). creaArbol([X|Xs],Ao,Ar):-insertArbol(X,Ao,An), creaArbol(Xs,An,Ar). | ?- listArbol([2,1,3],V). V = rama(2,rama(1,vacio,vacio),rama(3,vacio,vacio)) busca(X,rama(X,,)). busca(X,rama(Y,A1,A2)):-X < Y, busca(X,A1). busca(X,rama(Y,A1,A2)):-X > Y, busca(X,A2). nodos(vacio,[]). nodos(rama(X,A1,A2),Xs):-nodos(A1,Xs1), nodos(A2,Xs2), concat(Xs1,[X|Xs2],Xs). ordenArbol(Xs,XsO):-listArbol(Xs,A), nodos(A,XsO). | ?- ordenArbol([2,1,3,4],V). V = [1,2,3,4] ; búsqueda resultante de insertar X en A listaArbol(Xs,A):- A es el árbol de búsqueda creado a partir de la lista Xs
. Indicar qué patrón de recursividad se utiliza en la definición de listArbol busca(X,A):- Se cumple si X está en el árbol A nodos(A,Xs):- Xs son los nodos del árbol A. El predicado nodos realiza el recorrido del árbol empezando por los nodos de la izquierda, luego el nodo central y finalmente los de la derecha. Este recorrido se conoce como recorrido inorden. Existen otros recorridos como preorden y postorden 4 Obsérvese que con los árboles podrían definirse patrones recursivos similares a los definidos para las listas 9.
8 Predicados Internos
En general, Prolog no contiene chequeo de tipos en tiempo de compilación, siendo necesario utilizar una serie de predicados 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 representa el átomo A | ?- atom_chars(abc,V).
| ?- atom_chars(V,"abc"). V = abc number_chars(N,Cs) Cs es la lista de caracteres que representa el número N | ?- number_chars(123,V). V = [49,50,51] | ?- number_chars(V,"123"). V = 123 number_atom(N,A) A es el átomo que representa el número N | ?- number_atom(123,V). V = '123' | ?- number_atom(V,'123'). V = 123
En general, Prolog no contiene chequeo de tipos en tiempo de compilación, siendo necesario utilizar una serie de predicados predefinidos que chequean el tipo de sus argumentos. Predicado Condición para que se cumpla Ejemplos
integer( X) X es un entero. 4 9 Actualmente, se investiga la posibilidad de utilizar lenguajes que definan automáticamente dichos patrones de recursividad para los diferentes tipos de datos definidos por el usuario. Programación Práctica en Prolog Chequeo de tipo 15 float(X) X es un flotante. 4.
number(X) X es un número. 4 4. 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), Z is X + Y. sumaLogica(X,Y,Z):-integer(Y), 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 = 2 sumaLogica(X,Y,Z):- Z es igual a X + Y Define un predicado aritmético que admite la flexibilidad de las relaciones lógicas. alisar([],[]). alisar([X|Xs],Ls):-list(X), alisar(X,Ls1), alisar(Xs,Ls2), concat(Ls1,Ls2,Ls). alisar([X|Xs],[X|Ls]):- atomic(X), alisar(Xs,Ls). | ?- alisar([[1,2],[3],[[4]]],V). V = [1,2,3,4] alisar(Xs,Ys):- Ys contiene una lista con los elementos de las listas de Xs
aunque los programas con ‘=..’ son más legibles, también son menos eficientes, pues necesitan construir una lista auxiliar.
Los predicados meta-lógicos permiten controlar el algoritmo de resolución facilitando la meta-programación. Ésta consiste en construir programas que manipulan otros programas proporcionando una mayor expresividad al lenguaje.
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 variable instanciada | ?- nonvar(X). no | ?- X = 1, nonvar(X). X = 1 La utilización de estos predicados permite al programador chequear si una variable está instancia o no para proporcionar programas más flexibles y eficientes. abuelo(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). abuelo(X,Y) :- X es abuelo de Y
Predicado Condición para que se cumpla Ejemplos X==Y X e Y son iguales (no unifica las variables) | ?- f(X,2) = f(1,Y). X = 1 , 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 Programación Práctica en Prolog Conversión de Datos en Objetivos 17 unifica las variables) unifica(X,Y):-var(X),var(Y), X = Y. unifica(X,Y):-var(X), nonvar(Y), noOcurre(X,Y),X=Y. unifica(X,Y):-var(Y), nonvar(X), noOcurre(Y,X),Y=X. unifica(X,Y):-nonvar(X), nonvar(Y), atomic(X), atomic(Y), X = Y. unifica(X,Y):-nonvar(X), nonvar(Y), compound(X), compound(Y), unifTerm(X,Y). unifTerm(X,Y):- functor(X,F,A), functor(Y,F,A), unifArgs(A,X,Y). unifArgs(N,X,Y):- N > 0, unifArg(N,X,Y), 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,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). unifica(X,Y):- Se cumple si X e Y son unificables utilizando chequeo de ocurrencias. | ?- unifica(f(1,X),f(Y,2)). X = 2 , Y = 1 ; | ?- f(X,X)=f(Y,g(Y)). Error ... Stack Full, | ?- unifica(f(X,X),f(Y,g(Y))). no noOcurre(X,T):- se cumple si la variable X no aparece en el término T
El predicado call(X) se cumple si se cumple el objetivo X. o(X,Y):-call(X). o(X,Y):-call(Y). | ?- o(progenitor(belen,tomas), progenitor(tomas,belen)). yes | ?- progenitor(belen,tomas) ; progenitor(tomas,belen). yes for(0,X). for(N,X):-call(X),N1 is N - 1, for(N1,X). | ?- for(5,write('*')).
yes | ?- T =.. [progenitor, tomas, belen], T. T = progenitor(tomas,belen) ; o(X,Y):- se cumple si se cumple X o si se cumple Y 4 El predicado o(X,Y) está predefinido como el operador ‘;’ 4 El Prolog Standard sustituye automáticamente una objetivo en forma de variable X por call(X) Programación Práctica en Prolog Conversión de Datos en Objetivos 18
El 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) a un 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: