0% encontró este documento útil (0 votos)
61 vistas54 páginas

Introducción a Prolog y Programación Lógica

Cargado por

Ana Holgado
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
61 vistas54 páginas

Introducción a Prolog y Programación Lógica

Cargado por

Ana Holgado
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

Introducción a la Programación Lógica en Prolog

Fernando Soler Toscano

Centro Asociado de Sevilla - UNED

1
La lógica de Prolog

► Tres tipos de cláusulas de Horn:


1. Cláusulas unitarias (hechos): sólo un literal positivo, sin
literales negativos, p0, o bien → p0
2. Cláusulas no unitarias (reglas): un literal positivo y al menos un
literal negativo, p0 ∨ ¬n0 ∨ ¬n1 ∨ . . ., o bien n0 ∧ n1 ∧ . . . → p0
3. Cláusulas negativas (consultas): sólo tienen literales negativos:
¬n0 ∨ ¬n1 ∨ . . ., o bien n0 ∧ n1 ∧ . . . →
► Los dos primeros tipos reciben el nombre de cláusulas definidas

2
La demostración en Prolog

► Prolog emplea resolución para demostrar los objetivos que se


solicitan en las consultas
► Prolog mantiene una pila de objetivos. Cuando se lanza una
consulta, la introduce en la pila. Los objetivos se añaden y se
quitan siempre del mismo extremo de la pila
► Se emplea la operación de unificación. Dos literales unifican si
existe una sustitución que aplicada a sus variables los
transforma en el mismo literal. Una vez que unifican dos
literales, la operación no es reversible (salvo que se vuelva
sobre un punto de elección)
► Cuando Prolog recibe un objetivo para demostrar, lo introduce
en la pila de objetivos.

3
La demostración en Prolog II
► Mientras la pila de objetivos no esté vac´ıa, sea Obj su primer
elemento. Entonces busca la primera cláusula del programa
cuya cabeza unifique con Obj. Quita Obj de la pila de
objetivos e introduce en su lugar el cuerpo de la cláusula. En
tanto que puede haber más de una cláusula cuya cabeza
unifique con Obj, se crean puntos de elección a los que
será posible volver si la alternativa seguida no tiene éxito
(backtracking).
► El procedimiento sigue hasta que la pila de objetivos quede
vac´ıa (éxito de la prueba, responde s i ) o hasta que haya
objetivos que no pueden probarse tras intentar todas las
opciones (fallo en la prueba, responde no)
► El procedimiento puede representarse mediante árboles de
prueba
► Prolog permite seguir la traza de los objetivos que se lanzan
► Cuando pedimos soluciones adicionales, se exploran nuevas
ramas del árbol de prueba 4
Ejemplos
% e s c r i b i o ( ? A u t o r , ? E s c r i t o ) t iene ´exito s i Autor escribi´o E s c r i t o
escribio(gottlob, begriffsschrift). % C1
escribio(bertrand, principia). % C2
escribio(alfred, principia). % C3
escribio(terry, shrdlu). % C4
e s c r i b i o ( b i l l , lunar). % C5
e s c r i b i o ( r o g e r , sam). % C6
% l i b r o ( ? L i b r o ) t iene ´exito s i L i b r o es un l i b r o
libro(begriffsschrift). % C7
libro(principia). % C8
% programa(?Prog) t iene ´exito s i Prog es un programa
programa(lunar). % C9
programa(sam). % C10
programa(shrdlu). % C11
% autor(?Persona) t iene ´exito s i Persona ha e s c r i t o un l i b r o
autor(Persona) : - % C12
libro(Libro),
e s c r i b i o ( Pe r s o na , L i b r o ) .
% autor_de(?Persona, ? L i b r o ) t iene ´exito s i Persona ha e s c r i t o Libro
autor_de(Persona, L i b r o ) : - % C13
libro(Libro), 5
e s c r i b i o ( Pe r s o na , L i b r o ) .
Llamada a a utor(ber tr a nd).

Tiene éxito, se explora una rama que falla, pero la segunda


encuentra la prueba:

6
Llamada a a u t o r ( t e r r y ) .

Fracasan las dos opciones:

7
Llamada a autor de(bertrand, Obra).

Tiene éxito y unifica Obra con principia :

8
Seguimiento de la traza

? - t r a c e , autor(bertrand).
C a l l : ( 9 ) autor(bertrand) ?
C a l l : ( 1 0 ) l i b r o ( _ L 1 80 ) ?
E x i t : (10) l i b r o ( b e g r i f f s s c h r i f t ) ?
C a l l : (10) escribio(bertrand, b e g r i f f s s c h r i f t ) ?
F a i l : (10) escribio(bertrand, b e g r i f f s s c h r i f t ) ?
Redo: ( 1 0 ) l i b r o ( _ L 1 80 ) ?
E x i t : (10) l i b ro ( p ri n c i p i a ) ?
C a l l : (10) escribio(bertrand, p r i n ci p i a ) ?
E x i t : (10) escribio(bertrand, p r i n ci p i a ) ?
E x i t : ( 9 ) autor(bertrand) ?

Yes

9
Advertencias

► El orden de las cláusulas en el programa no cambia su sentido


semántico, pero puede afectar mucho a las pruebas
► Tener en cuenta el renombramiento de variables entre
diferentes cláusulas

Ejercicio: experimentar con el guitracer de SWI-Prolog

10
Definición recursiva de predicados

► Hasta ahora hemos definido los predicados complejos a partir


de otros más simples. En último término, los predicados más
elementales constitu´ıan la propia base de datos
► Para otros predicados, esta técnica no basta, necesitamos
hacer definiciones recursivas, en términos de s´ı mismos.
Ocurre cuando las definiciones implican cadenas de relaciones
de longitud arbitraria

11
Definición recursiva de predicados II

► Ejemplo (árbol familiar de Bertrand Russell):


padreomadre(katherine, b e r t r a n d ) . padreomadre(amberley, bertrand).
padreomadre(katherine, f r a n k ) . padreomadre(amberley, f r a n k ) .
padreomadre(katherine, r a c h e l ) . padreomadre(amberley, r a c h e l ) .

padreomadre(dora, k a t e ) . padreomadre(bertrand, k a t e ) .
padreomadre(dora, j o h n ) . padreomadre(bertrand, j o h n ) .
padreomadre(peter, conrad). padreomadre(bertrand, conrad).

mujer(katherine). hombre(amberley).
mujer(rachel). hombre(frank).
mujer(dora). hombre(bertrand).
mujer(peter). hombre(conrad).
mujer(kate). hombre(john).

► Ejercicio: escribir cláusulas que definan las relaciones de


padre, abuela, t´ıo, primo, etc., a partir de los predicados
primitivos padreomadre/2, mujer/1 y hombre/1.
12
Definición recursiva de predicados III

► Supongamos que queremos definir una relación de


ancestro/2. Intuitivamente, una persona Mayor es ancestro
de una persona Joven si están conectados mediante una
cadena de instancias de padreomadre/2 de longitud
arbitraria. Podr´ıamos intentar:
ancestro(Mayor, J o v e n ) : -
padreomadre(Mayor, Joven).
ancestro(Mayor, J o v e n ) : -
padreomadre(Mayor, Medio),
padreomadre(Medio, Joven).
ancestro(Mayor, J o v e n ) : -
padreomadre(Mayor, Medio),
padreomadre(Medio, Medio2),
padreomadre(Medio2, Joven).
...
13
Definición recursiva de predicados IV

► Necesitar´ıamos infinitas cláusulas. Afortunadamente podemos


definir la relación recursivamente. Son ancestros de Joven:
) Los padres de Joven
) Los ancestros de los padres de Joven
► Entonces:
ancestro(Mayor, J o v e n ) : -
padreomadre(Mayor, Joven).
ancestro(Mayor, J o v e n ) : -
padreomadre(Mayor, Medio),
ancestro(Medio, Joven).
► Seguir la traza de la llamada a ancestro(katherine,
kate).

14
Terminación
► La forma de definir un predicado puede influir en la
terminación de las llamadas que se realizan a dicho predicado.
Por ejemplo, podr´ıamos haber intentado definir ancestro/2
como:
ancestro(Mayor, J o v e n ) : -
ancestro(Mayor, Medio),
ancestro(Medio, Joven).
ancestro(Mayor, J o v e n ) : -
padreomadre(Mayor, Joven).
► La definición es semánticamente equivalente a la primera,
pero ahora, cuando Prolog trata de probar una llamada a
ancestro/2 nunca termina, porque siempre usa la primera
cláusula, construyendo una secuencia infinita de instancias de
ancestro/2.
► Seguir la traza de la llamada a ancestro(katherine,
k a t e ) . con esta definición 15
Terminación II

► Sin embargo, la llamada terminar´ıa simplemente cambiando el


orden de las cláusulas:
ancestro(Mayor, J o v e n ) : -
padreomadre(Mayor, Joven).
ancestro(Mayor, J o v e n ) : -
ancestro(Mayor, Medio),
ancestro(Medio, Joven).
► Ahora s´ı termina una llamada a ancestro/2, pero si pedimos
más soluciones (mediante “;”), volvemos a caer en un bucle
infinito
► Esto ocurre porque una de las cláusulas usa recursividad
izquierda, es decir, el primer literal es una referencia al propio
predicado, cosa que por lo general causa problemas en el
mecanismo deductivo de Prolog.

16
Terminación III

► Al escribir cláusulas recursivas debemos tener en cuenta la


forma en que Prolog las empleará, para evitar estos
problemas. Por lo general, conviene poner primero los casos
básicos de las cláusulas de un mismo predicado, y dejar para
el final las cláusulas que contienen llamadas recursivas,
evitando la recursividad izquierda. Por ello, la mejor definición
de ancestro/2 es la que dimos al principio:
ancestro(Mayor, J o v e n ) : -
padreomadre(Mayor, Joven).
ancestro(Mayor, J o v e n ) : -
padreomadre(Mayor, Medio),
ancestro(Medio, Joven).

17
Términos y unificación
► Hasta ahora, los argumentos de los predicados han sido
constantes o variables
► Sin embargo, Prolog permite términos arbitrarios como
argumentos
► Definición del conjunto de términos:
) Las constantes y las variables son términos
) Si t1, t2, . . . , tn son términos y f es un functor n-ario, entonces
f (t1, t2, . . . , tn ) es un término
) Nada más es un término
► Para ilustrar la notación, el siguiente programa axiomatiza la
suma usando recursividad y la función sucesor:
% suma(A, B , C) se v e r i f i c a cuando A+B=C
suma(0,Y,Y). % C1
s u m a ( s u c ( X ) , Y , s u c ( Z ) ) : - suma(X, Y , Z ) . % C2
► El término elemental (constante) 0 representa el número 0;
s u c ( 0 ) el 1; s u c ( s u c ( 0 ) ) el 2 y as´ı sucesivamente 18
Términos y unificación II
► Cada una de las cláusulas se corresponde con uno de los
axiomas de la suma:
0+ y = y
xr + y = (x + y )r
► Observación: cuando Prolog encuentra un término como
s u c ( 0 ) no lo iguala al término 1 ni ningún otro. La ú nica
relación entre los términos y sus valores es el significado que
nosotros le concedamos
► Algunas llamadas a suma/3:
? - suma(0, s u c ( 0 ) , Suma).
Suma = su c ( 0 )
Yes
? - suma(suc(suc(0)), s u c ( s u c ( 0 ) ) , Suma).
Suma = s u c ( s u c ( s u c ( s u c ( 0 ) ) ) )
Yes
? - suma(suc(0), Sumando, s u c ( s u c ( s u c ( 0 ) ) ) ) .
Sumando = s u c ( s u c ( 0 ) )
Yes 19
Términos y unificación III
► Ejercicio: usar el predicado suma/3 y la misma notación
sucesor para definir un predicado recursivo producto(A,B,C)
que sea verdadero cuando A × B = C. Tener en cuenta que:

0×y = 0
xr × y = (x × y ) + y
► Ahora, la operación de unificación se aplica a términos
compuestos (en Prolog, la relación “=” se da entre dos
términos, o predicados, que unifican):
? - suma(suc(suc(0)), s u c ( s u c ( 0 ) ) , Suma) = suma(suc(X), Y , s u c ( Z ) ) .
Suma = suc(_G184)
X = suc(0 )
Y = suc(suc(0))
Z = _G184
Yes
► G184 es el nombre interno que Prolog asigna a la variable Z
► La sustitución ha transformado los dos términos en:
su ma(suc(suc(0)), s u c ( s u c ( 0 ) ) , s u c ( Z ) ) . 20
Operaciones aritméticas

► Dentro de las constantes permitidas por Prolog están los


números. Operadores de comparación:
) <, menor que: 3<7
) >, mayor que: 7>3
) =<, menor o igual que: 3=<7, 7=<7
) >=, mayor o igual que: 7>=3, 7>=7
► Atención: estos operadores tienen restricciones: + < + (igual
para el resto, siempre debe haber dos expresiones númericas
sin variables a cada lado). En otro caso, Prolog tendr´ıa que
hacer recursión sobre todas las parejas posibles ( X , Y ) de
números tales que X < Y. Esto no está permitido por el
compilador.

21
Operaciones aritméticas II

► Expresiones numéricas:
? - 2*3 < 5.
No
? - 2*3 < 8.
Yes
? - 2*3 =< 6 .
Yes
? - 2*3 = 6.
No

► El último caso ilustra que la identidad = no sirve para la


evaluación numérica de expresiones. Para eso está el predicado
i s ( ? R e s u l t , +Expr), que puede ser usado de forma infija,
donde Expr es una expresión aritmética (debe tenerse en
cuenta la precedencia de los operadores aritméticos),y Result
bien un número o una variable:

22
Operaciones aritméticas III

? - X i s 2*3.
X = 6
Yes
? - 6 i s 2+3.
No
? - 5 i s 8 - 3.
Yes
? - 2*3 i s 6 .
No
? - 2*3 i s X .
ERROR: i s / 2 : Arguments are not s u f f i c i e n t l y inst ant iat ed
? - X i s 3 / (5 +2).
X = 0.428571
Yes
? - Y i s 3^2.
Y = 9
Yes

23
Observación: tipos de igualdad

Tipos de igualdad que usamos en Prolog:


► ?A = ?B. Tiene éxito si A y B unifican.
► +A == +B. Tiene éxito si A y B son términos idénticos (sin
unificar, deben tener las mismas variables).
► ?A i s +B. Tiene éxito si A unifica con la evaluación de la
expresión aritmética B.
► +A =:= +B. Tiene éxito si las dos expresiones aritméticas A y
B se evalúan al mismo nú mero.
Probar cada una de las igualdades viendo que no tienen éxito en
los mismos casos.

24
Listas
► La lista vac´ıa se representa mediante la constante [ ] .
► La secuencia (e, s) con cabeza e y cola s se representa
mediante [e|s]
► Generalizando, la secuencia (e1, (. . . (en, s) . . .)) se representa
mediante [e 1 , . . . , en | s]. Cuando s es la secuencia vac´ıa,
se simplifica [e 1 , . . . , en]
► Ejemplos:
) [Cabeza | Cola], representa una lista con al menos un
elemento Cabeza
) [ a , b | X ] representa una lista cuyos dos primeros elementos
son a y b. La cola puede ser vac´ıa si X = [ ]
) [ a , b ] es la lista con sólo dos elementos a y b
► En tanto que los elementos de una lista pueden ser a su vez
otras listas, podemos definir recursivamente la noción de lista:
lista([]).
lista([_Cabeza | Cola]) : - l i s t a ( C o l a )
25
Listas II

► En el programa anterior hemos usado la variable Cabeza para


indicar que no nos importa cuál sea su valor concreto.
Podemos construir variables de este tipo uniendo “ ” a
cualquier cadena de caracteres
► Prolog dispone incluso de la variable anónima “ ”
► Cada ocurrencia de es independiente de las demás. Por ello,
podemos unificar p ( , ) con p ( a , X ) y aún unificar X con b.
No ocurre lo mismo con las variables como Cabeza, donde
todas las apariciones de la misma variable deben unificar con
el mismo término

26
Manejo de listas

► Al definir predicados que tengan listas entre sus argumentos,


usualmente daremos una definición recursiva a partir de dos
cláusulas:
) Una que se usará cuando la lista esté vac´ıa [ ]
) Otra para listas no vac´ıas de la forma [Cabeza | Cola]
► De esta forma, hacemos recursión sobre la cola de la lista, que
cada vez será más pequeña y as´ı evitamos los problemas de no-
terminación, ya que cuando la lista es vac´ıa sólo es aplicable el
caso base

27
Ejemplo: concetenación de listas

► Definimos el predicado conc(L1, L 2 , L 3 ) de forma que L3


sea la lista resultante de concatenar las listas L1 y L2
► Recursivamente, definimos la operación de concatenación:
) Si L1 es la lista vac´ıa, su concatenación con L2 produce L2,
) En otro caso, sea L1 = [Cabeza | Cola]; entonces la
concatenación de L1 con L2 es una lista que tiene como primer
elemento Cabeza y como resto el resultado de concatenar Cola
con L2
conc([], L2, L2).
conc([Cabeza|Cola], L 2 , [Cabeza|ConcResto]):-
conc(Cola, L 2 , ConcResto).

28
Ejemplo: concetenación de listas II
► Ejemplo:
? - c o n c ( [ a , b ] , [ c , d ] , Conc).
Conc = [ a , b , c , d]
Yes
?- conc([a,b], L2, [a,b,1,2]).
L2 = [ 1 , 2]
Yes
?- conc([a,b], L2, [ a , c , d ] ) .
No
► Prolog dispone del predicado predefinido append/3 que
realiza esta función
► Carácter reversible del predicado conc/3:
? - co nc(L 1, L 2 , [ a , b , c , d ] ) .
L1 = [ ]
L2 = [ a , b , c , d] ;
L1 = [ a ]
L2 = [ b , c , d] ;
L1 = [ a , b]
L2 = [ c , d]
Yes 29
Control mediante corte

► Ejemplo sin corte: nota(+Cuantit, ? C u a l i t )


será verdadero cuando C u a l i t sea la calificación cualitativa
(suspenso, aprobado, notable, sobresaliente) correspondiente a
la nota cuantitativa Cuantit (un número de 0 a 10).
nota(N, suspenso) : - N < 5.
nota(N, aprobado) : - N >=5, N < 7 .
nota(N, notable) : - N >=7, N < 9 .
nota(N, s o b r e s a l i e n te ) : - N >= 9 .
► Ejemplo: calculamos la calificación correspondiente a un 6
? - nota( 6, Nota).
Nota = aprobado ;
No

30
Control mediante corte
► Prolog encuentra que la nota correspondiente es aprobado.
Para demostrarlo, Prolog ha recorrido las dos primeras ramas
del árbol de prueba hasta encontrar una demostración.
Cuando le preguntamos si hay más soluciones, responde que
no. Pero ha tenido que explorar las dos ramas restantes:
? - t r a c e , n o t a ( 6 , Nota).
C a l l : ( 8 ) n o t a ( 6 , _G171) ?
^ C a l l : ( 9 ) 6<5 ?
^ F a i l : ( 9 ) 6<5 ?
Redo: ( 8 ) n o t a ( 6 , _G171) ?
^ C a l l : ( 9 ) 6>=5 ?
^ E x i t : ( 9 ) 6>=5 ?
^ C a l l : ( 9 ) 6<7 ?
^ E x i t : ( 9 ) 6<7 ?
E x i t : ( 8 ) n o t a ( 6 , aprobado) ?
Nota = aprobado ;
Redo: ( 8 ) n o t a ( 6 , _G171) ?
^ C a l l : ( 9 ) 6>=7 ?
^ F a i l : ( 9 ) 6>=7 ?
Redo: ( 8 ) n o t a ( 6 , _G171) ?
^ C a l l : ( 9 ) 6>=9 ?
^ F a i l : ( 9 ) 6>=9 ?
31
No
Control mediante corte
► En ocasiones nos interesará que Prolog no recorra todas las
ramas del árbol de prueba, podando algunas de ellas que
sabemos que no serán prometedoras. En predicados como
nota/2 que sabemos que sólo tiene una solución, una vez
encontrada ésta, no tiene sentido seguir buscando otras.
► El corte ! es un predicado que Prolog siempre evalúa como
verdadero y que tiene el efecto de podar todas las ramas
alternativas en el subárbol de prueba correspondiente al
predicado en cuya definición se ha introducido el corte.
► Ejemplo:
nota2(N, suspenso) : - N < 5, ! .
nota2(N, aprobado) : - N < 7, ! .
nota2(N, notable) : - N < 9, ! .
nota2(_N, s o b r e s a l i e n te ) .

32
Control mediante corte
► Ahora en el árbol de prueba de n ota(6, Nota), cuando se
obtiene Nota = aprobado, se podan las dos ramas restantes:
? - t r a c e , nota2(6, Nota).
C a l l : ( 8 ) nota2(6, _G171) ?
^ C a l l : ( 9 ) 6<5 ?
^ F a i l : ( 9 ) 6<5 ?
Redo: ( 8 ) nota2(6, _G171) ?
^ C a l l : ( 9 ) 6<7 ?
^ E x i t : ( 9 ) 6<7 ?
E x i t : ( 8 ) nota2(6, aprobado) ?
Nota = aprobado ;
No
► Si el corte se usa adecuadamente puede reducir
considerablemente la búsqueda, pero también debemos
conocer sus consecuencias:
? - nota2(6, n o t a b l e ) .
Yes
► Se pierde carácter declarativo. En nota2/2, ahora el segundo
argumento es exclusivamente de salida, debe ser una variable 33
Control mediante corte
Ejercicio: Cuando hacemos una llamada al predicado member(E,
L), Prolog nos devuelve todos los elementos de la lista L que
unifican con E:

? - member(X, [ a , b , a ] ) .
X = a ;
X = b ;
X = a ;
No

se pide definir un predicado memberc(E,L) que realice un corte en


el árbol de prueba de modo que cuando encuentre el primer
elemento de L que unifique con E ya no busque otros, de modo que
responda No si se piden más soluciones:

? - memberc(X, [ a , b , a ] ) .
X = a ;
No
34
Negación por fallo

► Hasta ahora no hemos tenido forma de indicar negaciones.


Prolog maneja la hip´otesis del mundo cerrado: todo lo que no
puede probarse se considera falso. Para ello tenemos el
predicado not/1. Se define a partir del corte:
not(C) : - C , ! , f a i l .
not(_).
► Es decir, si puede demostrarse el objetivo C (al ser una
variable podrá ser cualquier cosa), entonces no se busca
ninguna prueba alternativa para not(C) y falla (el predicado
f a i l es siempre falso, as´ı como true es siempre verdadero).
En otro caso (cuando no se ha podido probar C), se considera
probado not(C).
► El predicado not/1 está predefinido en SWI-Prolog, y también
puede escribirse \+

35
Negación por fallo
► Ejemplo: podemos definir un predicado member d i f ( E , L 1,
L 2 ) que sea verdadero cuando E sea un elemento de la lista
L1 pero no de L2 (es decir, pertenece a la diferencia L1-L2):
member_dif(E, L 1 , L 2 ) : -
member(E, L 1 ) ,
\+ member(E, L 2 ) .
► Obsérvese cómo se han ordenado los literales. De esta forma,
la negación actúa sobre valores concretos. Ver qué pasa si se
ordenan de la otra forma.
► Veamos un ejemplo:
? - member_dif(E, [ a , b , c , d , e , f ] , [ a , c , e ] ) .
E = b ;
E = d ;
E = f ;
No
36
Ejemplo
Considérese la siguiente base de conocimientos:
mayor_edad(juan).
mayor_edad(ana).
mayor_edad(pedro).
mayor_edad(maria).
trabaja(ana).
trabaja(pedro).

Definimos un predicado busca t r a b a j o ( X ) que es verdadero


cuando X es mayor de edad y no trabaja:

busca_trabajo(X): -
mayor_edad(X),
\+ t r a b a j a ( X ) .

Probar añadir y quitar hechos de la base de conocimiento.


Observar carácter no monótono de la negación por fallo.
37
Condicional

► En Prolog disponemos del condicional -> que podemos usar


de dos formas posibles:
) I f -> Then; Else. Prolog evalúa primero la condición I f . Si
se cumple, evalúa Then. En otro caso, ignora Then y evalú a
Else. El condicional es verdadero cuando:
) Es verdadero I f y Then
) No es verdadero I f pero s´ı Else
) I f -> Then. Equivale a I f -> Then; f a i l . Es decir, si I f
es verdadero se evalúa Then que debe ser verdadero también.
En otro caso, el condicional es falso.

38
Condicional (ejemplos)

► Definición de max(+X,+Y,?Z) que tiene éxito si Z es el mayor


de los números X y Y:
max(X,Y,Z) : -
( X =< Y
-> Z = Y
; Z = X
).
► Pueden anidarse varios condicionales. Ejemplo:
nota(Numero, C a l i f ) : -
Numero < 5 -> C a l i f = suspenso;
Numero < 7 -> C a l i f = aprobado;
Numero < 9 -> C a l i f = notable;
C a l i f = sob re salie n te .

39
Ejercicio

Definir usando el condicional un predicado ndias(+NMes,


-NDias) al que se le dé el número NMes que representa un mes
(entre 1 y 12) y devuelva en NDias el número de d´ıas que tiene el
mes (suponer que febrero siempre tiene 28 d´ıas).

? - ndias(12,N).
N = 31
Yes
? - n d i a s ( 6 ,N) .
N = 30
Yes

40
Solución

ndias(NMes, NDias): -
member(NMes, [ 1 , 3 , 5 , 7 , 8 , 1 0 , 1 2 ] ) -> NDias = 31;
member(NMes, [ 4 , 6 , 9 , 1 1 ] ) -> NDias = 30;
NMes = 2 -> NDias = 28.

Uso:

? - n d ias(3,NDias).
NDias = 31.
?- ndias(6,30).
Yes
?- ndias(6,31).
No
? - ndias(13,N).
No
41
Predicados metalógicos

► El predicado map list(Pre d , L 1 , L 2 ) se verifica si se prueba


el predicado diádico Pred sobre los sucesivos pares de
elementos de L1 y L2:
? - maplist(member,[a,b,c],
[[p,a,p], [p,b,p], [p,c,p]]).
Yes
► El predicado f i n d a l l ( T e r m , O b j e t, L i s t ) se verifica si L
es la lista de instancias de Term que verifican Objet:
? - f i n d a l l ( X , (mayor_edad(X),
\+ t r a b a j a ( X ) ) , L i s t a ) .
L i s t a = [ j u a n , maria]
Yes

42
Predicados metalógicos

► El predicado setof(Term, O b j e t, L i s t ) se comporta igual


que f i n d a l l / 3 salvo que devuelve la lista L i s t ordenada y
sin repeticiones. Además, si no existe ninguna instancia de
Term que verifique Objet, falla (a diferencia de f i n d a l l / 3
que devuelve la lista vac´ıa.
► El predicado T = . . L se verifica si dado el término T, la lista
L tiene como primer elemento el functor de T y como resto los
argumentos de T:
?- lee(ana, l i b r o ) = . . L .
L = [ l e e , ana, l i b r o ]
Yes
? - lee(madre(ana), l i b r o ) = . . L .
L = [ l e e , madre(ana), l i b r o ]
Yes

43
Ayuda de SWI-Prolog
Tecleando ? - h e l p . accedemos a la ayuda de SWI-Prolog.
Obtenemos información del uso de todos los predicados
predefinidos.

44
Modificación dinámica de la base de conocimientos

► En ciertas ocasiones nos interesa que una consulta pueda


modificar la base de conocimiento en tiempo de ejecución
► Para ello, Prolog dispone de la opción de declarar ciertos
predicados como dinámicos
► Disponemos de predicados que nos permiten añadir nuevas
cláusulas de los predicados dinámicos, as´ı como borrar algunas
o todas las existentes.
► El predicado dynamic/1 permite declarar una lista de
predicados dinámicos, dando la aridad de cada uno de ellos.

45
Ejemplo

:-dynamic([paj aro/1, ping¨uino/1]).


:-set_prolog_flag(unknown, f a i l ) .

v u e l a ( X ) : - p a j a r o ( X ) , \+ ping¨uino(X).

► Hemos declarado como dinámicos los predicados pajaro/1 y


ping¨uino/1.
► La instrucción s e t prolog flag(unknown, f a i l ) hace que
cuando aparezca una llamada a un predicado del que no hay
definidas instancias, se produzca un fallo, en vez de un
mensaje de error (opción por defecto)
► Definimos el predicado vuela/1, que abarca todos los
individuos que son pájaros pero no pingüinos
► Observar el uso de la negación por fallo
46
Predicados assert y retract

► El predicado asse rt/1 añade a la base de conocimiento una


nueva instancia de un predicado dinámico, que recibe como
argumento.
► El predicado r e t r a c t / 1 elimina de la base de conocimiento la
primera cláusula de un predicado dinámico que unifique con el
argumento que recibe.
► El predicado r e t r a c t a l l / 1 elimina de la base de
conocimiento todas las instancias de un predicado dinámico
que unifiquen con el argumento que recibe.
► Estos predicados pueden usarse tanto en las consultas como
en el cuerpo de las cláusulas de la base de conocimiento.

47
Ejemplo (continuación)

Compilamos la base de conocimiento anterior:


? - a s s e r t ( p a j ar o (p i o l ´ ı n ) ). ?- retract(pajaro(_)).
true. true
? - vuela(piol ´ın). ?- findall(X,pajaro(X),Conj).
true. Conj = [ p ] .
? - assert(ping¨uino(piol´ın)). ?- retract(pajaro(p)).
true. true.
? - vuela(piol ´ın). ?- findall(X,pajaro(X),Conj).
fail. Conj = [ ] .
?- assert(pajaro(p)). ? - findall(X,ping ¨ uino (X),Co nj ).
true. Conj = [ p i o l ´ ı n , p ] .
? - assert(ping¨uino(p)). ? - r et r act all(ping ¨ uino(_)).
true. true.
?- findall(X,pajaro(X),Conj). ? - findall(X,ping ¨ uino (X),Co nj).
Conj = [ p i o l ´ ı n , p ] . Conj = [ ] .

48
Comentarios
► El ejemplo anterior muestra cómo los cambios en la base de
conocimiento pueden afectar a las inferencias que se realizan.
► Cuando sólo sab´ıamos que piol´ın es un pájaro, pudimos
inferir vuela(piol´ın), pero al incorporar nuevo
conocimiento, tras saber que es un pingüino, ya no podemos
inferir que vuela.
► Cuando un sistema formal puede invalidar ciertas inferencias
tras añadir nuevo conocimiento, se dice que no es monótono
► El razonamiento de sentido común no es monótono.
► El carácter no monótono de Prolog viene dado por el uso de la
negación por fallo y la posibilidad de modificar la base de
conocimiento en tiempo de ejecución.
► Recordemos que la negación por fallo considera que algo es
falso cuando no hay constancia de que sea verdadero
(hipótesis del mundo cerrado)
► Es una negación diferente de la que se usa en lógica clásica 49
Interacción con el usuario

► Hasta ahora, cuando realizamos una consulta, damos a Prolog


todos los datos que necesita para tratar de demostrarla.
Prolog continúa sin nuestra ayuda hasta dar una respuesta
afirmativa o negativa.
► En ocasiones, puede ser interesante pedir datos al usuario, y
en función de dichos datos, tomar un camino u otro en las
pruebas.
► Igualmente, es interesante dar información en pantalla más
allá de la respuesta afirmativa o negativa de las pruebas.
► El predicado read/1 lee un término introducido por el
terminal.
► Los predicados format/1 y format/2 muestran información
en pantalla.

50
Uso de format/1 y format/2
Uso de format(Cadena):
► El argumento Cadena es una cadena de caracteres encerrada
entre comillas simples.
► Cuando Prolog lo evalúa muestra la cadena en pantalla.
► El carácter de control ~n imprime una nueva l´ınea.

Uso de format(Cadena, L i s t a ) :
► El argumento Cadena es una cadena de caracteres y L i s t a
una lista de términos.
► Además de ~n, aparecen en Cadena ocurrencias de ~w (tantas
como elementos tenga Lista).
► Cuando Prolog lo evalúa, imprime en pantalla Cadena,
sustituyendo cada ocurrencia de ~w por el elemento de L i s t a
que ocupa su mismo lugar.
51
Uso de read/1
Uso de read(Term):
► Cuando Prolog lo evalúa muestra en pantalla | :
(se puede cambiar si antes se usó format para producir una
salida distinta)
► Entonces Prolog se para esperando una entrada del usuario.
► El usuario introduce un término seguido de un punto y nueva
l´ınea.
► Finalmente Prolog unifica Term con el término introducido
por el usuario.
► No hay ninguna restricción en cuanto al término que
introduce el usuario, puede ser un átomo, término complejo,
lista, número, etc.
► Para más detalles y opciones, consultar la ayuda de
SWI-Prolog.
52
Ejemplo
calcula : -
format(’Introduzca un n´umero: ’ ) ,
read(A),
format(’Introduzca otro n´umero: ’ ) ,
read(B),
format(’Operaciones:’),
format(’~n - Suma (s)’),
format(’~n - Resta (r)’),
format(’~n - Producto ( p ) ’ ) ,
format(’~n - D i v i s i o n ( d ) ’ ) ,
f o r m a t ( ’ ~ n E l j a una de e l l a s ( s , r , p , d ) : ’ ) ,
read(O),
operador(O,Op),
operar(Op,A,B,Res),
format(’Resultado: ~w~w~w = ~ w ’ , [ A , Op, B , R e s ] ) .

o p e r a d o r (s , + ) . o p e r a d o r ( r , - ). operador(p,*). operador(d,/).

operar(Op, A, B , R e s ) : - Fml = . . [ O p , A , B ] , Res i s Fml.


53
Ejemplo (uso)

?- calcula.
Introduzca un numero: 5 .
Introduzca otro numero: 4 .
Operaciones:
- Suma (s)
- Resta (r)
- Producto ( p )
- Division (d)
E l j a una de e l l a s ( s , r , p , d ) : d .
Resultado: 5/4 = 1.25
true.

54

También podría gustarte