Ejemplos prolog

60
Varilla de la izquierd a Varilla central Varilla de la derecha FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS CURSO DE SISTEMAS BASADOS EN EL CONOCIMIENTO 1 PROFESOR: PERVYS RENGIFO RENGIFO AUTOR: FELIPE FORERO INGENIERIA DE SISTEMAS VIII SEMESTRE 2007-I 1) Elabore un programa en prolog que permita resolver el problema de las Torres de Hanoi. Solución: Las torres de Hanoi se ha convertido en uno de los problemas clásicos dentro de las ciencias de la computación- El problema es fácil de comprender, y admite una solución recursiva simple. La historia puede ser embellecida de varias formas. Hay tres varillas, una de las cuales tiene un número de discos insertados, formando una pirámide. La cuestión fundamental es los discos están insertados en orden de tamaño, con el más grande en el fondo. La figura siguiente ilustra la condición inicial del problema Figura 1: Ilustración de la condición inicial del problema de la torre de Hanoi (Tomada de http://www.pbclibrary.org/raton/towers.htm) La tarea es transferir los discos desde la varilla de la izquierda hasta la varilla de la derecha, apoyándose, si se necesita, en la varilla central.

Transcript of Ejemplos prolog

Page 1: Ejemplos prolog

Varilla de la izquierda

Varilla central

Varilla de la derecha

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

CURSO DE SISTEMAS BASADOS EN EL CONOCIMIENTO 1PROFESOR: PERVYS RENGIFO RENGIFO

AUTOR: FELIPE FOREROINGENIERIA DE SISTEMAS VIII SEMESTRE

2007-I

1) Elabore un programa en prolog que permita resolver el problema de las Torres de Hanoi.Solución:Las torres de Hanoi se ha convertido en uno de los problemas clásicos dentro de las ciencias de la computación- El problema es fácil de comprender, y admite una solución recursiva simple.La historia puede ser embellecida de varias formas. Hay tres varillas, una de las cuales tiene un número de discos insertados, formando una pirámide. La cuestión fundamental es los discos están insertados en orden de tamaño, con el más grande en el fondo. La figura siguiente ilustra la condición inicial del problema

Figura 1: Ilustración de la condición inicial del problema de la torre de Hanoi (Tomada de http://www.pbclibrary.org/raton/towers.htm)

La tarea es transferir los discos desde la varilla de la izquierda hasta la varilla de la derecha, apoyándose, si se necesita, en la varilla central. Lo que hace no trivial este problema es que se deben cumplir tres restricciones:

1) Los discos pueden ser movidos uno a la vez.Si no estuviera esta restricción el problema se resolvería moviendo el bloque de la varilla actual a la varilla de la derecha.

2) Un disco sólo puede ser movido a otra varilla.Otra vez, esto previene una solución trivial – dejar los disco en el piso, y luego insertarlos en las varilla de la derecha. Esta restricción obliga a utilizar la varilla del centro para almacenar temporalmente los discos.

3) Un disco más grande nunca puede ser coloca encima de uno más pequeño.

Page 2: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

Si esta restricción no existiera, el problema podría, otra vez ser fácilmente resuelto. Simplemente se pasarían todos discos en la varilla central y luego trasladarían a la varilla de la derecha.

El problema computacional básico de las torres de Hanoi consiste en escribir un programa que incluya las operaciones necesarias para realizar la transferencia de un conjunto de N discos desde la varilla de la izquierda hasta la varilla de la derecha.La manera de pensar un problema recursivo es siempre concentrarse en dos preguntas:

a) Cuál es el caso baseEl caso más simple de las torres de Hanoi podría ser para una pirámide de solo un disco. El caso más simple es a menudo directo el es fácil de olvidar pero es fundamental para el éxito de cualquier recursión. Aquí, la cuestión es esencialmente esta: Como transferir una pila de un disco desde el la varilla de la izquierda, utilizando la varilla de la mitad( si es necesario), a la verilla de la derecha?. La respuesta es directa: Sólo mueva el disco de la pila de la izquierda a la pila de la derecha.También podría tomarse como caso base, el caso de que no haya discos. En este caso la respuesta es muy simple: Si no hay discos, entonces, no haga nada.En este momento no se sabe precisamente como formalizar esta respuesta. Debido a que el caso base es el más simple, su definición podría no aclarar qué factores se deben tomar en cuenta para la solución general del problema, es decir que argumentos tendría la función o el predicado principal que aproxime la solución. Sin embargo, el planteamiento si hace una distinción entre dos operaciones y el tipo de entidades a las que se aplican: Transferencia de pilas(de discos) y movimiento de un disco individual.Recuerde que la tarea general es transferir una pirámide de n discos, desde una varilla a otra, apoyándose en una tercera varilla como almacenamiento temporal, pero una de las restricciones establece que su solución debe involucrar el movimiento de discos individuales de una varilla a otra.

b) Cual es el caso recursivo

Pensar acerca de este problema recursivamente es pensar cómo puede usar la transferencia de una pila de discos para ayudar en su propia definición, es decir pensar cómo el problema de la transferencia de N discos puede ser reducido a un caso más simple de transferencia.Una aproximación inicial para este problema se logra haciendo la siguiente reflexión:Se deben pasar todos los discos desde la varilla de la izquierda hasta la varilla de la derecha pero no puede colocarse un disco más grande sobre uno más pequeño, moviendo solo un disco a la vez. Si pudiera pasar el disco más grande desde la varilla de la izquierda a la varilla de la derecha, tendría un comienzo excelente para transferir la pila de discos hasta la varilla de la derecha, ya que para que esta transferencia sea exitosa los discos se deben transferir aquí desde el mayor hasta el menor (recuerde que así están ordenados en la pila de la izquierda). Sin embargo, para hacer esto se requieren dos condiciones:

Page 3: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

Que el disco más grande quede solo en la varilla de la izquierda(sin ningún disco encima de él) y

que la varilla de la derecha no tenga, en este momento, ningún disco.De estas condiciones resulta como consecuencia que los N-1 discos que se encuentran inicialmente encima del disco más grande deben ser transferidos a la varilla central(utilizando, si se requiere, a la varilla de la derecha como varilla de almacenamiento temporal).La siguiente gráfica ilustra estas condiciones:

Figura 2: Se deben pasar n-1 discos desde la varilla izquierda hasta la varilla central

Figura 3: Luego se puede pasar el disco más grande desde la varilla izquierda hasta la varilla de la derecha.

Figura4: Estado final luego de las acciones anteriores.

Esto sugiere la primera fase de la recursión: Con el fin de transferir N discos desde la varilla de la izquierda a la varilla de la derecha, se debe transferir N-1 discos desde la varilla de la izquierda a la varilla central. El problema de transferir una pila de N discos se ha reducido al problema de transferir una pila de N-1 discos. Observe que durante la transferencia de los N-1 discos de la varilla de la izquierda hasta la varilla del centro, la varilla de la derecha actuará como varilla de almacenamiento temporal. Sin embargo, a pesar de que en el proceso de este paso, la varilla de la derecha almacenará temporalmente discos, al final de este paso, la varilla de la derecha no contendrá ningún disco, ya que todos estarán en la varilla del centro(N-1 disco) y en la varilla de la izquierda (el disco más grande)(ver figura 3).El paso siguiente de la recursión es el paso pivotal: mover el disco más grande desde la varilla de la izquierda hasta la varilla de la derecha(ver Figuras 3 y 4).La tercera fase de la recursión requiere que se transfiera los N-1 discos desde la varilla central hasta la varilla de la derecha, durante lo cual, la varilla de la izquierda actuará como varilla de almacenamiento temporal.Esta solución requiere que se distinga entre cada varilla particular y el papel que juega en cualquier fase de la operación. Cuando se inicia con N discos, la varilla de la izquierda es la fuente y la varilla de la derecha es el destino y la varilla central es la de almacenamiento temporal. Cuando esto se reduce al problema de transferir N-1 discos, la varilla de la mitad es la fuente, la de la derecha es el destino y la de la izquierda es la de almacenamiento temporal.

Implementación en PrologPara la implementación se requiere un predicado que permita transferir una pila de N discos desde una fuente X, apoyándose como almacenamiento temporal en Y, a un destino Z, que se podría declarar como:transfiera(N,X,Y,Z).

Caso Base:

Page 4: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

El caso base del algoritmo recursivo, como se mencionó más arriba podría ser el caso en que la pila de la izquierda tenga solamente un disco, para lo cual se requiere solamente, mover el disco desde el origen hasta el destino. En prolog, esto podría escribirse como:

transfiera(1,Izquierda,Centro,Derecha):- mueva_disco(Izquierda,Derecha).También podría considerarse como caso base el caso más trivial, en el cual no hay disco, en este caso simplemente, no hay que hacer nada. En prolog se escribiría así:

transfiera(0,Izquierda,Centro,Derecha).

Usted puede elegir uno de estos dos casos bases. Para este ejemplo se elegirá el caso de 0 discos como el caso base, y se exigirá que N>=0.

Caso RecursivoAquí simplemente se debe expresar en la sintaxis de prolog el algoritmo discutido anteriormente:Para transferir N discos desde la varilla Izquierda hasta la varilla Derecha haga lo siguiente:Transfiera N-1 discos desde la varilla de la izquierda hasta la varilla central, utilizando la varilla de la derecha como varilla de almacenamiento temporal.Luego, mueva el disco más grande (que quedó solo en la varilla de la izquierda), desde la varilla Izquierda hasta la varilla Derecha.A continuación, transfiera los N-1 discos desde la varilla Centro, hasta la varilla Derecha, utilizando la varilla izquierda como varilla de almacenamiento temporal.

En prolog, esto se expresaría de la siguiente forma

transfiera(N,Izquierda,Centro,Derecha):- %Para transferir N discos de Izquierda a Derecha, utilizando Centro como apoyo

N>0,M is N-1, % se asegura que N>0 y almacena N-1 en M

transfiera(M,Izquierda,Derecha,Centro), %transfiera N-1 discos de Izquierda a Centro, utilizando Derecha como apoyo

mueva_disco(Izquierda, Derecha), %mueva el disco mayor de Izquierda a Derecha

transfiera(M,Centro,Izquierda,Derecha). %transfiera N-1 discos de Centro a Derecha, utilizando a Derecha como apoyo

Ahora se define el predicado mueva_disco(Izquierda, Derecha). Este predicado solo debe indicar de donde a donde se realizará el movimiento del disco

mueva_disco(Izquierda,Derecha):- write('Mueva el disco de arriba desde '), write(Izquierda), write(' hasta '), write(Derecha),nl.

Finalmente el programa quedaría de la siguiente manera:

transfiera(0,Izquierda,Centro,Derecha).transfiera(N,Izquierda,Centro,Derecha):- N>0,M is N-1, transfiera(M,Izquierda,Derecha,Centro),

Page 5: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

mueva_disco(Izquierda, Derecha), transfiera(M,Centro,Izquierda,Derecha). mueva_disco(Izquierda,Derecha):- write('Mueva el disco de arriba desde '), write(Izquierda), write(' hasta '), write(Derecha),nl.

mueva_disco(Izquierda,Derecha):- write('Mueva el disco de arriba desde '), write(Izquierda), write(' hasta '), write(Derecha),nl.

Al compilar este programa y correrlo con 3 discos en la varilla izquierda, mediante transfiera(3,izquierda,centro,derecho), se obtiene:

2) Un sistema de producción consiste en un conjunto de pares “situación-acción”, indicando que si esta situación surge, tome esta acción. Un ejemplo de un sistema de producción es el programa “numerales romanos” dado abajo:

% Numerales Romanos para 1 <= X <= 39romano(X) :-

X > 39, write('Numero debe estar entre 1 y 39'), nl.

romano(X) :-X < 0, write(' Numero debe estar entre 1 y 39'), nl.

romano(X) :-X >= 10, X =< 39,write('X'),Y is X - 10,romano(Y).

romano(X) :-X == 9,write('IX').

romano(X) :-X >= 5, X =< 8,write('V'),Y is X - 5,romano(Y).

Page 6: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

romano(X) :-X == 4,write('IV').

romano(X) :-X >= 1, X =< 3,write('I'),Y is X - 1,romano(Y).

romano(0) :- nl.

Estudie como trabaja este algoritmo, y extiéndalo para manejar todos los números desde 1 a 399. Muestre que su programa funciona para 49, 51, 99, 101,299, y 399.Escriba un ciclo que despliegue los números romanos de todos los números entre 1 y 399 inclusive.

SOLUCION:

Se puede notar que la manera de procesar el número es de los mayores valores hacia los menores, ya que es la manera de escribir un número romano, encontramos primero los símbolos de mayor peso, o que representan mayor valor. Para expender el código para que maneje los número del 1 al 399, empezamos de manera similar, procesando primero los números de mayor valor, descomponiéndolo hasta llegar a un mínimo valor.

Antes de comenzar se valida que el número este en el rango que el algoritmo puede manejar:

romano(X) :-X > 399, write('Numero debe estar entre 1 y 399'), nl.

romano(X) :-X < 0, write(' Numero debe estar entre 1 y 399'), nl.

Empezamos entonces con los números que sean mayores o iguales que 100 y menores a 400, si esto sucede, se imprime una C como parte del resultado, y le restamos al numero de entrada estos 100 que ya se representaron, y volvemos a llamar la función, de manera recursiva, de tal manera que vuelva a hacer esta evaluación, y así poner tantas C como sea necesario o seguir con uno de los predicados siguientes:

romano(X) :-X >= 100, X =< 399,write('C'),Y is X - 100,romano(Y).

Una vez el numero sea menor que 100, se evalúa de nuevo, y si esta entre 90 y 99, agregamos a la salida ‘XC’, que es la manera de representar al 90, al hacer

Page 7: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

esto, tenemos que restarle al numero 90, ya que ya fueron representados, y se vuelve a llamar la función con este nuevo numero como argumento

romano(X) :-X >= 90, X < 100,write('XC'),Y is X-90,romano(Y).

Si el número esta entre 50 y 89, se le agrega a la salida una ‘L’, que representa el numero 50 en romano, y estos 50 son restados del numero a representar, y se vuelve a llamar la función romano con este nuevo valor

romano(X) :-X >= 50, X < 90,write('L'),Y is X - 50,romano(Y).

En el caso en que el número al que se le aplica la función romano es mayor o igual a 40 y menor que 50, se agrega a la salida ‘XL’, que representa 40 en romano. Como se ha venido haciendo, se le resta al numero procesado 40, que ya fueron representados, y con este valor se llama de nuevo la función romano, para seguir procesando el valor restante.

Hasta este punto es la modificación que se le tuvo que hace al algoritmo para que procesara números del 1 a 399.

romano(X) :-X >= 40, X < 50,Y is X-40,write('XL'),romano(Y).

En otro caso, si el numero a procesar es mayor o igual a 10 y menor que 40, se agrega a la salida una X que representa un 10, estos se le restan a el numero y se vuelve a llamar la función con este nuevo valor

romano(X) :-X >= 10, X =< 39,write('X'),Y is X - 10,romano(Y).

Cuando el número es igual a 9, se agrega a la salida ‘IX’, que representa al número 9 en romano, y no se vuelve a llamar la función. Cuando el número esta entre 5 y 8, se agrega a la salida ‘V’, se le resta 5 al número y se vuelve a llamar la función con este nuevo valor.

romano(X) :-

Page 8: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

X == 9,write('IX').

romano(X) :-X >= 5, X =< 8,write('V'),Y is X - 5,romano(Y).

En otra entrada a la función, si el número es igual a 4, se agrega a la salida ‘IV’, y no se vuelve a llamar la función, ya que el número estaría totalmente representado en romano. Cuando el numero es menor que 4 y mayor o igual a 1, se agrega a la salida ‘I’, se resta 1, y se vuelve a llamar la función con el nuevo valor.

El algoritmo quedaría de la siguiente manera:

% Numerales Romanos para 1 <= X <= 39romano(X) :-

X > 399, write('Numero debe estar entre 1 y 399'), nl.

romano(X) :-X < 0, write(' Numero debe estar entre 1 y 399'), nl.

romano(X) :-X >= 100, X =< 399,write('C'),Y is X - 100,romano(Y).

romano(X) :-X >= 90, X < 100,write('XC'),Y is X-90,romano(Y).

romano(X) :-X >= 50, X < 90,write('L'),Y is X - 50,romano(Y).

romano(X) :-X >= 40, X < 50,Y is X-40,write('XL'),romano(Y).

romano(X) :-X >= 10, X =< 39,write('X'),Y is X - 10,

Page 9: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

romano(Y).romano(X) :-

X == 9,write('IX').

romano(X) :-X >= 5, X =< 8,write('V'),Y is X - 5,romano(Y).

romano(X) :-X == 4,write('IV').

romano(X) :-X >= 1, X =< 3,write('I'),Y is X - 1,romano(Y).

romano(0) :- nl.

Finalmente, para imprimir todos los números del 1 al 399 en romano, usamos la función forall, acompañada de la función integer_bound:

romanos:- forall(integer_bound(1,A,399), romano(A)), nl.

De esta manera, al llamar la función romanos, se imprimirán todos los números.El programa final sería el siguiente:

% Numerales Romanos para 1 <= X <= 39romano(X) :-

X > 399, write('Numero debe estar entre 1 y 399'), nl.

romano(X) :-X < 0, write(' Numero debe estar entre 1 y 399'), nl.

romano(X) :-X >= 100, X =< 399,write('C'),Y is X - 100,romano(Y).

romano(X) :-X >= 90, X < 100,write('XC'),Y is X-90,romano(Y).

romano(X) :-X >= 50, X < 90,write('L'),

Page 10: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

Y is X - 50,romano(Y).

romano(X) :-X >= 40, X < 50,Y is X-40,write('XL'),romano(Y).

romano(X) :-X >= 10, X =< 39,write('X'),Y is X - 10,romano(Y).

romano(X) :-X == 9,write('IX').

romano(X) :-X >= 5, X =< 8,write('V'),Y is X - 5,romano(Y).

romano(X) :-X == 4,write('IV').

romano(X) :-X >= 1, X =< 3,write('I'),Y is X - 1,romano(Y).

romano(0) :- nl.

romanos:- forall(integer_bound(1,A,399), romano(A)), nl.

Al correr el predicado “romanos”, se obtiene el siguiente resultado:

Si quisiera saber cómo se escribe un número cualquiera en el intervalo [1,399], puede utilizar el predicado “romano”, de la siguiente forma:

Page 11: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

3) Definir los siguientes predicados

a. Definir en prolog la siguiente función:

F(x)=2, si x>10F(x)= raíz(x), si 0≤ x ≤10

F(x)=-x, si x <0

SOLUCION

Se definen los predicados de la misma manera que están enunciados, usando la función de prolog ,‘sqrt(X)’, que sirve para hallar la raíz cuadrada de X.

funcion(X,2):-X>10, !.funcion(X,Y):-X>=0, X=<10, Y is sqrt(X), !.funcion(X,Y):-X<0, Y is -X, !.

Al correr el programa, se obtiene:

b. suma(Liminferior, LimSup, Suma), donde suma es igual a la suma de los enteros desde límite inferior hasta límite superior.

Page 12: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

Por ejemplo: Suma(2, 10, Suma), debería retornar suma= 2+3+4+5+6+7+8+9+10= 54

SOLUCIONSe definen los predicados de manera recursiva:Caso base: Cuando el valor del límite inferior, Liminferior, es igual al limite superior, LimSup. En este caso la Suma es igual a Liminferior.

Suma= ∑i=Liminferior

Liminferior

i=Liminferior

Esto se podría indicar de la siguiente manera:suma(Liminferior, Liminferior, Liminferior):- !.Caso recursivo: Cuando Liminferior < LimSup, en este caso, la Suma es igual a Liminferior más la suma desde Liminferior+1 hasta LimSup.

Suma= ∑i=Liminferior

lim sup ¿i=Liminferior+ ∑i=Liminferior+1

lim sup ¿i¿

¿¿

¿

Esto se escribe de la siguiente manera:suma(Liminferior, LimSup, Suma):- Liminferior<LimSup, NuevoLim is Liminferior+1, suma(NuevoLim,LimSup,NuevaSuma), Suma is Liminferior + NuevaSuma.En este predicado, NuevoLim es Liminferior+1, y es el nuevo límite de la suma. NuevaSuma es la suma desde NuevoLim hasta LimSup, y Suma es la suma total, igual a Liminferior más NuevaSuma.Es decir, que para este caso, se vuelve a llamar al predicado “suma”, esta vez con el limite inferior incrementado en 1, y el resultado se le suma al limite inferior.Finalmente, el programa quedaríasuma(Liminferior, Liminferior, Liminferior):- !.suma(Liminferior, LimSup, Suma):- Liminferior<LimSup, NuevoLim is Liminferior+1, suma(NuevoLim,LimSup,NuevaSuma), Suma is Liminferior + NuevaSuma.

A continuación una corrida de este programa:

Page 13: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

c. Construya el predicado: Productoria(Liminferior, LimSup, Prod), donde Prod sea el producto de los enteros entre liminferior y LimSup. Por ejemplo Productoria(2,5,Prod), debe retornar, Prod= 2*3*4*5=120

SOLUCION

La manera de implementar el predicado que realice este producto, es similar a la manera en que se desarrollo el punto 4 de este taller, la única diferencia es que en lugar de hacer la suma, se hace el producto:

productoria(X,Y,X):- X==Y,!.productoria(X,Y,Prod):- X<Y, A is X+1, productoria(A,Y,S), Prod is X*S

d. Construya el predicado: raicesecuacion(A,B,C,X1.X2) donde X1 y X2 son las raíces de la ecuación cuadrática: AX^2+BX+C= 0.

SOLUCIONPara solucionar este problema se consideran dos casos:1) Cuando el discriminante, B2−4 AC ≥ 0, en este caso las soluciones

son reales.

X 1=−B+√B2−4 AC2 A

X 2=−B+√B2−4 AC2 A

Aquí se incluye el caso en que B2−4 AC=0, en el cual X1=X22) Cuando el discriminante, B2−4 AC <0, en este caso las soluciones

son conjugadas complejas.

X 1=−B2 A

+ √|B2−4 AC|2 A

i

X 2=−B2 A

−√|B2−4 AC|2 A

i

Adicionalmente, con el fin de garantizar que la ecuación sea cuadrática, se verificará que el primer coeficiente sea diferente de cero.

El programa quedaría de la siguiente forma:raicesecuacion(A,_,_,_,_):-A=:=0, write('Para que la ecuación sea cuadrática,el primer coeficiente debe ser diferente de cero'),abort,!.raicesecuacion(A,B,C,X1,X2):-B*B-4*A*C>=0, X1 is (-B+sqrt(B*B-4*A*C))/(2*A), X2 is (-B-sqrt(B*B-4*A*C))/(2*A),!.raicesecuacion(A,B,C,X1,X2):-B*B-4*A*C<0, Aux is abs(B*B-4*A*C), Xr is -B/(2*A), Xi is sqrt(Aux )/(2*A),

Page 14: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

X1=Xr+Xi*i, X2=Xr-Xi*i.

A continuación se presentan varias corridas de este programa:

e. Construya el predicado: potencia(X,N, Pot), donde Pot= X^N, pero sin utilizar la función ^ definida en prolog.

SOLUCION%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

La potenciación tiene una definición recursiva:

X N=X∗X N−1

Caso Base: X0=1, lo cual se indicaría en prolog de la siguiente manera:potencia(X,0, 1).

Caso recursivo: X N=X∗X N−1

potencia(X,N,P):-Y is N-1, potencia(X,Y,Q), P is X*Q,!.

Aunque esto captura el contenido lógico de la potenciación, no es totalmente correcta como un programa, debido a la forma como prolog busca la solución a una consulta. En primera instancia este programa retornará el resultado correcto para un X>0, pero cuando se pregunte por soluciones adicionales, se hará una recursión infinita, ya que en ninguna parte del programa se ha establecido que existe una única solución para X0,por lo tanto prolog intentará encontrar otras soluciones para potencia(X,0, P), ahora utilizando la definición recursiva.En este caso se generará una recursión infinita, ya que no hay un caso base para detenerla y se produdirá un desbordamiento de pila.

Page 15: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

Al escribir “;” o presionar la barra espaciadora, se pregunta a prolog por soluciones alternativas, obteniéndose:

Para resolver este inconveniente, se debe indicar a prolog que X0=1 y no hay más soluciones; esto se puede hacer utilizando el corte,!, de la siguiente forma: potencia(X,0, 1):-!.El corte evita que prolog, una vez halle una solución, siga buscando otras soluciones.Para evitar que se produzcan errores por el procesamiento de exponentes negativos:%caso recursivo N>0potencia(X,N,P):-N>0, Y is N-1, potencia(X,Y,Q), P is X*Q,!.

El caso de exponentes negativos se puede incluir teniendo en cuenta que para N<0:

X N= 1

X|N|

Con lo cual esta parte quedaría como:%caso recursivo N<0potencia(X,N,P):-N<0,

Page 16: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

AN is abs(N), potencia(X,AN,Q), P is 1/Q,!.

El programa, finalmente sería:

%%%Potencias(X,N,P) calcula el valor de X^N, y lo almacena en P%caso base X^0=1 potencia(X,0,1):-!. %caso recursivo N>0potencia(X,N,P):-N>0, Y is N-1, potencia(X,Y,Q), P is X*Q,!. %caso recursivo N<0potencia(X,N,P):-N<0, AN is abs(N), potencia(X,AN,Q), P is 1/Q,!.

A continuación se presentan algunas ejecuciones de este programa:

f. Construya el predicado: Fibonacci(N,M), donde M es N-ésimo término de la serie de fibonacci

SOLUCION

La serie fibonacci también la definimos en términos recursivos, ya que el n-esimo término de la serie es igual a la suma de los dos términos anteriores. Los casos base de la serie son el primer y segundo termino de la serie, que son el 0 y el 1. Los otros los podemos hallar de la suma de los dos anteriores términos de la serie:fibonacci(0,0):-!.fibonacci(1,1):-!.fibonacci(N,M):-N>0, A is N-2, B is N-1, fibonacci(A,X), fibonacci(B,Y),

Page 17: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

M is X+Y.

g. Construya el predicado:Tabla_de_multiplicar(X, LimSup) imprima la tabla de multiplicar de X, desde 1 hasta LimSup.

Ejemplos: Tabla_multiplicar(2, 5), debe imprimir:

2*1=22*2=42*3=62*4=82*5=10

SOLUCION

Para este predicado podemos usar la función de Prolog llamada integer_bound, la cual, si se llama con los parámetros (1,M,L), en M asignará un numero entero desde 1 hasta L, incrementándose de 1 en 1, cada vez que se llame la función. Para obligar a que prolog vuelva a entrar en el predicado, usamos la instrucción fail, que hace que prolog vuelva a buscar una solución, y así incrementar a M en la siguiente entrada. Cada vez que entre se va a imprimir la multiplicación con M del numero del que se quiere la tabla de multiplicar, que en este caso es X. esto sucederá hasta que M llegue a L.

tabla_de_multiplicar(X,L):- integer_bound(1,M,L), R is X*M, write(X * M = R), nl, fail.

Al ejecutar este predicado para generar la tabla de multiplicación del 9, desde 1 hasta 10, se obtiene lo siguiente:

Page 18: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

Utilizando un esquema recursivo también es posible obtener el mismo resultado.Se define un predicado que escribe las multiplicaciones:escribir_mult(X,N,R):-write(X*N=R), nl.Se define un predicado que imprime las tabla de multiplicar para X, desde LimInf hasta LimSup:Caso Base: Si LimInf =LimSup, entonces escriba X*N=R, donde R es la variable en donde se almacena el resultado numérico de X*N. multiplicar(X,LimSup,LimSup):-Resultado is X*LimSup, escribir_mult(X,LimSup,Resultado),!.

Caso Recursivo: Si LimInf<LimSup, escriba X*LimInf=Resultado, incremente LimInf y almacénelo en NuevoLimInf y haga la tabla desde NuevoLimInf hasta LimSup. multiplicar(X,LimInf,LimSup):-LimInf<LimSup , Resultado is X*LimInf, escribir_mult(X,LimInf,Resultado), NuevoLimInf is LimInf+1, multiplicar(X,NuevoLimInf,LimSup).

Con base en este predicado se define el predicado tabla_de_multiplicar(X,LimSup) así:tabla_de_multiplicar(X,LimSup):- multiplicar(X,1,LimSup).

El programa completo sería:

escribir_mult(X,LimSup,Resultado):-write(X*LimSup=Resultado), nl.multiplicar(X,LimSup,LimSup):-Resultado is X*LimSup, escribir_mult(X,LimSup,Resultado),!.multiplicar(X,LimInf,LimSup):-LimInf<LimSup , Resultado is X*LimInf, escribir_mult(X,LimInf,Resultado), NuevoLimInf is LimInf+1, multiplicar(X,NuevoLimInf,LimSup).tabla_de_multiplicar(X,LimSup):- multiplicar(X,1,LimSup).

Page 19: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

En la siguiente figura se muestra un ejemplo de la ejecución de este predicado

h. Elabore un programa que simule una instrucción “while”, imprimiendo en pantalla una palabra, un número determinado de veces.

SOLUCIÓN:Se puede plantear una solución recursiva, basados en un predicado imprima_palabra(Veces, palabra), se la siguiente forma:Caso Base: Si Veces es igual a cero, no haga nada. Esto se escribiría como:imprima_palabra(0, Palabra).

Caso Recursivo: Si Veces es diferente a 0, entonces escriba Palabra , decremente Veces en 1 y vuelva a llamar el predicado imprima_palabra. Esto se indica en prolog de la siguiente forma

imprima_palabra(Veces, Palabra):-write(Palabra),nl, % esto corresponde al predicado que desea repetirVeces1 is Veces-1,imprima_palabra(Veces1,Palabra).

Al ejecutar este predicado con Veces=5, y Palabra = Pervys, se obtiene

Page 20: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

4) Construya predicados convenientes para calcular las siguientes series:

a) f ( x )=∑k=0

n

xk

b) f ( x )=∑k=1

nx2 k+1

2 k+1

c) sen ( x )=∑k=1

n

(−1 )k x2 k+1

(2k+1 )!

d) exp ( x )=∑k =0

nxk

k !

e) ln ( x )=∑k=1

n

(−1 )k−1 ( x−1 )k

k

f) cos (x )=∑k=0

n

(−1 )k x2 k

(2k )!

SOLUCION

Para desarrollar estos ejemplos se requiere desarrollar los siguientes predicados básicos:%%%Potencias(X,N,P) calcula el valor de X^N, y lo almacena en P%caso base X^0=1 potencia(X,0,1):-!. %caso recursivo N>0potencia(X,N,P):-N>0, Y is N-1, potencia(X,Y,Q), P is X*Q,!. %caso recursivo N<0potencia(X,N,P):-N<0, AN is abs(N), potencia(X,AN,Q), P is 1/Q,!.

%%factorial(N,Factorial) calcula el valor de N!, y lo almacena en NFactorial%caso base 0!=1factorial(0,1):-!.%caso recursivofactorial(N,NFactorial):-N>0,X is N-1, factorial(X,Y),

Page 21: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

NFactorial is N*Y,!.

%%%Factorial version iterativafactorial_iter(N,F) :- fact_iter(N,1,F).%El valor en Aux, cuando I sea 0 es el factorialfact_iter(0,F,F):-!.fact_iter(I,Aux,F) :- I1 is I-1,

Aux1 is I*Aux, fact_iter(I1,Aux1,F).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

a) f 1 ( x )=∑k =0

n

xk

%%versión 1suma1(X,LimInf,LimInf, Suma1):-potencia(X,LimInf,Suma1),!.suma1(X,LimInf,N,Suma1):-N>0,K is LimInf+1, potencia(X,LimInf,R), suma1(X,K,N,T), Suma1 is R+T.f1(X,N,F1):- suma1(X,0,N, F1).Considérese el caso en el cual X=3 y N=7

f 1 ( x )=∑k =0

7

3k=30+31+32+33+34+35+36+37=3.280

Al correr este programa se obtiene:

%%versión 2suma11(X,0,1):-!.suma11(X,N,S):-N>0,K is N-1, potencia(X,N,R), suma11(X,K,T), S is R+T,!.

Page 22: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

f11(X,N,F1):- suma11(X,N, F1).Al correr esta nueva versión se obtiene:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

a) f 2 ( x )=∑k =0

nx2 k+1

2k+1

f2(X,0,X):-!.f2(X,N,S):-N>0,Q is N-1, P is 2*N+1, potencia(X,P,Z), f2(X,Q,T), S is Z/P+T.

Al correr esta predicado con X=3 y N=4, se obtiene:

f 2 (3 )=∑k=0

432 k+1

2k+1= 32( 0)+1

2 (0 )+132 (1 )+1

2 (1 )+1+ 32 (2 )+1

2 (2 )+1+ 32 (3 )+1

2 (3 )+1+ 32 ( 4) +1

2 (4 )+1=2560.02857

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Page 23: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

a) sen ( x )=∑k=0

n

(−1 )k x2 k+1

(2 k+1 )!

suma3(X,0,X):-!.suma3(X,N,S):-N>0,Q is N-1, P is 2*N+1, potencia(X,P,Z), potencia(-1,N,R), factorial(P,F),suma3(X,Q,T), S is R*Z/F+T.

Ahora, con base en el predicado anterior se define la función seno, tomando N= 8 términos de la serie( N mayores producirán mayor exactitud)seno(X,Seno):-suma3(X,8,Seno).El programa completo quedaría así:suma3(X,0,X):-!.suma3(X,N,S):-N>0,Q is N-1, P is 2*N+1, potencia(X,P,Z), potencia(-1,N,R), factorial(P,F),suma3(X,Q,T), S is R*Z/F+T.seno(X,Seno):-suma3(X,8,Seno).

Al correr este programa con X=0.5 se obtiene:Sen(0.5)= 0.47942554

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

b) exp ( x )=∑k =0

nxk

k !

suma5(X,0,1):-!. suma5(X,N,S):-P is N-1, potencia(X,N,R), factorial(N,F), suma5(X,P,T),

Page 24: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

S is R/F+T.%Ahora se define la función exponencial con N=11exp (X,Exp):-suma5(X,11,Exp).

Al correr este programa con X=0.5, se obtiene:Exp(0.5)= 1.64872127

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

c) ln ( x )=∑k=1

n

(−1 )k−1 ( x−1 )k

k

suma6(X,1,S):-S is -1+X,!.suma6(X,N,S):-P is N-1, Q is -1+X, potencia(-1,P,R), potencia(Q,N,T), suma6(X,P,M), S is R*T/N+M.%Con base en el predicado anterior se define el Logaritmo, tomando 30 términos de la serieln(X,Ln):-suma6(X,30,Ln).

Al correr este programa con X=0.5 se obtiene: ln(0.5)= -0.69314718

Page 25: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

d) cos (x )=∑k=0

n

(−1 )k x2 k

(2k ) !

%%version 1suma7(X,0,1):-!.suma7(X,N,S):-Q is N-1, P is 2*N, potencia(X,P,Z), potencia(-1,N,R), factorial(P,F), suma7(X,Q,T), S is R*Z/F+T,!.coseno(X,Cos):-suma7(X,8,Cos).

%%version 2suma71(X,N,N,S):- P is 2*N,potencia(-1,N,R),potencia(X,P,Z),factorial(P,F),S is R*Z/F,!.suma71(X,N,N1,S):-Q is N+1, P is 2*N, potencia(X,P,Z), potencia(-1,N,R), factorial(P,F), suma71(X,Q,N1,T), S is R*Z/F+T,!.coseno1(X,Cos):-suma71(X,0,7,Cos).

Al correr estos programas con X=0.5, se obtiene:cos(0.5)= 0.87758256

Page 26: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

5) Elabore un programa que permita responder consultas acerca de las capitales de los departamentos de Colombia, siguiendo los siguientes lineamiento: Que cargue al iniciar la base de conocimiento incompleta sobre

departamentos y capitales del archivo “capital.pl”, lo cual se puede hacer almacenando en este archivo, hechos de la forma “capital(departamento, capital)”.

Cuando el usuario digite un departamento que no se encuentre en la base de conocimiento actual, el programa debe solicitar al usuario que ingrese la capital de ese departamento con el fin de aprenderla y poder responder adecuadamente en la siguiente ocasión.

Al finalizar el programa debe guardar en el archivo “capital.pl”, toda la base de conocimiento.

SOLUCIÓN%Se define a capital como un predicado dinámico de dos argumentos. Esto permite agregar instancias de este predicado, en tiempo de corrida% durante el tiempo de corrida.:-dynamic(capital/2).

% encuentraCapital es el predicado principal. El acepta el nombre de un departamento% y llama a buscaCapital para que haga la búsquedapregunta_cont:-write('desea continuar? '),read(T),continue(T).continue('s'):-encuentraCapital,!.continue('S'):-encuentraCapital,!.continue('n'):-continue('N').continue('N'):-write('Ahora se procederá a salvar la base de conocimiento'),nl, tell('capital.pl'), listing(capital), told, write('Ya se ha guardado'),nl,write(' ADIOS!!!!!!').continue(_):-pregunta_cont,!.

inicio:-reconsult('capital.pl'), encuentraCapital.

Page 27: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

encuentraCapital :- write('ingrese el departamento: '),nl, read(Departamento), buscaCapital(Departamento), pregunta_cont. % buscaCapital usa la busqueda de encadenamiento hacia atrás para encontrar una matching % capital(Departamento, Capital). Si él tiene éxito, entonces imprime la ciudad y se detiene

buscaCapital(Departamento) :- capital(Departamento, Capital), write('La capital del departamento: '),write(Departamento), write(' es: '), write(Capital), nl.% El control pasará aquí solamente si el primer intento de búsqueda falla% En ese caso se pregunta al usuario para que proporcione la información. % Observe el uso de assertz, que adiciona la nueva información al final de la base de conocimiento

buscaCapital(Departamento) :-write('Yo no conozco ese departamento.'),nl, write('Usted me podría decir cuál es su capital?'),nl, write('Yo lo recordaré la próxima vez.'), read(Capital), assertz(capital(Departamento, Capital)), write('Gracias!'), nl.

inicio:-captchreconsult('capital.pl'), encuentraCapital.inicio:-catch(Error,reconsult('capital.pl')),Error=:=31->fcreate(cap,'capital.pl',0,0,0),fclose(cap),reconsult('capital.pl'), encuentraCapital;encuentraCapital.%reconsult('capital.pl'), encuentraCapital.

1. Construya un programa que implemente los siguientes métodos para hallar raíces de ecuaciones no lineales:Método de BisecciónMétodo de Regla falsa

Page 28: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

Método de la Secante.

CONTROL CON EL CORTE Por una variedad de razones, una definición puede ser lógicamente correcta pero ser ineficiente como un programa. Una forma en la que un programa es ineficiente es por permitir a Prolog que busque más soluciones cuando no hay más soluciones. Esto hace que Porlog gaste un poco de tiempo hasta darse cuenta que ya no hay más soluciónes y en el pero de los casos lo enviará a un ciclo infinito. Prolog tiene una característica especial que restringe la búsqueda para soluciones alternativas, el corte. En la sintaxis de Edimburgo ella se escribe como una signo de exclamación. A pesar de su nombre el corte es un buen instumento de corte para controlar a un programa restringiendo el backtracking. La idea básica es que cuando prolog pasa por una ocurrencia de ¡!, al intentar resolver alguna consulta, el corte previene el re-paso de ese punto cuando hace el backtracking.Una vez prolog alcanza el ¡! En algún punto dentro de una cláusula, else vuelve comprometido para la solución de cualquier meta que lo obtenga en la búsqueda de ese punto , y puede backtarck solamente a la derecha del corte.Suponga que diversas cláusulas en la definición de algún predicado p, y que una de ellas contiene una ocurrencia de ¡!,imagine que en el curso de resolver alguna consulta , Prolog necesita encontrar una solución ap(x) y obtener la cláusula con el corte. Una analogía sería, si pensamos a prolog como un vehículo que viaja una ruta hacia adelante y hacía atrás a traves de un progrmam, buscano soluciones, ese corte es un tipo especial de traluz de tráfico. Inicialmente, las luces estan en verde. Cuando Prolog pasa a través de la luz , búsqueda de una solución, ellas automáticamente cambian a rojo,. Prolog puede seguir hacia delante y hacia atrás la parte de la carretera que está después de las luces, en la búsqueda de soluciones , pero no puede pasar hacia atrás de las luces para intentar re-resolver las metas que las preceden.

Tv(t)Tv(f)Pair(X,Y):-tv(X),tv(Y).Sintácticamente, el corte puede ser adicionado como una condición atómica en cualquier parte en el cuerpo de una regla. Por ejemplo podemos colocarlo así.Pair(X,Y):-tv(X),!!,tv(Y).Hay tres lugares en donde podría ser colocado en esta regla, la cual marcaría como sigue:Pair(X,Y):- (iii), tv(X), (ii) tv(Y) (i).

Ninguna de las tres posiciones corresponde a un usos realísticos del corte, pero ilustran su efecto sobre el backtracking. Si nosotros colocamos el cote al final de la cláusula n la posición (i), Prolog es reducido a las soluciones que él obtiene para tv(X) y tv(Y) que obtiene allí; el no puede baktrack de ninguna forma. Si nosotros lo clocamos en la posición ii) esto libera para backtrack sobre la soluciónes de tv(Y), pero no sobre tv(X). Poniéndolo en la posición iii, significa que prolog cruza el corte tan pronto como intenta resolver pair, y es reducido a esa cláusula. El puede backtrack por todas las metas a la derecha, justo como el programa original sin corte. Pero si hubieran clausulas adicionales a la definición de pair, un! En la posición (iii) podría resultar redundante

Page 29: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

pair(X,Y) tv(X)

X=f

X=t tv(Y)

tv(Y)

Y=f

Y=t

Y=f

Y=t i

ii

iii

pair(t,t)

pait(t,f)

pair(f,t)

pair(f,f)

Posición (i) permite a este programa solo una solución, (i) le permite dos, y (iii) permite todas las cuatro.

Factorial:La función factorial es uno de los ejemplos más simples de recursión numérica. Para construir la función vamos a analizar el procedimiento de cálculo para un ejemplo en particular:5!=5*4*3*2*1=5*4!Generalizando:n!=n(n-1)!En palabras: el factorial de un número es ese número multiplicado por el factorial de su predecesor.Adicionando a esto el caso base de que 1!=1, se tiene una definición recursiva del factorial. En notación matemática:1!.N!=N(N-1)!Para calcular el factorial de un número n, primero encontramos el número X que es uno menos que n, luego halle el factorial Y de X, luego multiplique Y por N. En prologFac.(1,1).Fac.(N,M):-X is N-1, fact(X,Y), M is N*Y.Aunque esto es esencialmente correcto, aquí surge el mismo problema que ocurre durante el retroceso para el caso de la potenciación. Si se requieren soluciones adicionales, fact generará una regresión infinita.

Page 30: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

fact(3,M)

Ruta invertida durante el retroceso

M=6

X is 3-1 fact(2,Y) M is 3*2

Y is 2*1fact(1,B)A is 2-1

X=2

2 is 3-1

6 is 3*2

Y=2

B=1A=1

6 is 3*21 is 2-1

fact(1,1)

!

Ruta de la solución

C is 1-1 fact(0,D)

fact(-1,F)E=0-1

E=-1

C=0

Nosotros podemos prevenir esto conla estrategia adoptada para exp: insertando un N>1 como la primera condición en el antecedente de la cláusula general, nosotros hacemos explícita la condición que fact aplica solamente para número mayores que 1. Hay sin embargo, una manera completamente diferente de asegurar este efecto. Más que construir en la definición la condición que fact solo aplica a números positivos, nosotros tenemos como meta hacerlo a partir del hecho de que fact es una función. En este sentido aunque sabemos que el factorial es una relación funcional que para la cualquier N solo puede existir uno y solo un M tal que fact(N,M), no hay nada en el programa que lo explicite. Nosotros sabemos por ejemplo que la única solución para fact(1,M) es M=1. Pero si Prolog está buscando soluciones para esta meta, nada en le programa hasta ahora le dice que esta es la única instancia de esa relación.El corte nos habilita para asegurar este efecto-decirle a Prolog que no intente buscar soluciones alternativas para fact(1,M). Ya que ¡ es sintácticamente solo una condición atómica, si nosotros deseamos adicionar un corte a una sentencia incondicional, la haremos condicional:fact(1,1):-!.En general, es mejor pensar el corte como no teniendo ningún efecto sobre la lectura declarativa de un sentencia, es decir para leer esto como:El fatorial e 1 es 1, incondicionalmente( es decir si nada)Esto es esencialmente lo mismo que antes. Debido a que el corte esta relacionado con el

Page 31: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

control, es decir con la restricción del backtracking, el corte no se muestra realmente en el contenido lógico de un programa. Donde el hace una diferencia significativa es en la lectura procedimental.Para probar que el factorial de 1 es 1, no haga nada(esto es lo mismo que sin ¡)-pero falle totalmente en cualquier intento por re-resolver esta meta.Sin embargo, en este caso la presencia del corte es ligeramente especial, en que nosotros podemos pensarlo como una afectación al contenido descriptivo de la definición., vizEl factorial de 1 es, únicamente 1.Esto es, pensarlo como decirle a prolo que fact es una función que para el caso del número 1 , el único M para el cual fact(1,M) es 1(y el único N para el cual fac(N,1) es 1) Debido a que esto es la base para una recursión, la unicidad tiene aquí el efecto de asegurar la unicidad para todos los números.Para ver la forma que tiene el corte para prevenir que fact entre en una regresión infinita en el retroceso, ayuda seguie la manera como el factorial es calculado en un caso particular, por ejemplo hallar el factorial de 3 es 6. Nosotros ilustramos el camino para la solución como siguies.Cada vez el fact se llama recursivamente , mostramos el valor obtenido en los cálculos como instanciaciones sucesivas de la regla general hasta que se verifique la condición base.

El siguiente predicado chequea si un elemento pertenece a una lista

pertenece(X,[X|_]).pertenece(X,[_|Ys]):-pertenece(X,Ys).

Tamaño de una lista

longitud([],0).

longitud([H|T],N) :- size(T,N1), N is N1+1.

The length of the empty list is 0. The length of the list whose head is H and whose tail is the list T is: 1 + (the

length of T).

La longitud de la lista vacia es cero:La longitud de la lista cuya cabeza es H y cuya cola es T es 1+(la longitud de T)

Suma de los elementos de una listasumlist([],0).

sumlist([H|T],N) :- sumlist(T,N1), N is N1+H.La suma de los elementos de la lista vacía es 0.La suma de los elementos de la lista cuya cabeza es H y cuya cola es T, es H+ ( la suma de los elementos de T).

Menbresíamember(X,[X|_]).

Page 32: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

member(X,[_|T]) :- member(X,T).x es un miembro si la lista cuyo elemento de la cabeza es X( y cuya cola es cualquiera.X es miembro de la lista cuya cabeza es cualquiera y cuya cola es T, si X es un miembro de T

Predicado appendappend([a,b,c],[one,two,three],Result).

Suponga uque se desea escribir un predicado de un argumento, e imprima todos los nùmero entre èl y 0.

Imprima_hasta(0) :- write(0). Imprima_hasta(N) :- N>0, write(N), nl, N1 is N-1, imprima_hasta(N1)Si N=0, imprima 0Si N>0, escriba N, haga N-1 y luego imprima N-1, hasta que N=0.

Ahora suponga que deseamos tomar estos números y procesarlos en una cierta otra parte del programa; para hacer esto tendríamos que almacenarlos en alguna parte - la opción natural es utilizar una lista. Así desearíamos un predicado de la forma collect_to(N, L) donde estaba el número N de la entrada, y L era la lista que contenía la respuesta.

collect_to(0,L) :- L=[].

This will be slightly different to the other list predicates, since now we want to build a list as we iterate, rather than take one apart. However, the process will still use the standard "[H|T]" notation that we have been using.

We should work it out int he usual recursive manner:

Esto será levemente diferente a los otros predicados de lista, ya que ahora nosotros deseamos construir una lista conforme se itera, y no tomar cada uno por separado. Sin embargo, el proceso usarà la notacion estándar [ H|T ] .

Caso Base: Si el numero que se ingresa es igual a 0, entonces la respuesta es sera [ 0 ], asì se puede escribir

collect_to(0,L) :- L=[]. Caso Recursivo:Si se està tratando con un numero, por decir N, entonces asumimos que sabemos como recolectar todos los nùmero hasta N-1(gracias a la recursiòn) de tal forma que solo necesitamos conocer como asicionarun bit de información extra acerca del elemento actual; el codigo seria

collect_to(N,L) :- N>0, N1 is N-1, collect_to(N1,T), L=[N|T].

Aunque esto esta bien la manera mas normal de escribir esto es:new_collect_to(0,[]).new_collect_to(N,[N|T]) :- N>0, N1 is N-1, new_collect_to(N1,T).JUNTANDO LISTAS

Page 33: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

Nosotros podemos escribir un predicado que junte dos listas; el predicado append(L1,L2,L3) significa Si juntamos L1 y L2 se obtine L3

Si se consideran las posibilidades para L1

1) L1 es vacìa, caso en el cual L3 es L22) L1 es de la forma [H1 | T1].

1. L1 is the empty list, in which case L3 is just L2 2. L1 is of the form [H1 | T1]., se obtendría una lista cuya cabeza es H1 y cuya

cola es el resultado de juntar T1 y L2

Asì un intento inicial sería

append(L1,L2,L3) :- L1=[], L3=L2. append(L1,L2,L3) :- L1=[H1|T1], append(T1,L2,T3), L3=[H1|T3].

Ya que se sabe que prolog harà unificación cuando el empareje(matches) parámetro contra argumentos, una soluciòn mas simple( pero equivalente) serìa

append([], L2, L2).

append([H1|T1], L2, [H1|L3]) :- append(T1,L2,L3).

Haga las siguientes consultas-

append([1,2],[6,7],X) append(X, [5,6], [3,5,6]). append([3,4], Y, [3,4,5,6]). append(X,Y,[1,2]).

El operador "corte".

El operador corte, representado por el símbolo "!" nos da un cierto control sobre el mecanismo de deducción del PROLOG.  Su función es la de controlar el proceso de reevaluación, limit ndolo a los hechos que nos interesen. Supongamos la siguiente regla:

        regla :- hecho1, hecho2, !, hecho3, hecho4, hecho5.

PROLOG efectuará reevaluaciones entre los hechos 1, 2 sin ningún problema, hasta que se satisface el hecho2.  En ese momento se alcanza el hecho3, pudiendo haber a continuación reevaluaciones de los hechos 3, 4 y 5. Sin embargo, si el hecho3 fracasa, no se intentara de ninguna forma reevaluar el hecho2.

Una interpretación práctica del significado del corte en una regla puede er que "si has llegado hasta aquí es que has encontrado la única solución a este problema y no hay razón para seguir buscando alternativas".

Aunque se suele emplear como una herramienta para la optimización de programas, en muchos casos marca la diferencia entre un programa que funciona y otro que no lo hace.

Page 34: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

% From the book% PROLOG PROGRAMMING IN DEPTH% by Michael A. Covington, Donald Nute, and Andre Vellino% (Prentice Hall, 1997).% Copyright 1997 Prentice-Hall, Inc.% For educational use only

% File CAR.PL% Simple automotive expert system

:- reconsult('getyesno.pl'). % Use ensure_loaded if available.

%% Main control procedures%

start :- write('This program diagnoses why a car won''t start.'),nl, write('Answer all questions with Y for yes or N for no.'),nl, clear_stored_answers, try_all_possibilities.

try_all_possibilities :- % Backtrack through all possibilities... defect_may_be(D), explain(D), fail.

try_all_possibilities. % ...then succeed with no further action.

%% Diagnostic knowledge base% (conditions under which to give each diagnosis)%

defect_may_be(drained_battery) :- user_says(starter_was_ok,yes), user_says(starter_is_ok,no).

defect_may_be(wrong_gear) :- user_says(starter_was_ok,no).

defect_may_be(starting_system) :- user_says(starter_was_ok,no).

Page 35: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

defect_may_be(fuel_system) :- user_says(starter_was_ok,yes), user_says(fuel_is_ok,no).

defect_may_be(ignition_system) :- user_says(starter_was_ok,yes), user_says(fuel_is_ok,yes).

%% Case knowledge base% (information supplied by the user during the consultation)%

:- dynamic(stored_answer/2).

% (Clauses get added as user answers questions.)

%% Procedure to get rid of the stored answers% without abolishing the dynamic declaration%

clear_stored_answers :- retract(stored_answer(_,_)),fail.clear_stored_answers.

%% Procedure to retrieve the user's answer to each question when needed,% or ask the question if it has not already been asked%

user_says(Q,A) :- stored_answer(Q,A).

user_says(Q,A) :- \+ stored_answer(Q,_), nl,nl, ask_question(Q), get_yes_or_no(Response), asserta(stored_answer(Q,Response)), Response = A.

%% Texts of the questions%

ask_question(starter_was_ok) :- write('When you first started trying to start the car,'),nl, write('did the starter crank the engine normally? '),nl.

Page 36: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

ask_question(starter_is_ok) :- write('Does the starter crank the engine normally now? '),nl.

ask_question(fuel_is_ok) :- write('Look in the carburetor. Can you see or smell gasoline?'),nl.

%% Explanations for the various diagnoses%

explain(wrong_gear) :- nl, write('Check that the gearshift is set to Park or Neutral.'),nl, write('Try jiggling the gearshift lever.'),nl.

explain(starting_system) :- nl, write('Check for a defective battery, voltage'),nl, write('regulator, or alternator; if any of these is'),nl, write('the problem, charging the battery or jump-'),nl, write('starting may get the car going temporarily.'),nl, write('Or the starter itself may be defective.'),nl.

explain(drained_battery) :- nl, write('Your attempts to start the car have run down the battery.'),nl, write('Recharging or jump-starting will be necessary.'),nl, write('But there is probably nothing wrong with the battery itself.'),nl.

explain(fuel_system) :- nl, write('Check whether there is fuel in the tank.'),nl, write('If so, check for a clogged fuel line or filter'),nl, write('or a defective fuel pump.'),nl.

explain(ignition_system) :- nl, write('Check the spark plugs, cables, distributor,'),nl, write('coil, and other parts of the ignition system.'),nl, write('If any of these are visibly defective or long'),nl, write('overdue for replacement, replace them; if this'),nl, write('does not solve the problem, consult a mechanic.'),nl.

% suma de vectoressumavectores( [],[],[] ).sumavectores( [C1|R1],[C2|R2],[C3|R3] ):-C3 is C1+C2, sumavectores( R1,R2,R3 ).

Page 37: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

?-sumavectores( [1,2,3], [4,5,6], X ).X=[5,7,9]%suma de matrices bidimensionalessumamatrices( [],[],[] ).sumamatrices( [C1|R1],[C2|R2],[C3|R3] ):-sumavectores(C1,C2,C3),sumamatrices(R1,R2,R3).?-sumamatrices([[1,2],[3,4]],[[5,6],[7,8]],X).X=[[6,8],[10,12]].

%suma generalizadasuma([],[],[]).suma(X,Y,Z):- var(Z),number(X),number(Y),Z is X+Y.suma( [C1|R1],[C2|R2],[C3|R3] ):-suma(C1,C2,C3),suma(R1,R2,R3).?-suma( [1,2,3], [4,5,6], X ).X=[5,7,9]?-suma([[1,2],[3,4]],[[5,6],[7,8]],X).X=[[6,8],[10,12]].?-suma([[[1,2],[1,1]],[[2,2],[3,4]]],[[[5,6],[0,0]],[[8,8],[7,8]]],X).X=[[[6,8],[1,1]],[[10,10],[10,12]]].

Definición de operadores- Contenido de la base de conocimiento:- op(800,xfx,estudian).:- op(400,xfx,y).juan y ana estudian logica.- Consultas:?- Quienes estudian logica.Quienes = juan y ana?- juan y Otro estudian Algo.Otro = anaAlgo = logica

2.6 Tree data and relations

Consider the following tree diagram.

Page 38: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

Fig. 2.6

The file 2_6.pl has a representation for this tree and predicate definitions to do some processing of the tree. Note the use of Prolog operators in some of the definitions.

/* The tree database */

:- op(500,xfx,'is_parent').

a is_parent b. c is_parent g. f is_parent l. j is_parent q. a is_parent c. c is_parent h. f is_parent m. j is_parent r. a is_parent d. c is_parent i. h is_parent n. j is_parent s. b is_parent e. d is_parent j. i is_parent o. m is_parent t. b is_parent f. e is_parent k. i is_parent p. /* X and Y are siblings */ :- op(500,xfx,'is_sibling_of'). X is_sibling_of Y :- Z is_parent X, Z is_parent Y, X \== Y. /* X and Y are on the same level in the tree. */ :-op(500,xfx,'is_same_level_as').

X is_same_level_as X . X is_same_level_as Y :- W is_parent X, Z is_parent Y, W is_same_level_as Z. /* Depth of node in the tree. */ :- op(500,xfx,'has_depth').

a has_depth 0 :- !. Node has_depth D :- Mother is_parent Node, Mother has_depth D1, D is D1 + 1. /* Locate node by finding a path from root down to the node. */ locate(Node) :- path(Node), write(Node), nl. path(a). /* Can start at a. */

Page 39: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

path(Node) :- Mother is_parent Node, /* Choose parent, */ path(Mother), /* find path and then */ write(Mother), write(' --> '). /* Calculate the height of a node, length of longest path to a leaf under the node. */ height(N,H) :- setof(Z,ht(N,Z),Set), /* See section 2.8 for 'setof'. */ max(Set,0,H). ht(Node,0) :- leaf(Node), !. ht(Node,H) :- Node is_parent Child, ht(Child,H1), H is H1 +1. leaf(Node) :- not(is_parent(Node,Child)). max([],M,M). max([X|R],M,A) :- (X > M -> max(R,X,A) ; max(R,M,A)).

The 'is_sibling_of' relationship tests whether two nodes have a common parent in the tree. For example, ?- h is_sibling_of S. S=g ; S=i ; no

Note the use of the literal X \==Y, which succeeds just in case X and Y are not cobound (bound to the same value).

The 'is_same_level_as' relationship tests whether two nodes are on the same level in the tree.

The 'depth' predicate computes the depth of a node in the tree (how many edges from the root). For example,

?- t has_depth D. D=4

Here is an alternate definition of 'depth' using Prolog implication:

N has_depth D :- N == 'a' -> D=0 ; Mother is_parent N, Mother has_depth D1, D is D1 + 1.

The 'locate' predicate computes and prints a path from the root to a node. For example,

?- locate(n). a --> c --> h --> n

Page 40: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

The 'leaf' predicate defines a leaf to be a node which is not a parent. Note the free variable inside the negation. This is correct, since if the node has any child then the node is not a leaf.

The 'height' predicate computes the height of a node -- defined as the length of the longest path to a leaf under the node. This definition uses lists and the second-order Prolog predicate 'setof'. We will continue discussion of 'height' and 'setof' in section 2.8.

Load the program into the Prolog environment and test the program by issuing various goals.

Exercise 2.6.1 Write a Prolog definition for 'ancestor(X,Y)' with the intended meaning that "X is an ancestor of Y in the tree". Pay attention: recursion from the top of the tree or from the bottom of the tree?

Exercise 2.6.2 Formulate definitions for a human family tree using relations 'male', 'female', 'parent', 'father', 'mother', 'sibling', 'grandparent', 'grandmother', 'grandfather', 'cousin', 'aunt', and 'uncle'. Let 'male', 'female', 'parent' be the fundamental relations and define the others in terms of these.

Prolog Code for this section. Prolog Tutorial Contents

The program is mainly interesting with regard to how it tries to verify certain properties that it uses to draw conclusions, and how it asks questions and records the answers for further reference. If a question q is asked and the answer is 'yes', then that answer is recorded by asserting 'yes(q)' and succeeding, otherwise the answer is recorded by asserting 'no(q)' and failing. Even 'yes' answers need to be recorded since a subsequent 'no' answer to a different question while trying to verify the same hypothesis may cause the entire hypothesis to fail, but that same 'yes' answer could lead to a successful verification of a different hypothesis later. This is how the program avoids asking the same question twice. The general method of verifying a condition q is then to check whether 'yes(q)' has been stored in memory, and succeed, or 'no(q)' has been stored, and fail, otherwise ask(q).

Factorial (N)Si N = 0 entonces Factorial = 1Si N > 0 entonces Factorial = N * Factorial (N-1)

Suponga que desea crear un programa que halle todas las soluciones para un objetivo dado. Si se pretende crear un predicado que recursivamente muestre las soluciones, entonces puede ocurrir un desbordamiento de pila. Una opción es utilizar los siguientes predicados:Findall(T,C,L)

father(michael,cathy).father(charles_gordon,michael).father(jim,melody).

Page 41: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

We can ask Prolog to display the names of all the fathers by issuing a query such as:?- father(X,_), write(X), nl, fail.That is: Find an X for which father(X,_) succeeds, print it, and backtrack to findanother one.But what if, instead of displaying the names, we want to process them furtheras a list? We are in a dilemma. In order to get all the names, the program mustbacktrack. But in order to construct the list, it must use recursion, passing thepartially constructed list as an argument from one iteration to the next — which abacktracking program cannot do.One possibility would be to use assert and retract to implement roughly thefollowing algorithm:1. Backtrack through all solutions of father(X,_), storing each value of X in aseparate fact in the knowledge base;2. After all solutions have been tried, execute a recursive loop that retracts all thestored clauses and gathers the information into a list.Fortunately, we don’t have to go through all this. The built–in predicatefindall will gather the solutions to a query into a list without needing to performasserts and retracts.5 Here’s an example:?- findall(X,father(X,_),L).L = [michael,charles_gordon,jim]More generally, a query of the form?- findall(Variable,Goal,List).will instantiate List to the list of all instantiations of Variable that correspond tosolutions of Goal. You can then process this list any way you want to.The first argument of findall need not be a variable; it can be any term withvariables in it. The third argument will then be a list of instantiations of the firstargument, each one corresponding to a solution of the goal. For example:?- findall(Parent+Child,father(Parent,Child),L).L = [michael+cathy,charles_gordon+michael,jim+melody]Here the plus sign (+) is, of course, simply a functor written between its arguments.Exercise 5.14.1Given the knowledge base5If your Prolog lacks findall, define it: findall(V,Goal,L) :- bagof(V,Goal^Goal,L).

5.15. USING bagof AND setofA BAG is a mathematical object like a set except that the same element can occur init more than once. Obviously, findall creates a bag, not a set, because the samesolution can appear in it more than once. Likewise, bagof creates a bag in theform of a list containing all the solutions to a query; setof does the same thingexcept that the list is sorted into alphabetical order and duplicates are removed. Thesorting operation takes extra time, but it can be worthwhile if it saves duplication ofsubsequent work.The big difference between bagof and setof on the one hand, and findallon the other, concerns the way they handle uninstantiated variables in Goal that donot occur in X. As you might expect, findall treats them as uninstantiated on everypass. Thus,?- findall(X,parent(X,Y),L).means “Find everyone who is the parent of anybody” – Y need not have the samevalue for each parent. But?- bagof(X,parent(X,Y),L).

findall/3

Page 42: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

Retorna una lista no ordenada de términos en las soluciones de una meta u objetivo dado.findall( Termino, Objetivo, Lista )?Termino <término>+Objetivo <Objetivo>?Lista <variable> o <lista>Comentarios Este predicado retorna una lista no ordenada de soluciones que normalmente se pueden obtener sólo por falla y backtracking a través de una consulta. Este predicado es exitoso si Lista puede ser unificada a una lista de todas las instancias de Término tales que el Objetivo sea cierto. El Término puede ser cualquier termino de Prolog, y el Objetivo puede ser cualquier objetivo Prolog, con o sin llamadas al predicado “cuantificador existencial”, ^ / 2, que es ignorado en el presente predicado

Examples Consider the database relation:foo( 1, c ).foo( 2, a ).foo( 1, b ).foo( 2, a ).La siguiente llamada devuelve una lista de todas las soluciones de "X" en el Objetivo "foo(Y,X)", sin hacer partición en los diferentes valores de "Y":?- findall( X, foo(Y,X), Z ). <enter>X = _ ,Y = _ ,Z = [c,a,b,a]Notes A diferencia de los predicados bagof/3 y setof/3, findall/3 no realiza ninguna partición de resultados. Por lo tanto, no tiene el concepto de "cuantificación existential ", y como tal trata cualquier llamada a ^/2 sólo como si el objetivo apropiado se llamara directamente.

bagof/3Retorna una lista no ordenada de términos en las soluciones de un objetivo dadobagof( Termino, Objetivo, Lista )?Term <term>+Goal <goal>?List <variable> or <list>Comments Este predicado retorna una lista no ordenada de soluciones que normalmente se pueden obtener sólo por falla y backtracking a través de una consulta. Este predicado es exitoso Lista puede ser unificada a una lista de todos las instancias de Término tales que el Objetivo sea cierto. El Término puede ser cualquier termino de Prolog, y el Objetivo puede ser cualquier objetivo Prolog, con o sin llamadas al predicado “cuantificador existencial”, ^ / 2, que es usado para alterar la partición e las soluciones

Examples Consider the database relation:

Page 43: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

padre( felipe, jose ).foo( Felipe, maria ).foo( 1, b ).foo( 2, a ).La siguiente llamada retorna los conjuntos de soluciones de "X" en el objetivo "foo(Y,X)", particionado de acuerdo a los diferentes valroes de "Y":?- bagof( X, foo(Y,X), Z ). <enter>X = _ ,Y = 1 ,Z = [c,b] ; <space>X = _ ,Y = 2 ,Z = [a,a] ; <space>noIf it is desired to get all solutions irrespective of the bindings of "Y", then "existential quantification" can be used:Si se desea obtener todas las soluciones independientemente de los valores de "Y", entonces se puede usar "la cuantificación existencial":?- bagof( X, Y^foo(Y,X), Z ). <enter>X = _ ,Y = _ ,Z = [c,a,b,a]Notes El predicado bagof/3 está muy relacionado con setof/3. La única diferencia en el comportamiento es que el último ordena los conjuntos retornados, removiendo las solcuiones duplicadas en el proceso.La característica de "existential quantification" de bagof/3 y setof/3 a menudo causan confusión. En general, las solcuiones para ambos predicados se particionan simplmente de acuerdo con los valores de las variables que aparecen en el Objetivo pero no en el TérminoConsidere el comando:?- bagof( (X,Y), foo(X,Y,A,B), Z ).Esto podría retornar una serie de listas de (X,Y) para el predicado hipotético, foo/4, con cada lista correspondiente a una combinación diferente de (A,B). Supóngase que lo que se desea es obtener una partición de acuerdo a los valores de B, pero no de A, todo lo que se requiere es mencionar a A en el Objetivo como el operando izquierdo de una llamada a ^/2:?- bagof( (X,Y), A^foo(X,Y,A,B), Z ).Esta vez, las series de listas de las soluciones (X,Y) serán divididas de acuerdo cin los diferentes valores de B: efectivamente, A será ignorado durante la partición.El átomo "^" se define como un operador infijo y asociativo por la izquierda, de tal forma que se puede mencionar una serie de variables, extendiendo(profundizando) simplmente la secuencia de llamadas de a ^/2:?- bagof( (X,Y), A^B^foo(X,Y,A,B), Z ).Note que aparte de la interpretación especial en los predicados bagof/3 y setof/3, ^/2 no tiene ningún significado diferente al de la

Page 44: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

meta que constituye su segundo argumento; Es por esto que el comando:?- A ^ foo(A,B).Es en todo los aspectos idéntico al comando?- call( foo(A,B) ).One remaining solution set predicate, findall/3, returns all solutions to a goal, without partitioning or sorting: in this case, use of existential quantification is meaningless.

setof/3Retorna conjuntos ordenados de términos en las soluciones de un objetivo dadosetof( Termino, Objetivo, Lista )?Termino <terminos>+Objetivo<objetivo>?Lista<variable> o <lista>Este predicado retorna conjuntos ordenados de soluciones que normalmente se pueden obtener sólo por falla y backtracking a través de una consulta. Este predicado es exitoso Lista puede ser unificada a una lista de todos las instancias de Término tales que el Objetivo sea cierto. El Término puede ser cualquier termino de Prolog, y el Objetivo puede ser cualquier objetivo Prolog, con o sin llamadas al predicado “cuantificador existencial”, ^ / 2, que es usado para alterar la partición e las soluciones

Examples Consider the database relation:foo( 1, c ).foo( 2, a ).foo( 1, b ).foo( 2, a ).La siguiente llamada retorna conjuntos de soluciones de "X" en el Objetivo "foo(Y,X)", particionado de acuerdo a los diferentes valores de "Y":?- setof( X, foo(Y,X), Z ). <enter>X = _ ,Y = 1 ,Z = [b,c] ; <space>X = _ ,Y = 2 ,Z = [a] ; <space>noIf it is desired to get all solutions irrespective of the bindings of"Y", then "existential quantification" can be used:?- setof( X, Y^foo(Y,X), Z ). <enter>X = _ ,Y = _ ,Z = [a,b,c]

integer_bound/3genera o prueba enteros entre una cota superior y una cota inferiorinteger_bound( Cota_Inferior, Numero, Cota_Superior )

Page 45: Ejemplos prolog

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE INGENIERÍA DE SISTEMAS

+Cota_Inferior <entero>?Numero <entero> o <variable>+Cota_Superior <integer>Comments When called with three integers, this predicate succeeds if the given Number is greater than or equal to the given Lower bound, and less than or equal to the given Upper bound. If both the Lower and Upper bounds are specified, but Number is an unbound variable, successive integers in the range [Lower..Upper] are bound to Number on backtracking.Cuando se llama con tres enteros, este predicado tiene éxito si el Número es mayor o igual a Cota_Inferior, y menor o igual que la Cota_Superior. Si se especifican tanto Cota_Inferior como Cota_Superior, pero Número es una variable no acotada, entonces, enteros sucesivos en el rango [Cota_Inferior… Cota_Superior], se unifican con el Número.

Examples La siguiente llamada verifica simplemente que "2" es un entero en el rango [1..3]:?- integer_bound( 1, 2, 3 ). <enter>yesLa siguiente llamada muestra que este predicado puede generar soluciones sucesivas en el backtracking:?- integer_bound( 1, X, 3 ). <enter>X = 1 ; <space>X = 2 ; <space>X = 3Notes

Aunque conveniente en su modo de "prueba", integer_bound/3 es en realidad como un generador de números. Debido a que Prolog no proporciona la asignación destructiva, es difícil escribir programas que se comporten como ciclos "for", incrementando un contador y deteniéndolo cuando se alcanza el límite. Una combinación de integer_bound / 3 y backtracking permite una solución simple a esta necesidad particular. La siguiente es una forma de escribir "para los valores de X de 0 a 9, escribir X"?- integer_bound( 0, X, 9 ), write( X ), fail ; nl. <enter>0123456789X = _