Está en la página 1de 21

Curso de Programación Usando

el Lenguaje de Programación Prolog

M. C. Justino Ramiréz Ortegón


INTRODUCCIÓN.
CAPÍTULO 1. COMO CORRER PROLOG.
1.1 Comienzo.
1.2 Lectura de Archivos con Programas.
1.3 Ingreso de Cláusulas a la Terminal.
1.4 Directivas: Preguntas y Comandos.
1.5 Errores de Sintaxis.
1.6 Predicados no definidos.
1.7 Ejecución de Programas e Interrupción de éstos.
1.8 Salida del Intérprete.
1.9 Ejecuciones Anidadas - Break y Abort.
1.10 Guardando y Recuperando Estados de Programas.
1.11 Inicialización.
1.12 Entrandas a Prolog.
CAPÍTULO 2. DEPURACIÓN.
2.1 El Modelo de Flujo del Procedimiento Box Control.
2.2 Predicados Básicos de Depuracion .
2.3 Rastreo.
2.4 Spy-Points.
2.5 Formato de los Mensajes de Depuración.
2.6 Opciones Disponibles Durante la Depuración.
2.7 Consultar Durante la Depuración.
CAPÍTULO 3. COMPILACIÓN.
3.1 Llamando al Compilador
3.2 Declaraciones Públicas.
3.3 Mezclando Código Compilado y Código Interpretado.
3.4 Declaraciones de Modo.
3.5 Indexación.
3.6 Optimización de la Cola de Recursión.
3.7 Limitaciones Practicas.
INTRODUCCIÓN.
Prolog es un lenguaje de programación simple pero poderoso desarrollado en la
Universidad de Marsella como una herramienta práctica para programación lógica. Desde
el punto de vista del usario, la ventaja principal es la facilidad para programar, ya que se
pueden escribir rapidamente y con pocos errores, programas claramente leíbles.
Para una introducción al Prolog, se recomienda que se consulte el libro de Closkin y
Mellish (81), sin embargo, para beneficio de aquellos que no tiene acceso al libro y para
aquellos que tienen conocimientos anteriores de lógica, se encuentra un sumario del
lenguaje en el apéndice I de esta obra.
Este manual describe el Sistema Prolog que fue desarrollado en el Departamento de
Inteligencia Artificial de la Universidad de Edimburgo expresamente para el DECsystem-
10. Este sistema se compone de un intérprete y un compilador, ambos escritos también en
Prolog. A nivel del usuario, el compilador se puede considerar como un procedimiento
integrado en el sistema que puede ser llamado por el intérprete.
Ya compilado, un procedimiento se puede correr a una velocidad de 10 a 20 veces más
rápida, así como su almacenamiento también se ve reducido. Sin embargo, se recomienda
que los usuarios nuevos ganen experiencia con el intérprete antes de intenten usar el
compilador. El interprete facilita el desarrollo y la prueba de programas así como también
provee facilidades muy poderosas para la depuración del código.
Ciertos aspectos del Prolog no se han previsto en la instalación, por ejemplo el tipo de
monitor en el que se va a usar, aspecto que lleva muchos de los procedimientos con los que
el sistema cuenta. Este manual describe la instalación de la versión de Edimburgo bajo
TOPS-10, versión 7.01, los usuarios de otro tipo de instalación se pueden referir al apéndice
III.
Este manual se basa en la obra "User's Guide to DECsystem-10 Prolog" de L.M. Pereira,
F.C.N. Pereira y D.H.D. Warren. Parte del capítulo 2 se tomo del libro de Byrd, (80).
Comentarios muy utiles que se presentan en este manual fueron reslizados por Lawrence
Byrd, Luis Jenkins, Richard O'Keefe, Fernando Pereira, Robert Rae y Leon Sterling.
El sistema Prolog es mantenido por el Departmento de Inteligencia Artificial y el
Engineering Board Computing Committee del Science and Engineering Research Council.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice
CAPÍTULO 1. COMO CORRER PROLOG.
El Prolog para el DECsystem-10 ofrece al usuario un ambiente de programación con
herramientas para construir programas, depurarlos siguiendo su ejecución a cada paso y
modificar partes de los programas sin tener que volver a comenzar todo el proceso desde el
último error.
El texto en un programa en Prolog se crea en un archivo o en un número de archivos
usando cualquier editor de texto estándar. El intérprete de Prolog puede ser instruido para
que lea los programas contenidos en estos archivos. A esta operación se le llama consultar el
archivo.

http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

1.1 Comienzo
Para correr el intérprete de Prolog, se deberá teclear el siguiente comando:
.r prolog
El intérprete responde con un mensaje de identificación y el indicador "| ?- " se presentará
cuando el sistema esté listo para aceptar cualquier entrada, así, la pantalla se verá como
sigue:
Edinburgh DEC-10 Prolog version 3.47
University of Edinburgh, September 1982
| ?-
En este momento el intérprete estará ya esperando que el usuario ingrese cualquier
comando por ejemplo: una pregunta o una orden (ver sección 1.4). No se pueden introducir
cláusulas inmediatamente (ver sección 1.3). Este estado se llama nivel alto del intérprete.
Mientras que se teclea un comando, el indicador permanecerá de la siguiente manera:
"| ".
El indicador "?-" aparecerá solamente en la primera línea.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

1.2 Lectura de archivos con programas


Un programa esta compuesto por una secuencia de cláusulas que se pueden intercalar con
directivas para el intérprete. Las cláusulas de un procedimiento no necesariamente tienen
que ser consecutivas, pero si es necesario recordar que el orden relativo es muy importante.
Para Ingresar un programa desde un archivo, sólo se tiene que teclear el nombre del
archivo dentro de corchetes y seguidos de un ENTER:
| ?- [archivo] ENTER
Esta orden le dice al intérprete que tiene que leer (consultar) el programa. La
especificación del archivo tiene que ser un átomo de Prolog, también puede contener
especificación de dispositivos y/o una extensión, pero no se debe incluir la ruta de
ubicación. Notese que es necesario que todas estas especificaciones se coloquen dentro de
comillas, por ejemplo:
| ?- ['dska:myfile.pl'].
Después de haber tecleado esto el archivo será leído,
Así las cláusulas que se han guardado en un archivo están listas para ser leídas e
interpretadas, mientras que las directivas son ejecutadas al momento de ser leídas. Cuando
se encuentra el fin del archivo, el intérprete pone en pantalla el tiempo que se ha gastado en
la lectura y el número de palabras ocupadas por el programa. Cuando este mensaje se
despliegue quiere decir que el comando se ha ejecutado con éxito.
También se pueden combinar varios archivos de la siguiente manera:
| ?- [miprograma,archivos_extras,archivos_de_tests].
En este caso los tres archivos serán leídos.
Si un nombre de archivo se antecede del signo "menos" (-), por ejemplo:
| ?- [-tests,-fixes].
Entonces este archivo o estos archivos serán releídos. La diferencia entre la lectura simple y
la releída es que cuando un archivo es leído entonces todas las cláusulas en el archivo se
añaden a la base de datos interna de Prolog, mientras que si se lee el archivo dos veces,
entonces se tendrá una copia doble de todas las cláusulas.
Sin embargo, si un archivo es releído entonces las cláusulas de todos los procedimientos en
el archivo reemplazarán a cualquier cláusula existente anteriormente. La reconsulta es útil
para indicarle a Prolog las correcciones que se realizan a los programas.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

1.3 Ingreso de las cláusulas a la terminal


Las cláusulas se puede ingresar directamente en la terminal pero esto es recomendado
solamente cuando éstas no se necesitan permanentemente y cuando son pocas. Para
ingresar cláusulas desde la terminal, se debe dar el comando especial: give the special
command:
| ?- [user].
|
y el indicador "| " mostrara que el intérprete está ahora en el estado de espera de cláusulas
o directivas. Para ingresar al nivel más alto del intérprete se deberá teclear Contro + Z
(^Z). Este es el equivalente al fin de archivo de archivo temporal virtual llamado ‘user’
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

1.4 Directivas: Preguntas y comandos


Las directivas pueden ser preguntas y/o comandos. Ambas pueden ser formas de dirigir al
sistema para alcanzar alguna o algunas metas. En el siguiente ejemplo, la función de
pertenencia a una lista se defina como sigue:
member(X,[X|_]).
member(X,[_|L]) :- member(X,L).
(Notese que las variables sin valor asignado se representan como "_".)
La sintáxis completa para una pregunta es "?-" seguida por una secuencia de metas, por
ejemplo:
?- member(b,[a,b,c]).
Al nivel más alto del intérprete (en el que el indicador es como este: "| ?- "), una pregunta
se puede teclear abreviando el "?-" que de hecho ya está incluído en el indicador. Así, en el
nivel más alto, una pregunta se vería de la siguiente manera:
| ?- member(b,[a,b,c]).
Recuerde que los términos en Prolog deben terminar con el punto ".", por lo que el Prolog
no ejecutará nada hasta que Usted haya tecleado este punto y un ENTER al final de la
pregunta.
Si la meta que se ha especificado en la pregunta puede ser satisfecha, y si no hay variables a
considerar como en este ejemplo, entonces el sistema responde:
yes
Y la ejecución de la pregunta ha terminado.
Si en la pregunta se incluyen variables, entonces el valor final de cada variable es
desplegado (excepto para las variables anónimas). Así la pregunta:
| ?- member(X,[a,b,c]).
Podría ser respondida como:
X=a
En este momento el intérprete estará esperando que el usuario introduzca un ENTER o un
punto "." Seguido de un ENTER. Si se teclea solamente ENTER, termina la pregunta y el
sistema responde "yes". Sin embargo, si se teclea ".", el sistema realiza un backtracking y
busca soluciones alternativas. Si no hay soluciones alternativas entonces el sistema
responde:
no
La salida para algunas preguntas como la que se muestra abajo, donde un número precede
a un "_" significa un nombre generado por el sistema para una variable, por ejemplo:
| ?- member(X,[tom,dick,harry]).
X = tom ;
X = dick ;
X = harry ;
no
| ?- member(X,[a,b,f(Y,c)]), member(X,[f(b,Z),d]).
X = f(b,c),
Y = b,
Z=c
yes
| ?- member(X,[f(_),g]).
X = f(_52)
yes
| ?-
En el caso de los comandos, son similares a las preguntas excepto porque:
1. Las variables asociadas con un valor no se muestran cuando la ejecución del
comando tiene éxito.
2. No existe la posibilidad de hacer backtracking para encontrar otras alternativas.
Los comandos inician con el símbolo ":-" . A nivel alto del intérprete simplemente basta
con iniciar con el indicador "| ?- ". Cualquier salida pretendida debe ser programada
explícitamente, por ejemplo, en el comando:
:- member(3,[1,2,3]), write(ok).
Dirije al sistema para que verifique si el número 3 pertenece a la lista [1,2,3], y a que
redirija la salida hacia la variable "ok" si así es. La ejecución de un comando termina
cuando todas las metas en el comando se han ejecutado de manera exitosa. No se muestran
soluciones alternativas. Si no se encuentra solución entonces el sistema indica:
?
como una advertencia.
El uso principal de los comandos (en oposición al uso de las preguntas) es permitir a los
archivos el contener las directivas que llaman a varios procedimientos, para los cuales el
usuario no requiere salida impresa. En estos casos solo se requiere llamar a los
procedimientos por su efecto, por ejemplo, si no quiere tener interacción con el intérprete
durante la lectura de un archivo. Un ejemplo muy útil es el uso de una directiva que
consulte una lista completa de archivos.
:- [ bits, bobs, main, tests, data, junk ].
Si un comando como este se encuentra contenido en el archivo 'myprog' entonces, teclear lo
siguiente sería la forma más rápida para cargar el programa entero:
| ?- [myprog].
Cuando se interactúa al nivel más alto del intérprete de Prolog, la distinción entre
comandos y preguntas es normalmente muy importante. A este nivel se teclean las
preguntas en forma normal. Solo si se lee de un archivo, entonces para realizar varias
metas se deben usar comandos, por ejemplo; una directiva en un archivo debe ser
precedida por un ":-", de otra manera serían tratados como cláusulas.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

1.5 Errores de sintáxis


Los errores de sintaxis se detectan durante la lectura. Cada cláusula o directiva, o en
general cualquier término leido de un archivo o de la terminal, que provoca una falla, es
desplegado en la terminal tan pronto como es leído por el sistema. Una marca indica el
punto en la cadena de símbolos en donde al parser ha fallando en su análisis, por ejemplo:
member(X,X:L).
Implica que el parser muestre:
*** syntax error ***
member(X,X
*** here *** : L).
Si el operador "." No ha sido declarado como operado infijo.
Notese que no se muestran comentarios que especifiquen el tipo de error. Si usted tiene
duda acerca de qué cláusula contiene el error, puede usar el predicado:
listing/1
Para enlistar todas las cláusulas que han sido eficientemente leídas, por ejemplo:
| ?- listing(member).
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice
1.6 Predicados no definidos.
El sistema puede ocasionalmente también darse cuenta de que se han llamado a predicados
que no tienen cláusulas, el estado de esta facilidad de identificación puede ser:
- 'trace', que causa que este tipo de errores sean desplegados en la terminal y que el proceso
de depuración muestre la última vez que ha ocurrido.
O,
- 'fail', que causa que estos predicados fallen (este es el estado por default)
El predicado evaluable:
unknown(OldState,NewState)
unifica a OldState con el estado actual y coloca a State como Newstate. Este falla si los
argumentos no son los apropiados. La depuración de predicados evaluables imprime el
valor de este estado a lo largo de otras informaciones. Es importante notar que se lleva casi
un 70% más de tiempo correr al intérprete en esta modalidad. Se espera que esta facilidad
se pueda mejorar en el futuro.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

1.7 Ejecución de programas e interrupción de éstos.


La ejecución de un programa se incia cuando se le da al intérprete una directiva en la cual
se continenen llamadas a uno de los procedimientos del programa.
Sólo cuando la ejecución de una directiva se ha realizado por completo es cuando el
intérprete va por otra directiva. Sin embargo, uno puede interrumpir la ejecución normal
de ésta al presionar ^C mientras el sistema está corriendo. Esta interrupción tiene el efecto
de suspender la ejecución y se despliega el siguiente mensaje:
function (H for help):
En este momento el intérprete acepta comando de una sola letra, que correspondan con
ciertas acciones. Para ejecutar una acción simplemente se deberá teclear el carácter
correpondiente (en minúsculas) seguido de un ENTER. Los posibles comandos son:
a aborta el comando actual tan pronto como sea posible
b detiene la ejecución (ver apartado 1.9)
c continuar la ejecución
e Salir de prolog y cerrar todos los archivos
g manejar posibilidad de recobrar aspectos ya borrados con anterioridad
h Lista todos los comandos disponibles
m Sale a nivel Monitorl (puede teclear Monitor o CONTINUE)
n desactiva el comando trace
t activa el comando trace
Notese que no es posible romper la ejecución directamente desde el código compilado, cada
una de las opciones "a", "b" y "t" piden que el intérprete realice una acción, por lo que la
acción se seguirá realizando hasta que el código compilado devuelva en mando al
intérprete.
Note también que la opción ("a") no saca al usuario cuando esta en modo [user] es decir
insertando cláusulas desde la terminal. Tiene que teclear ^Z para parar este proceso o
teclear ("e") para poder salir de Prolog.
Si se trata de abortar un programa con ^C y accidentalmente se llegara al nivel Monitor,
(quizá porque se apretó ^C demasiadas veces), deberá teclear CONTINUE para regresar a
la interrupción ^C.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

1.8 Salida del intérprete


Para salir del intérprete y regresar al nivel monitor, deberá teclear ^Z a nivel alto del
intérprete, o llamar al procedimiento "halt" (pre-cargado por default), o usar el comando
"e" (exit) seguido de una interrupción ^C. ^Z es diferentes de los otros dos métodos de
salida, ya que imprime algunas estadísticas. Es posible regresar usando el comando del
Monitor CONTINUE después de ^Z, si se arrepiente de haber querido salir.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

1.9 Ejecuciones anidadas, Break y Abort.


El sistema prolog integra una manera de suspender la ejecución de un programa e
introducir nuevas directivas o cambiar metas a nivel alto del intérprete. Esto se logra si se
llama a un predicado evaluable Break o tecleando "b" despues de una interrupción con ^C
( ver sección 1.7).
Esto causa que el intérprete suspenda la ejecución inmediatamente, a lo que el interprete
contestará
[ Break (level 1) ]
Que quiere decir que se ha parado desde el nivel Break y que se pueden introducir
preguntas de la misma manera en que se había hecho desde el nivel alto del intérprete.
El intérprete indica el nivel Break en el que el sistema se encuentra (por ejemplo, en Breaks
anidados), imprimiendo el nivel de Break después de un yes o un no final a las preguntas.
Por ejemplo, a nivel Break 2, se podría ver la respuesta así: uld look like:
| ?- true.
[2] yes | ?-
Un ^Z cierra la interrupción que se había realizado y se reaundan las tareas. Una ejecución
suspendida se puede abortar usando la directiva:
| ?- abort.
Dentro de un break.
En este caso no se necesitaa un ^Z para cerrar el break; Todos los niveles break se
descartarán y se llega automáticamente al nivel más alto del intérprete.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

1.10 Guardado y restauración de estados de programas


Una vez que el programa ha sido leído, el intérprete tendrá disponible toda la información
que sea necesaria para su ejecución, esta información se llama estado de programa.
El estado de un programa se puede grabar en disco para ejecuciones posteriores. Para
guardar un programa en un archivo, realice la siguiente directiva:
| ?- save(file).
Este predicado se puede llamar en cualquier momento, por ejemplo, puede ser muy útil a
fin de guardar los estados de un programa inmediatos.
Cuando el programa ha sido guardado en un archivo, la siguiente directiva recuperaría el
estado de un programa:
| ?- restore(file).
Después de esta ejecución el programa entonces podrá ser regresado exactamente al mismo
punto en que se dejó al momento de salvarlo la ´´ultima vez.
| ?- save(myprog), write('programa restaurado').
Así, al ejecutarse esta orden con el mensaje propio del usuario, se obtendrá el mensaje
"programa restaurado", por ejemplo.
Notese que cuando una versión de Prolog nueva se instala, todos los programas grabados se
vuelven obsoletos.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

1.11 Inicialización
Cuando prolog inicia busca un archivo llamado 'prolog.bin' en la ruta default del usuario.
Si se encuentra este archivo entonces se asume que el estado de un programa se ha
restaurado. El efecto es el mismo que si se hubiera tecleado:
| ?- restore('prolog.bin').
Si no se encuentra este archivo, entonces se busca en forma similar, el archivo 'prolog.ini'.
Si se encuentra este archivo, sería lo mismo que haber tecleado:
| ?- ['prolog.ini'].
La idea de este archivo es que el usuario pueda tener aquí los procedimientos y directivas
que se usan usualmente de manera que no se tengan que teclear cada vez que se necesiten.
El archivo 'prolog.bin' parece ser que es útil cuando se usa con el plsys(run(_,_)) que
permite correr otros programas desde dentro de Prolog. Esta facilidad permite también
regresar al mismo punto si se corrió prolog desde otros programas. En este caso, el
predicado evaluable save/2 debe ser usado paara salvar el estado del programa dentro de
'prolog.bin'.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

1.12 Entrada a prolog


Cuando se entra a prolog directamente en una interacción con la terminal, se escribe
autoimaticamente el archivo 'prolog.log' en modo append. Esto es, si ya existe el archivo, en
el directorio del usuario, entonces la nueva información se añade, si no es así, y el archivo
no existe, entonces el archivo se crea.
mailto:lopezcua@proton.ucting.udg.mxmailto:lopezcua@proton.ucting.udg.mx
Sugerencias o comentarios: mailto:lopezcua@proton.ucting.udg.mx
CAPÍTULO 2 DEPURACIÓN
Este capítulo describe las facilidades de depuración que están disponibles en el intérprete
de Prolog, el propósito de estas facilidades es proveer información concerniente al control
del flujo del programa, las principales facilidades del paquete de depuración son las
siguientes:
- El Procedure_Box, modelo de ejecución de prolog que permite visualizar con fines de
control el flujo del programa, especialmente durante un backtracking. El control de
flujo se considera un nivel de procedimiento más que un procedimiento a nivel de
cláusulas individuales.
- La habilidad para rastrear el programa o un grupo selectivo de puntos de este. Puntos
espías que pueden ser procedimientos básicos o princiapales, en los que el programa
deberá tener para que el usuario pueda interactuar con el sistema.
- La posibilidad de contar con opciones de control y de iformación, disponibles durante
la depuración.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

2.1 El modelo de flujo del procedimiento Box Control


Durante la depuración de un programa se imprimen una secuencia de metas defectuosas a
fin de mostrar el estado que el programa ha alcanzado durante esta ejecución. Sin
embargo, para poder entender qué es lo que ocurre, es necesrio entender primero cuándo y
por que el interprete imprime las metas. Como en otros lenguajes de programación, existen
puntos principales de interés como los procedimientos de entrada y regreso, pero en Prolog,
existe el backtracking que tiene una complejidad adicional. Una de las principales
confusiones para los novatos es que los programadores tiene que enfrentar la cuestión de
qué es lo que está ocurriendo en el momento en que una meta falla y el sistema inicia
repentinamente el backtracking. El modelo Box de Prolog permite que el flujo del
programa posibilite identificar cualquier punto en la ejecución en términos de localización
en el texto del programa. Este modelo provee las bases para la depuración de un programa.
Examinando a fondo un procedimiento se tiene:
*--------------------------------------* Call | | Exit ---------> + descendant(X,Y) :- offspring(X,Y).
+ ---------> | | | descendant(X,Z) :- | <--------- + offspring(X,Y), descendant(Y,Z). + <---------
Fail | | Redo *--------------------------------------*
La primer cláusula establece que Y es descendiente de X si Y es resulatdo de X, y la
segunda cláusula establece que Z es descendiente de X si Y lo es de X y si Z es descendiente
de Y. En el diagrama, una caja se ha dibujada al rededor de todo el procedimiento y se han
estipulado flechas para establecer el flujo de control con entradas y salidas de esta caja.
Existen cuatro flechas por examinar durante el flujo:
 Call que representa la llamada inicial del procedimiento. Cuando una meta es de la
forma descendant(X,Y) se requiere que el centro pase a través de la caja para ver un
componente que haga matching y que de satisfacción a alguna de las submetas en el
cuerpo de la cláusula. Este procedimiento es independiente del matching posible que
se de, por ejemplo, en la primera etapa se llama y el matching tiene lugar. Podemos
imaginar textualmente el movimiento del código cuando se llega a una llamada de
descendencia en alguna parte del código.
 Exit. Esta flecha representa un regreso exitoso del procedimiento. Este ocurre
cuando la meta inicial ha sido unificada con uno de los componentes clausales y
cualquiera de las submetas ha sido satisfecha. El control entonces pasa por el puerto
de salida de la caja de descendencia. Textualmente se para el código siguiente por
descendencia y se regresa por el camino por donde se llegó.
 Redo. Esta flecha indica que la meta subsiguiente ha fallado y que el sistema hace
backtracking en un intento de encontrar alternativas a soluciones previas. El control
pasa a través del puerto Redo de la caja de descendencia. Se hace un intento
entonces por resatisfacer una de las submetas componentes en el cuerpo de la última
cláusula en la que se ha tenido éxito, si esto falla, se hace un completo, nuevo,
matching con la cláusula original al cuerpo de una nueva cláusula, textualmente se
sigue la parte anterior de código de la manera en que se ha ido buscando nuevas
formas de obtener éxito descomponiendo ésta en otras cláusulas y siguiendo así
mientras que sea necesario.
 Fail. Esta flecha representa una falla en la meta inicial, que puede ocurrir si no
existe un matching efectivo con alguna cláusula o si las submetas establecidas nunca
son satisfechas, o si cualquiera de las soluciones producidas es rechazada siempre
por el proceso posterior. El control pasa entonces por la caja de descendencia en el
puerto Fail y el sistema continua en backtracking. Textuelmente el sistema se mueve
hacia atrás en el código que ha llamado este procedimiento y se continua
moviendose hacia atrás buscando puntos de elección.
En términos de este modelo, la información que nosotros obtenemos acerca de esta caja de
procedimiento, es sólo acerca del flujo de control que se da a lo largo de estos cuatro
puertos. Esto significa que a este nivel no importa con cual cláusula se hace matching y
como se da satisfacción a las submetas, sino más bien como quisieramos conocer la meta
inicial y la final tienen efecto.
Note que la caja que se ha dibujado para cercar el procedimiento tiene que ser vista como
una caja de invocación, esto es, que hay una caja diferente para cada procedimiento,
obviamente con algunos procesos recurrentes en todos los procedimiento, con diferentes
llamadas y salidas en el flujo de control, pero estas para diferentes invocaciones. Por ello se
les de una entero único de identificación a cada una de estas cajas.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

2.2 Predicados básicos de depuración.


El intérprete proporciona un rango de predicados evaluables para el control de las
facilidades de evaluación, lo más basicos son los siguientes:
 debug que coloca al modo Debug en On (usualmente está en off) a fin de tener un
rango amplio de control en el flujo de información disponible desde el principio.
Cuando el debug está en off, el sistema no recuerda los llamados hechos a
procedimientos anteriormente, sino que solamente recuerda las invocasiones que se
están ejecutando. Se puede llamar a medias de una ejecución despues de haber dado
un ^C ( ver el comando trace) pero la información anterior no estará disponible.
 nodebug Pone adebug en off, y si existen puntos espías, éstos serán borrados.
 state. Muestra el estado de debug.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

2.3 Rastreo
El siguiente comando evaluable puede ser usado a fin de tener un control más efectivo del
programa que se va a depurar.
 trace coloca el switch debug en on, si es que no se ha hecho ya, y asegura que el
siguiente tiempo de control, se despliegará un mensaje y se le pedirá al usuario que
interactue con el sistema. El efecto del rastreo tembién puede ser logrados tecleando
un "t" después de una interrupción con ^C.
 leash(Mode) coloca el Leashing_Mode en forma de modo, donde modo puede tener
cualquiera de los siguientes valores:
 full - prompt on Call, Exit, Redo y Fail
 tight - prompt on Call, Redo y Fail
 half - prompt on Call y Redo
 loose - prompt y Call
 off - never prompt
o cualquiera otra combinación de estos y de los puertos descritos en la sección 4.12
El valor inicial del modo es "half", se puede cambiar si se modofica el archivo "prolog.ini".
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

2.4 Spy-points
Para programas extensos o de cualquier extensión es practicamente imposible que el
programador siga paso a paso todo lo que esta ocurriendo en cada módulo o en cada meta o
submeta. Es por ello que se posibilita la tarea de formular puntos espías que permiten
mantener un control exacto solamente en puntos clave elejidos por el usuario para el
control total del programa y su curso.
La selección del modo que se realice no tiene ingerencia alguna en los puntos espías que se
han elegido por parte del usuario.
Los puntos espías son conjuntos de establecimientos de variables y de predicados
evaluables o también de operadores estándares.
spy X Coloca en On el modo de los puntos espías, se puede usar en cualquier predicado o
punto del programa en una oración evaluable o en una directiva establecida previamente.
nospy X Funciona de manera similar a spy X pero en esta caso x es un conjunto de puntos
espías definidos previamente y removidos.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

2.5 Formato de los mensaje de depuración.


Se puede ver el formato que tienen exactamente y a profundidad los mensajes de error, esto
permitira realizar de una manera más eficiente las tareas de depuración de programas al
posibilitar el conocimiento de los simbolos usados en cada mensaje como este
** (23) 6 Call : foo(hello,there,_123) ?
"**" indica que es un spy-point. Si este punto no es un conjunto de puntos espías
predefinidos entonces el puntero se convierte en un ">". Que da las siguientes posibles
combinaciones:
"**" un spy-point.
"*>" un spy point con un skip la ultima vez que se estuvo en la caja
" >" No es un sapy point pero si hubo un skip la ultima vez que se estuvo en la caja
" " No es un spy point.
Notese que en esta caso las acciones son rastreadas a fin de mantener un centro exacto en el
depurado durante el establecimiento de este tipo de mensajes.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

2.6 Opciones disponibles durante la depuración


Esta sección describe las opciones particulares que estan disponibles cuando el sistema te
muestra despues de algun mensaje de depuracion. Todas las opciones son una letra como
nemonico, y algunas pueden ser opcionales seguidas de un entero decimal. Algunas
opciones solo requieren el terminador.
La unica opcion que se hace necesaria de recordar es "h" y un ENTER, ya que es la
función que despliegará a las siguientes funciones:
<cr> creep c creep
<lf> leap l leap
<esc> skip s skip
x back to choice point q quasi skip
r retry r <n> retry goal n f fail f <n> fail goal n
; redo
a abort e salir de Prolog
h help p imprime una meta
w escribe meta d despliega una meta
g imprime ancestros g <n> ultimo n ancestros
@ comando accept b break
[ consult user n nodebug
Las primeras tres opciones son decisiones de control basicas ya que son las más
frecuentemente usadas, cada una puede ser llamada con una sola tecla c <cr> Creep
Causa que el intérprete se vaya de un solo paso al siguiente puerto e imprima un mensaje.
Si el puerto esta atascado se le pedira al usuario acciones posteriores, de otra manera el
procedimiento continuará hasta terminar en la terminal.
l <lf> Leap
Causa que el intérprete regrese ala ejecución del programa, solo para cuando un punto
espía se ha encontrado, o cuando el programa termina
s <esc> Skip
Es válido solamente en el puerto Redo, brinca sobre una ejecución entera o un
procedimiento. El uso de esta directiva de compilación garantiza que el control será
devuelto a la caja de control despues de la ejecución dentro de la caja. Cuando se da un
cuasibrinco o cuasiskip en donde no se ignoran los puntos espías, la opción "t" después de
un ^C desabilitará las máscaras.
q Quasi-skip
Es como skip, excepto porque este brinco no oculta a los puntos espías para la depuración.
Si existe un punto espía en la ejecución de una meta, entonces el control regresa al punto en
donde la acción se debe realizar.
x Back to choice point
Da la posibilidad de hacer un fail rápio, llevando al programa al punto real de decisión
anterior. Cuando el usuario sabe que algo hará fail, puede anticipar el punto de decisión y
verificarlo rapidamente sin tener que repetir el proceso completo. Si se da una secuencia de
Fails seguidos de una secuencia de Redos (o si la secuencia está vacía) se tienen mensajes
estándares (como los mostrados anteriormente) excepto para los primeros dos caracteres
donde será "=>". Cuando se llama a la acción exit, la operación de salida ocurriá
normalmente.
r Retry
Se puede usar en cualquiera de los cuatro puertos, aunque el puerto call no tenga efecto en
realidad. Esto permite reestablecer la invocación cuando por ejemplo, el usuario se ha dado
cuenta de que ha obtenido resultados algo raros. El estado de la ejecución es exactamente el
mismo que el alcanzado durante la ejecución normal original. Si se proporciona un entero
con el comando retry entonces se tomará como una especificación de que el sistema trate de
invocar al puerto y no a la caja actual, por supuesto que a un puerto designado por el
usuario. Desafortunadamente el proceso no puede ser garantizado. Se puede suplir con cuts
(!) al interior del programa. Un mensaje de error "[ ** JUMP ** ]" se despliegará en la
terminal para indicar que es lo que ha ocurrido.
f Fail
es similar al retry ya que transfiere el contro al puerto fail desde la caja actual, en una
posición en donde se estpá cercado a hacer un backtracking
; Redo
Puede ser llamado en una salida y forzar a mover al puesrto Redo
a Abort
Causa que se aborte la ejecución actual. Todas las ejecuciones se mantienen hasta que el
usuario se asegura de que no las necesita conforme sube al mas alto nivel del intérprete (es
equivalente al predicado evaluable abort)
e Exit from Prolog
Causa una salida irreversible del sistema de prolog, de regreso al Monitor (esta directiva es
equivalente a Halt)
h Help
Despliega la tabla de opciones marcada arriba
p Print goal
Reimprime la meta actual usando print
w Write goal
Escribe la meta actual en la terminal usando write. Esto puede ser muy útil cuando la lista
temporal de rutinas no hace lo que se espera de ella
d Display goal
Despliega la meta en turno, usando display (ver Write arriba).
g Print ancestor goals
Provee al usuario de una lista de las metas o submetas que ya se han cumplido en la
ejecución de un programa, el orden se da en forma jerarquica hacia arriba de la secuencia
que ha sido llamada. Usa los ancestros de cada predicado evaluable (ver pág 42). Si se
proporciona un entero con esta directiva entonces se despliegan n antecesores desde el
punto en que el usuario ha dado la directiva.
@ Accept command
Permite llamar arbitrariamente a metas de Prolog, es un break de un solo paso muy
efectivo, (ver mas adelante). El mensaje inicial "| :- " saldrá en la terminal y el comando
entonces se lee desde la terminal y se ejecuta como si el usuario estuviera en el nivel más
alto.
b Break
Llama al predicado evaluable break, pone al interprete al nivel mas alto con la ejecución
aparte del modulo actual, cuando se finaliza el modo break (^Z) el sistema pregunta en que
punto se hizo el rompimiento, y una nueva ejecución se separa de la suspendida, los
números de invocación comienzan a partir de 1 desde su invocación.
[ Consult user Permite insertar clausulas y regresar a donde se estaba, es lo mismo que usar
"@" seguida de "[user].".
n noebug
Desactiva el modo debug, lo pone en Off, es la forma correcta de apagar el debug desde el
modo de rastreo. No se puede usar "@" o "b" porque siempre activa el debug desde el
regreso.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

2.7 Consultar de nuevo durante la depuración.


Es posible y a veces es útil reconsultar o releer un archivo a medias de la ejecución de un
programa. Sin embargo, esto puede ocasionar que el sistema funcione de una manera
impredecible debido a las siguientes circunstancias: un procedimiento se ha ejecutado con
éxito, se ha redefinido por una consulta y después se ha reactivado por un backtracking.
Cuendo el backtracking ocurre, todas las clausulas nuevas apaarecerán en el intérprete
como posibilidades de alternativa de solución aún cuando se hayan usado ya clausulas o
predicados exactamente iguales, así grandes cantidades de procedimientos no deseados
ocasionarían backtracking. Este problema se evita si se hace el consult desde el pueto del
procedimiento que será redefinido.
mailto:lopezcua@proton.ucting.udg.mxmailto:lopezcua@proton.ucting.udg.mx
Sugerencias o comentarios: mailto:lopezcua@proton.ucting.udg.mx
CAPITULO 3. COMPILACIÓN
El compilador Prolog DECsystem-10 produce código más compacto y eficiente, el cual
funciona de 10 a 20 veces más rápido que el interprete de código y requiere mucho menos
almacenamiento en tiempo de ejecución. Los programas compilados con Prolog, son
comparados en eficiencia, con programas desarrollados en LISP ( con el compilador LISP
DECsystem-10 ), para realizar las mismas funciones. En contra de esto, la desventaja es
que la compilación es varias veces más lenta que la "consulta" y mucha de la ayuda
proporcionada por el depurador, como el seguimiento, no es aplicable al código compilado.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

3.1 Llamando al Compilador.


Para compilar el programa se usa la siguiente sentencia :
|? compile (Archivos).
donde "Archivos" es cualquier nombre de archivo ( incluyendo el archivo ‘user’ ), o una
lista de los nombres de los archivos que se desean compilar. Con esta instrucción, los
procedimientos contenidos en dichos archivos serán compilados. A continuación se muestra
un ejemplo con varios archivos :
|? compile ( [dbase, 'extras.pl,' user] ).
Exteriormente, el efecto de "compile" es mucho muy parecido al de "reconsult". Si las
cláusulas para algunos predicados aparecen en más de un archivo, el juego posterior de
dichas cláusulas, sobre-escribe el anterior. La división del programa en archivos separados
no implica ninguna estructura modular ( ningún procedimiento compilado puede llamar a
cualquier otro ).
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

3.2 Declaraciones Públicas.


Para hacer que un procedimiento compilado sea accesible por el interprete de código
( incluyendo directivas ) es necesario declarar dicho procedimiento como público, lo cual se
realiza con el comando siguiente del compilador :
:- public Predicates.
donde "Predicates" es una especificación del predicado, en la forma : Nombre / Arity , o
también puede ser una conjunción de especificaciones semejantes, por ejemplo :
:- public concatenate/3, member/2, ordered/1, go/0.
Las declaraciones públicas pueden aparecer en cualquier parte dentro de un archivo
compilado; no es necesario que las declaraciones públicas procedan a el correspondiente
procedimiento, ni tampoco que estén dentro del mismo archivo.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

3.3 Mezclando Código Compilado y Código Interpretado.


Para predicados públicos un procedimiento compilado sobre-escribe cualquier versión
interpretada previa ( cf. reconsult ). De la misma forma una reconsulta subsecuente de la
versión interpretada sobre-escribirá la versión compilada.
Es posible tener un procedimiento compilado con el mismo nombre y arity, así como
muchos y diferentes procedimientos interpretados. Suponiendo que el procedimiento
compilado no fue declarado para ser público, los dos procedimientos nunca intervendrán el
uno con el otro, es decir, el código compilado utilizará la versión compilada mientras que el
interpretador de código usará la versión interpretada.
Cuando una versión compilado se hace presente y sobre-escribe un procedimiento
interpretado, éste último es reemplazado por la cláusula :
P :- incore(P).
donde "P" es el objetivo más general para el predicado y "encore" es un predicado
evaluable estándar ( análogo a "call" ), por medio del cual son accesibles todos los
procedimientos compilados para los predicados públicos.
Hay dos formas en que el código compilado puede utilizar procedimientos interpretados :
 Si no hay cláusulas compiladas para el predicado, el procedimiento interpretado es
llamado automáticamente.
 La sentencia : call( P ) , siempre llama al interprete. Es importante hacer notar, que
esto implica que deseamos llamar procedimientos compilados con "call" , deben ser
declarados como públicos.
Para aclarar lo anterior vamos a ver un ejemplo :
Primero compilamos el siguiente archivo: :- public f/1, g/1.
f(a).
g(X) :- f(X).
g(X) :- h(X).
No hay cláusulas para h/1. Después consultamos lo siguiente :
f(b).
h(c).
Ahora, si nosotros llamamos a " f "obtendremos :
?- f(X).
X=a;
X=b;
no
Esto es, nosotros usamos tanto las cláusulas compiladas, como las interpretadas para " f ".
De cualquier modo si llamamos a " g " :
?- g(X).
X=a;
X = c ; no
podemos observar que " g " solo llama la versión compilada de " f ", así que la solución : X
= b , no es encontrada. La segunda cláusula para " g " llama a " h ", y como no hay
cláusulas compiladas para " h " esta llamada es pasada al interprete, el cual encuentra una
solución : X = c.

http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice
3.4 Declaraciones de Modo.
Cuando un programa va a ser compilado es conveniente incluir declaraciones de modo, las
cuales informan al compilador que ciertos procedimientos serán usados en forma
restringida, es decir, que algunos argumentos en la llamada siempre serán "entrada",
mientras que otros siempre serán "salida". Esta información habilita al compilador para
ser capaz de generar código más compacto y hacer un mejor uso del almacenamiento en
tiempo de ejecución. Las declaraciones de modo también ayudan a que otras personas
comprendan la operación del programa.
Una declaración de modo es indicada con una directiva del compilador de la forma :
:- mode P(M).
donde "P" es el nombre de un procedimiento y "M" especifica los "modos" de sus
argumentos. M consiste de cierto número de "elementos de modo" ( elementos que indican
el modo deseado para los argumentos ), separados por comas, una para cada posición de
los argumentos del predicado interesado. Los elementos de modo pueden ser de cualquiera
de los 3 tipos siguientes :
 Modo + : Especifica que el argumento correspondiente en cualquier llamada al
procedimiento siempre será "entrada".
 Modo - : Indica que el argumento nunca será "entrada", es decir, siempre será
"salida".
 Modo ? : Indica que no hay restricción en la forma del argumento. Por ejemplo, una
declaración de modo como :
:- mode concatenate(?,?,?).
es equivalente a omitir completamente la declaración.
Por ejemplo, si tenemos un procedimiento llamado "encadenar" y los dos argumentos
primeros, siempre serán "entradas", podemos dar la siguiente declaración de modo :
:- mode encadenar(+,+,?).
En el caso de que en el procedimiento anterior el tercer argumento siempre será "salida",
podemos reforzar la declaración de modo como sigue :
:- mode encadenar(+,+,-).
Además, esta permitido combinar varias declaraciones de modo en un solo comando, por
ejemplo :
:- mode encadenar(+,+,-), mode miembro(+,?), mode orden(+).
Para que una declaración de modo tenga efecto debe aparecer antes de las cláusulas del
procedimiento correspondiente. Cuando una declaración de modo es violada por una
llamada a un procedimiento, la forma precisa como reacciona depende de el objetivo y la
cabecera de la cláusula. La llamada puede ser realizada con éxito como si no hubiera una
declaración de modo o puede causar un mensaje de error y fracasar. Como el resultado
preciso depende de los cambios en las versiones futuras del sistema, el usuario debió asumir
que todas las declaraciones de modo que son violadas causaran un mensaje de error.
Las declaraciones de modo son ignoradas por el interprete.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

3.5 Indexación.
En contraste con el interprete, las cláusulas de un procedimiento compilado son indexadas
de acuerdo al "functor" principal del primer argumento especificado en la cabecera de la
cláusula. Esto significa que el subconjunto de cláusulas, son emparejadas con un
determinado objetivo, hasta que el primer paso de la unificación interesada, sea hallada
muy rápidamente, prácticamente en un tiempo constante ( un tiempo independiente del
número de cláusulas ). Esto puede ser muy importante donde hay un gran número de
cláusulas en un procedimiento.
La indexación también mejora la capacidad del sistema de Prolog para detectar la
determinacia, la cual es importante en la conservación del espacio de trabajo.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

3.6 Optimización de la cola de Recursión.


El compilador incorpora "Optimización de la cola de recursión" para mejorar la velocidad
y la eficiencia del espacio de procedimientos determinados. Cuando la ejecución alcanza el
último objetivo en una cláusula que pertenece a un procedimiento, y provee que no hay
puntos de retroseguimiento restantes, todo el espacio de trabajo asignado a los
procedimientos locales es reclamado ANTES de finalizar la llamada y cualquier estructura
que fue creada es eliminada. Esto significa que el programa puede realizar varias
recursiones sin necesidad de exceder el limite en el espacio.
Por ejemplo :
cycle(State) :- transform(State,State1), cycle(State1).
donde "transform" es un procedimiento determinado, puede continuarse ejecutando
indefinidamente, previendo que cada estructura individual "State", no sea demasiado
larga. El procedimiento "cycle" es equivalente a un lazo iterativo de in lenguaje
convencional.
Para lograr la ventaja de la optimización de la cola recursiva, debemos asegurarnos que
Prolog pueda reconocer que el procedimiento es determinado en el punto donde la llamada
recursiva toma lugar. Dicho en otra forma, el sistema debe ser capaz de detectar que no hay
otras soluciones que deben ser encontradas para el objetivo actual, mediante subsecuente
retroseguimiento. En general esto esta envuelto en la indexación del compilador Prolog
DEC-10 y / o el uso de corte.
http://proton.ucting.udg.mx/tutorial/prolog/index.htm -
indicehttp://proton.ucting.udg.mx/tutorial/prolog/index.htm - indiceRegresar al Indice

3.7 Limitaciones Practicas.


Algunas consideraciones que debemos tomar en cuenta son :
 Hay que tener presente que el espacio ocupado por el código compilado, cuando es
reemplazado, no es reclamado.
 Hacer que un predicado sea público, nos lleva a generar una cantidad significante
de código extra. Además este código es regenerado cada vez que el compilador es
llamado ( con lo cual el espacio ocupado por el código anterior no es reclamado ).
Debido a esto, es conveniente, cuando sea posible, incluir en una sola llamada al
compilador, todos los archivos que se desea sean compilados.
 La ejecución del código compilado no puede ser "rota" o "abortada", lo cual si s
posible con el código interpretado. Una respuesta a la petición para "abortar",
realizada con CTRL+C, solo tiene efecto en la siguiente entrada de un
procedimiento interpretado.
Se puede notar que hay una pausa despreciable en el inicio y terminación de la
compilación. Esto se debe a que el compilador reside en una capa separada, la cual debe ser
intercambiada.

También podría gustarte