Guía de Ejercicios en Prolog
Lección 3 - Manipulación de la Base de Datos y
Archivos
Carga la siguiente base de datos de países con sus respectivas
capitales.
:- dynamic capital_of/2.
capital_of(suiza, berna).
capital_of(chile, santiago).
capital_of(eeuu, washington).
capital_of(estados_unidos, washington).
capital_of(italia, roma).
capital_of(francia, paris).
capital_of(austria, viena).
capital_of(alemania, berlin).
capital_of(españa, madrid).
capital_of(peru, lima).
capital_of(mexico, cuidad_de_mexico).
|
1.- read/1 permite leer expresiones Prolog desde
el teclado. Intenta lo siguiente: verifica las respuestas que te
entrega Prolog para las siguientes entradas.
hola.
'hola que tal'.
hola que tal.
hola(hermano).
Hola.
f(X) :- g(Y).
|
¿Puedes explicar a qué se deben las respuestas de
Prolog?
2.- Veamos cómo un programa Prolog es capaz de aquirir
nuevas cláusulas en tiempo de ejecución.
?- capital_of(hawaii, X).
|
Como puedes ver, no se pudo unificar la variable X.
Ahora, prueba con
¿Qué ocurre? listing muestra todas las cláusulas
que conforman el programa en memoria. Ahora prueba
Ésto sólo muestra aquellas cláusulas asociadas
al predicado indicado como parámetro.
Se pueden incluir más cláusulas a la base de datos
mediante el predicado assert/1:
?- assert(capital_of(hawaii, honolulu)).
|
Sin embargo, ésto sólo funciona para predicados
que han sido marcados como dínamicos mediante el predicado dynamic/1.
Ojo, pues en Prolog dos predicados con el mismo functor (i.e.
el nombre del predicado) son distintos si tienen aridad (i.e.
nombre de argumentos) distintos. Es algo similar a lo que le
llaman la firma de una función en Java por ejemplo.
En consecuencia, a(X) y a(X,Y) son
distintos predicados (a/1 y a/2 respectivamente,
según la notación Prolog).
El predicado capital_of/2 ha sido declarado previamente
como dinámico. Puedes verificarlo ejecutando listing.
Un predicado que no es dinámico es estático.
Los predicados estáticos no pueden ser alterados en tiempo
de ejecución.
Prolog internamente compila las cláusulas estáticas
para mejorar la eficiencia. Es por esta razón que debe
hacerse la diferencia.
Ahora, si preguntas por
?- capital_of(hawaii, X).
|
debiera resultar la unificación de la variable en forma
exitosa.
3.- Obsevemos que assert agrega la cláusula al final de
la lista de predicados del mismo nombre. Existe tambien asserta/1
y assertz/1, que agregan la cláusula al comienzo y al final
respectivamente.
Agrega dos cláusulas nuevas a la base de datos, y verifica
luego que éstas fueron efectivamente incluídas. ¿Qué ocurre
si agregas una clásula con un predicado nuevo, por ejemplo, assert(hola)?
Verifica consultando por listing(hola).
retract/1 permite eliminar una cláusula de
la base de datos.
?- retract(capital_of(hawaii, honolulu)).
|
Existen más predicados que permiten inspeccionar el estado
de la base de datos, inclusive para construir y ejecutar dinámicamente
predicados en tiempo de ejecución. Para mayor información,
puedes revisar la base de datos.
4.- Ahora veamos algunos predicados de manejo sencillo de archivos. Éstos
son: see/1, seen/1, tell/1 y told/1.
see('mi_archivo') abre el archivo 'mi_archivo' y
lo establece como fuente de los comandos de lectura, tales como read/1.
Para cerrarlo, aplicar seen/0.
Por otro lado, tell('mi_archivo') abre al archivo 'mi_archivo' y
redirige la escritura hacia él, análogo a see.
Para cerrar al archivo, aplicar told/0.
?- tell('mi_archivo'), write('andrea.'), nl, write('javier.'), nl, told.
|
Tras ejecutar la consulta anterior, revisa si existe el archivo 'mi_archivo' y
si su contenido es el esperado.
Ahora, vuelve a leer los datos escritos mediante:
?- see('mi_archivo'), read(X), read(Y).
|
¿Qué habría ocurrido si se hubiese escrito write('andrea') en
vez de write('andrea.')?
Intenta escribir el contenido de la base de datos actualmente
residente en memoria dentro de algún archivo. Verifica que ésto
haya funcionado bien abriendo el archivo y revisando su contenido.
5.- Ahora carga el programa 'learner.pl' y ejecuta start.
Juega un rato con él. Para finalizarlo, ingresa stop.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% File learner.pl %
% Un pequeño programa que modifica su propia base de conocimientos. %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
start :- consult('bdc.pl'),
nl,
write('Escribe los nombres completamente en minúsculas,'), nl,
write('seguidos de un punto.'), nl,
nl,
process_a_query.
process_a_query :- write('País? '),
read(Pais),
answer(Pais).
% Si el usuario ingresa "stop.", entonces grabar la nueva
% base de conocimientos y salir.
answer(stop) :- write('Grabando la base de conocimientos...'), nl,
tell('bdc.pl'),
listing(capital_of),
told,
write('Listo.'), nl.
% Si el país ya está en la base de conocimientos, entonces retornar
% el nombre de su capital.
answer(Pais) :- capital_of(Pais, Ciudad),
write('La capital de '),
write(Pais),
write(' es '),
write(Ciudad), nl,
nl,
process_a_query.
% Si el país no está en la base de conocimientos, entonces pedir
% el nombre de la capital e ingresar este fact a la base.
answer(Pais) :- \+ capital_of(Pais, Ciudad),
write('No conozco la capital de ese país.'), nl,
write('Por favor, dime cual es.'), nl,
write('Capital? '),
read(Ciudad),
write('Gracias.'), nl, nl,
assert(capital_of(Pais, Ciudad)),
process_a_query.
|
Revisa el programa y explica cómo funciona. Modifícalo,
de manera que al ingresar delete, el programa borre
un país de la base de datos, tal como indica el siguiente
diálogo:
...
País? chile.
La capital de chile es santiago
País? delete.
Qué país deseas borrar? chile.
Se borró chile.
País? chile.
No conozco la capital de ese país.
...
|
|