























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
Asignatura: Introduccion a la inteligencia artificial, Profesor: , Carrera: Gestió Aeronàutica, Universidad: UAB
Tipo: Apuntes
1 / 31
Esta página no es visible en la vista previa
¡No te pierdas las partes importantes!
























madre(X,Y):-mujer(X), progenitor(X,Y).
mujer(pilar). mujer(belen). mujer(lucia). mujer(ana). mujer(maria). hombre(tomas). hombre(pedro). hombre(jose).
Equivale a: Para todo X e Y, si X es mujer y X es el progenitor de Y, entonce X es la madre de Y
4 En lógica de predicados: ∀x∀y(mujer(x)∧progenitor(x,y)→madre(x,y))
| ?- madre(belen,pedro). yes
| ?- madre(X,belen). X = pilar ;
no
| ?- madre(belen,X). X = ana ;
X = pedro
no
| ?- madre(X,Y). X = pilar , Y = belen ;
X = belen , Y = ana ;
X = belen , Y = pedro ;
no
La programación lógica basa su modelo en la utilización de relaciones, lo cual permite que un mismo procedimiento sirva para diferentes propósitos dependiendo de qué variables están instanciadas^2
En el ejemplo, una misma regla madre sirve para:
Comprobar si belen es madre de pedro. Calcular la madre de belén Calcular los hijos de belén Calcular parejas de madres/hijos
4 Obsérvese que las variables de los objetivos corresponden a cuantificadores existenciales, es decir:
?- madre(belen,X) equivale a:? ∃x (madre(belen,x))
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)
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)
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
de los sistemas Prolog debido a su complejidad. Esto hace que en determinadas ocasiones, el sistema se meta en un bucle infinito tratando de unificar 2 términos
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
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). concat([X|Xs],Ys,[X|Zs]):-concat(Xs,Ys,Zs).
| ?- concat([1,2],[3,4],V). V = [1,2,3,4]
| ?- concat([1,2],X,[1,2,3,4]). X = [3,4]
| ?- concat(X,Y,[1,2,3,4]). X = [] , Y = [1,2,3,4] ;
X = [1] , Y = [2,3,4] ;
X = [1,2] , Y = [3,4] ;
X = [1,2,3] , Y = [4] ;
X = [1,2,3,4] , Y = [] ;
no
concat(Xs,Ys,Zs):- Zs es el resultado de concatenar las listas Xs e Ys
4 Obsérvese la flexibilidad de la definición de concat que permite una gran variedad de usos dependiendo de qué variables están instanciadas en la llamada.
Gracias a la flexibilidad de las relaciones lógicas, el predicado concat se utiliza en la definición de una gran cantidad de predicados.
prefijo(Xs,Ys):- concat(Xs,Bs,Ys). sufijo(Xs,Ys):- concat(As,Xs,Ys). sublista(Xs,Ys):- concat(AsXs,Bs,Ys), concat(As,Xs,AsXs).
| ?- prefijo([1,2],[1,2,3,4]). yes
| ?- sufijo([3,4],[1,2,3,4]). yes
| ?- pertenece1(1,[2,1,3]). yes
| ?- sublista([2,3],[1,2,3,4]). yes
Definir los predicados prefijo, sufijo y sublista de forma recursiva sin la ayuda del predicado concat
Definir mediante concat los predicados: pertenece(X,Xs):-X es un elemento de Xs reverse (Xs,Ys):-Ys es Xs con los elementos en orden inverso adyacentes(X,Y,Xs) :- X e Y están en posiciones consecutivas en Xs ultimo(Xs,X) :- X es el último elemento de Xs primeros(Xs,Ys) :-Ys es el resultado de eliminar el último elemento a Xs
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
| ?- 3+5==2+6. no
& Para la comparación se utiliza el operador “=<” en lugar del más habitual “<=” debido a que éste último se asemeja a una doble flecha y se reserva para otros propósitos
. Describir la diferencia entre el comportamiento de los operadores: “=”, “is ” y “=:=”
fact(0,1). fact(N,F):-N > 0, N1 is N - 1, fact(N1,F1), F is N * F1.
fact(N,F):-F es el factorial de N
4 La versión de factorial aquí presentada es poco eficiente.
| ?- fact(5,V). V = 120
sum([],0). sum([X|Xs],S):-sum(Xs,Sc), S is Sc + X.
long([],0). long([X|Xs],L):-long(Xs,Lc), L is Lc + 1.
prod([],1). prod([X|Xs],P):-prod(Xs,Pc), P is Pc * X.
| ?- sum([1,2,3,4],V). V = 10
| ?- long([1,2,3,4],V). V = 4
| ?- prod([1,2,3,4],V). V = 24
%% Version optimizada de sum sum1(Xs,S):-sumAux(Xs,0,S).
sumAux([],S,S). sumAux([X|Xs],Sa,S):-Sn is X + Sa, sumAux(Xs,Sn,S).
& Obsérvese la similitud entre las tres definiciones. En algunos lenguajes se utilizan construcciones de orden superior que permiten utilizar una única definición parametrizada por las operaciones y constantes^5.
4 Las definiciones ofrecidas no aprovechan la optimización de la recursividad de cola. Consiste en que el último objetivo de una definición recursiva sea el predicado que se está definiendo. Los sistemas con dicha optimización permiten que las definiciones recursivas se comporten de forma similar a un bucle en un lenguaje imperativo. sum1 es una versión optimizada de sum
4 La definición de sum1 sigue el patrón de acumulación de resultados que se ve a continuación
A diferencia de los lenguajes imperativos, Prolog utiliza variables lógicas. En el momento en que una variable lógica es instanciada, dicho valor no puede modificarse. De esta forma, no es posible utilizar variables globales 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]
=
j
i
yj 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.
ordenada([X,Y|Ys]):-X 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.
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). V = [97,98,99]
| ?- 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.
subTerL(S,[A|As]):- subTer(S,A). 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) ;
X = b ;
X = a ;
subTerm(T,T). subTerm(S,T):-compound(T), functor(T,F,A), subTermA(A,S,T).
subTermA(N,S,T):-arg(N,T,Ta), subTerm(S,Ta). subTermA(N,S,T):-N > 1, N1 is N - 1, subTermA(N1,S,T).
como ‘univ’
subTerm(S,T):- Se cumple si S es un subtérmino de T.
4 En general el predicado ‘=..’ proporciona la misma expresividad que los predicados ‘functor’ y ‘arg’ juntos. Sin embargo, 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
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 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.
En general, la utilización del corte debe ser examinada con precaución. En muchas ocasiones conviene sustituir el corte 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). soloMujeres([X|Xs],Ys) :- hombre(X), soloMujeres(Xs,Ys).
| ?- soloMujeres3([ana,pedro,maria],V). V = [ana,maria] ;
no
soloMujeres(Xs,Ys):-Ys contiene las mujeres de Xs
Si se hace backtracking, el predicado chequeará más alternativas comprobando si las mujeres son, a su vez, hombres.
soloMujeres1([],[]). soloMujeres1([X|Xs],[X|Ys]) :- mujer(X), !, soloMujeres1(Xs,Ys). soloMujeres1([X|Xs],Ys) :- hombre(X), soloMujeres1(Xs,Ys).
soloMujeres1 : Si se inserta un corte tras la condición mujer se le indica al sistema que no busque más alternativas cuando encuentra una mujer.
soloMujeres2([],[]). soloMujeres2([X|Xs],[X|Ys]) :- mujer(X), !, soloMujeres2(Xs,Ys). soloMujeres2([X|Xs],Ys) :- soloMujeres2(Xs,Ys).
soloMujeres2: Utilizando el corte, si el sistema encuentra una mujer, no va a chequear si es un 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).
soloMujeres3([],[]). soloMujeres3([X|Xs],Ys1) :- ifThenElse(mujer(X), Ys1 = [X|Ys], Ys1 = Ys), soloMujeres3(Xs,Ys).
El esquema conseguido puede generalizarse.
ifthenelse (Cond,X,Y) :-Si Cond entonces ejecuta X sino , ejecuta Y.
soloMujeres4([],[]). soloMujeres4([X|Xs],Ys1) :- (mujer(X) -> Ys1 = [X|Ys] ; Ys1 = Ys), soloMujeres4(Xs,Ys).
El predicado ifThenElse está predefinido mediante el operador ‘->’.
8.5.1.2 Negación por fallo
El lenguaje Prolog utilice un subconjunto de la lógica de predicados de primer orden (cláusulas Horn ) lo que impide modelizar ciertas situaciones con conocimiento negativo. La negación por fallo es una aproximación a las té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.
animal(X):-perro(X). animal(X):-serpiente(X).
serpiente(kika). perro(kiko).
Se desea representar el siguiente conocimiento:
“A Ana le gustan todos los animales salvo las serpientes”
fail es un predicado interno que siempre falla.
Programación Práctica en Prolog Aplicaciones del Corte
le_gusta(ana,X):-serpiente(X),!,fail. le_gusta(ana,X):-animal(X).
| ?- le_gusta(ana,kika). no
| ?- le_gusta(ana,kiko). yes
Se puede generalizar el patrón de negación por fallo.
falla_si(X):-call(X),!,fail. falla_si(X).
le_gusta2(ana,X):-falla_si(serpiente(X)), animal(X).
| ?- le_gusta2(ana,kika). no
| ?- le_gusta2(ana,kiko). yes
falla_si(X):- falla si el objetivo X se cumple y se cumple si X falla.
4 El predicado falla_si está predefinido en Prolog Standard como el operador: ‘+’.
& En muchos sistemas, el predicado ‘+’ se conoce como not. En la definición Standard se decidió evitar el predicado not para que los usuarios no lo confundiesen con una negación común. El símbolo ‘+’ pretende ser una representación del símbolo matemático? (no demostrable)
| ?- le_gusta2(ana,X). no
| ?- le_gusta2(ana,X). no
Con variables sin instanciar no funciona. En cuanto encuentra una serpiente, falla y no busca más alternativas.
le_gusta3(ana,X):- animal(X), falla_si(serpiente(X)).
En esta caso, puede corregirse cambiendo de orden los 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 defecto
pension(X,invalidez):- invalido(X),!. pension(X,jubilacion):- jubilado(X),!. pension(X,nada). invalido(pedro). jubilado(tomas). jubilado(pilar).
| ?- pension(tomas,X). X = jubilado
| ?- pension(ana,X). X = nada
pension(P,Tp):- Tp es el tipo de pension que le corresponde a la persona P
J Con preguntas sencillas funciona
| ?- pension(tomas,nada). yes
| ?- pension(X,jubilacion). X = tomas
| ?-
K No funciona, debería responder que no!
L Tampoco funciona, le ha quitado la pensión a Pilar
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). pension2(X,jubilacion):- jubilado(X).
La solución sería quitar el corte y utilizar dos niveles.