Documentos de Académico
Documentos de Profesional
Documentos de Cultura
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
Figura 2: Se deben pasar n-1 discos desde Figura 3: Luego se puede pasar el disco más Figura4: Estado final luego de las
la varilla izquierda hasta la varilla central grande desde la varilla izquierda hasta la varilla acciones anteriores.
de la derecha.
Implementación en Prolog
Para 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).
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
Caso Base:
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 Recursivo
Aquí 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.
transfiera(0,Izquierda,Centro,Derecha).
transfiera(N,Izquierda,Centro,Derecha):- N>0,M is N-1,
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
transfiera(M,Izquierda,Derecha,Centro),
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.
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:
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).
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
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
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).
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).
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 >= 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,
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
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.
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:
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) :-
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
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,
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.
F(x)=2, si x>10
F(x)= raíz(x), si 0≤ x ≤10
F(x)=-x, si x <0
SOLUCION
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:
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
SOLUCION
Se 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.
𝐿𝑖𝑚𝑖𝑛𝑓𝑒𝑟𝑖𝑜𝑟
𝑆𝑢𝑚𝑎 = ∑ 𝑖 = 𝐿𝑖𝑚𝑖𝑛𝑓𝑒𝑟𝑖𝑜𝑟
𝑖=𝐿𝑖𝑚𝑖𝑛𝑓𝑒𝑟𝑖𝑜𝑟
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.
𝐿𝑖𝑚𝑆𝑢𝑝 𝐿𝑖𝑚𝑆𝑢𝑝
𝑆𝑢𝑚𝑎 = ∑ 𝑖 = 𝐿𝑖𝑚𝑖𝑛𝑓𝑒𝑟𝑖𝑜𝑟 + ∑ 𝑖
𝑖=𝐿𝑖𝑚𝑖𝑛𝑓𝑒𝑟𝑖𝑜𝑟 𝑖=𝐿𝑖𝑚𝑖𝑛𝑓𝑒𝑟𝑖𝑜𝑟+1
SOLUCION
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.
SOLUCION
Para solucionar este problema se consideran dos casos:
1) Cuando el discriminante, 𝐵 2 − 4𝐴𝐶 ≥ 0, en este caso las
soluciones son reales.
−𝐵 + √𝐵 2 − 4𝐴𝐶
𝑋1 =
2𝐴
−𝐵 + √𝐵 2 − 4𝐴𝐶
𝑋2 =
2𝐴
−𝐵 √|𝐵 2 − 4𝐴𝐶|
𝑋1 = + 𝑖
2𝐴 2𝐴
−𝐵 √|𝐵 2 − 4𝐴𝐶|
𝑋2 = − 𝑖
2𝐴 2𝐴
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
Adicionalmente, con el fin de garantizar que la ecuación sea
cuadrática, se verificará que el primer coeficiente sea diferente de cero.
SOLUCION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
La potenciación tiene una definición recursiva:
𝑋 𝑁 = 𝑋 ∗ 𝑋 𝑁−1
Caso Base: X0=1, lo cual se indicaría en prolog de la siguiente
manera:
potencia(X,0, 1).
Caso recursivo: 𝑋 𝑁 = 𝑋 ∗ 𝑋 𝑁−1
potencia(X,N,P):-Y is N-1,
potencia(X,Y,Q),
P is X*Q,!.
1
𝑋𝑁 =
𝑋 |𝑁|
Con lo cual esta parte quedaría como:
%caso recursivo N<0
potencia(X,N,P):-N<0,
AN is abs(N),
potencia(X,AN,Q),
P is 1/Q,!.
SOLUCION
2*1=2
2*2=4
2*3=6
2*4=8
2*5=10
SOLUCION
multiplicar(X,LimSup,LimSup):-Resultado is X*LimSup,
escribir_mult(X,LimSup,Resultado),!.
escribir_mult(X,LimSup,Resultado):-write(X*LimSup=Resultado), nl.
multiplicar(X,LimSup,LimSup):-Resultado is X*LimSup,
escribir_mult(X,LimSup,Resultado),!.
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
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).
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).
imprima_palabra(Veces, Palabra):-
write(Palabra),nl, % esto corresponde al predicado que desea repetir
Veces1 is Veces-1,
imprima_palabra(Veces1,Palabra).
𝑛
a) 𝑓(𝑥) = ∑𝑘=0 x k
𝑛
x2k+1
b) 𝑓(𝑥) = ∑
𝑘=1 2k+1
𝑛
x2k+1
c) 𝑠𝑒𝑛(𝑥) = ∑ (−1)k
(2k+1)!
𝑘=1
𝑛
xk
d) 𝑒𝑥𝑝(𝑥) = ∑
𝑘=0 k!
𝑛
(𝑥−1)𝑘
e) 𝑙𝑛(𝑥) = ∑ (−1)𝑘−1
𝑘=1 𝑘
𝑛
𝑥 2𝑘
f) cos(𝑥) = ∑ (−1)𝑘
(2𝑘)!
𝑘=0
SOLUCION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
𝑛
a) 𝑓1 (𝑥) = ∑𝑘=0 𝑥 𝑘
%%versión 1
suma1(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
7
𝑓1 (𝑥) = ∑ 3𝑘 = 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 = 3.280
𝑘=0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
𝑛
𝑥 2𝑘+1
a) 𝑓2 (𝑥) = ∑
𝑘=0 2𝑘+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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
𝑛
x2k+1
a) 𝑠𝑒𝑛(𝑥) = ∑ (−1)k (2k+1)!
𝑘=0
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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
𝑛
xk
b) 𝑒𝑥𝑝(𝑥) = ∑
𝑘=0 k!
suma5(X,0,1):-!.
suma5(X,N,S):-P is N-1,
potencia(X,N,R),
factorial(N,F),
suma5(X,P,T),
S is R/F+T.
%Ahora se define la función exponencial con N=11
exp (X,Exp):-suma5(X,11,Exp).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
𝑛
(𝑥−1)𝑘
c) 𝑙𝑛(𝑥) = ∑ (−1)𝑘−1
𝑘=1 𝑘
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.
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
%Con base en el predicado anterior se define el Logaritmo, tomando 30
términos de la serie
ln(X,Ln):-suma6(X,30,Ln).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
𝑛
𝑥 2𝑘
d) 𝑐𝑜𝑠(𝑥) = ∑ (−1)𝑘 (2𝑘)!
𝑘=0
%%version 1
suma7(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 2
suma71(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).
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).
inicio:-reconsult('capital.pl'), encuentraCapital.
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
encuentraCapital :- write('ingrese el departamento: '),nl,
read(Departamento),
buscaCapital(Departamento),
pregunta_cont.
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.
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
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
Y=t i pair(t,t)
X=t ii tv(Y)
Y=f pait(t,f)
Y=t pair(f,t)
X=f tv(Y)
Y=f 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 prolog
Fac.(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.
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
fact(3,M) M=6
6 is 3*2
2 is 3-1
1 is 2-1 6 is 3*2
fact(1,1)
C is 1-1 fact(0,D)
C=0
!
E=0-1 fact(-1,F)
E=-1
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
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.
, viz
El 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.
pertenece(X,[X|_]).
pertenece(X,[_|Ys]):-pertenece(X,Ys).
longitud([],0).
longitud([H|T],N) :- size(T,N1), N is N1+1.
Menbresía
member(X,[X|_]).
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 append
append([a,b,c],[one,two,three],Result).
Imprima_hasta(0) :- write(0).
Imprima_hasta(N) :- N>0, write(N), nl, N1 is N-1, imprima_hasta(N1)
Si N=0, imprima 0
Si N>0, escriba N, haga N-1 y luego imprima N-1, hasta que N=0.
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.
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
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
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
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:
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".
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
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.
% File CAR.PL
% Simple automotive expert system
%
% 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.
%
% 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).
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).
%
% 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,
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
write('did the starter crank the engine normally? '),nl.
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 vectores
sumavectores( [],[],[] ).
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
sumavectores( [C1|R1],[C2|R2],[C3|R3] ):-C3 is C1+C2,
sumavectores( R1,R2,R3 ).
?-sumavectores( [1,2,3], [4,5,6], X ).
X=[5,7,9]
%suma de matrices bidimensionales
sumamatrices( [],[],[] ).
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 generalizada
suma([],[],[]).
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 = ana
Algo = logica
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.
:- op(500,xfx,'is_parent').
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.
a has_depth 0 :- !.
Node has_depth D :- Mother is_parent Node,
Mother has_depth D1,
D is D1 + 1.
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
The 'locate' predicate computes and prints a path from the root to a node. For example,
?- locate(n).
a --> c --> h --> n
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.
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 = 1
Si 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).
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 find
another one.
But what if, instead of displaying the names, we want to process them further
as a list? We are in a dilemma. In order to get all the names, the program must
backtrack. But in order to construct the list, it must use recursion, passing the
partially constructed list as an argument from one iteration to the next — which a
backtracking program cannot do.
One possibility would be to use assert and retract to implement roughly the
following algorithm:
1. Backtrack through all solutions of father(X,_), storing each value of X in a
separate fact in the knowledge base;
2. After all solutions have been tried, execute a recursive loop that retracts all the
stored clauses and gathers the information into a list.
Fortunately, we don’t have to go through all this. The built–in predicate
findall will gather the solutions to a query into a list without needing to perform
asserts 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 to
solutions 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 with
variables in it. The third argument will then be a list of instantiations of the first
argument, 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.1
Given the knowledge base
5If your Prolog lacks findall, define it: findall(V,Goal,L) :- bagof(V,Goal^Goal,L).
findall/3
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
bagof/3
Retorna una lista no ordenada de términos en las soluciones de un objetivo dado
bagof( 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
setof/3
Retorna conjuntos ordenados de términos en las soluciones de un objetivo dado
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
setof( 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
integer_bound/3
genera o prueba enteros entre una cota superior y una cota inferior
integer_bound( Cota_Inferior, Numero, Cota_Superior )
+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.
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-PROGRAMA DE
INGENIERÍA DE SISTEMAS
Examples
La siguiente llamada verifica simplemente que "2" es un entero en el rango [1..3]:
?- integer_bound( 1, 2, 3 ). <enter>
yes
La 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=3
Notes