Logo Studenta

Apunte Prolog

¡Este material tiene más páginas!

Vista previa del material en texto

LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
 
 
 
 
���������	
�	�
���� 
 
 
�
 
 
 
 
Faraón Llorens Largo 
Mª Jesús Castel de Haro 
 
 
 
 
 
DEPARTAMENTO DE CIENCIA DE LA COMPUTACIÓN E 
INTELIGENCIA ARTIFICIAL 
Universidad de Alicante 
 
 
 
 PROLOG 
© 1996-2001 Faraón Llorens Página i 
 
 
 
Contenido 
 
 
 
1. PROGRAMACIÓN LÓGICA ......................................................................................................... 1 
2. PROLOG Y EL LENGUAJE DE LA LÓGICA DE PRIMER ORDEN...................................... 3 
2.1. PREDICADOS .............................................................................................................................. 3 
2.2. TÉRMINOS.................................................................................................................................. 4 
2.3. CONECTIVAS LÓGICAS............................................................................................................... 6 
3. ESTRUCTURA DE UN PROGRAMA........................................................................................... 9 
3.1. PREGUNTAS................................................................................................................................ 9 
4. SINTAXIS........................................................................................................................................ 12 
4.1. CARACTERES............................................................................................................................ 12 
4.2. ESTRUCTURAS.......................................................................................................................... 13 
4.3. OPERADORES ........................................................................................................................... 13 
5. ESTRUCTURAS DE DATOS........................................................................................................ 18 
5.1. ÁRBOLES.................................................................................................................................. 18 
5.2. LISTAS...................................................................................................................................... 18 
6. ESTRUCTURAS DE CONTROL ................................................................................................. 23 
6.1. RECURSIÓN .............................................................................................................................. 23 
6.2. UNIFICACIÓN............................................................................................................................ 24 
6.3. REEVALUACIÓN........................................................................................................................ 25 
6.4. EL CORTE................................................................................................................................. 27 
6.5. PREDICADOS DE CONTROL ....................................................................................................... 30 
7. PREDICADOS DE ENTRADA Y SALIDA ................................................................................. 32 
7.1. LECTURA Y ESCRITURA DE TÉRMINOS.................................................................................... 32 
7.2. LECTURA Y ESCRITURA DE CARACTERES ............................................................................... 33 
7.3. LECTURA Y ESCRITURA EN FICHEROS..................................................................................... 34 
8. MODIFICACIÓN DE LA BASE DE CONOCIMIENTOS ........................................................ 37 
8.1. ADICIÓN DE BASES DE CONOCIMIENTO EXTERNAS ................................................................. 37 
8.2. MANIPULACIÓN DE LA BASE DE CONOCIMIENTOS .................................................................. 38 
8.3. COMPONENTES DE ESTRUCTURAS ........................................................................................... 41 
9. DEPURACIÓN DE PROGRAMAS PROLOG............................................................................ 44 
10. PROGRAMACIÓN EN PROLOG........................................................................................... 47 
10.1. ENTORNO DE TRABAJO............................................................................................................ 47 
10.2. ESTILO DE PROGRAMACIÓN EN PROLOG.................................................................................. 47 
10.3. INTERPRETACIÓN PROCEDIMENTAL DE LOS PROGRAMAS PROLOG........................................... 49 
10.4. VENTAJAS DE PROLOG............................................................................................................. 50 
11. EJEMPLOS ................................................................................................................................ 52 
11.1. FORMAS NORMALES ................................................................................................................ 52 
11.2. ÁRBOL GENEALÓGICO.............................................................................................................. 55 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página ii © 1996-2001 Faraón Llorens 
11.3. JUEGO LÓGICO ......................................................................................................................... 58 
12. PREDICADOS PREDEFINIDOS ............................................................................................ 63 
13. SISTEMAS PROLOG ............................................................................................................... 67 
13.1. PROLOG-2 ................................................................................................................................ 67 
13.2. SWI-PROLOG ........................................................................................................................... 68 
ANEXO: CUADRO COMPARATIVO DE LAS DIFERENTES NOTACIONES PARA 
PROGRAMACIÓN LÓGICA................................................................................................................. 71 
BIBLIOGRAFÍA ...................................................................................................................................... 72 
 
 
 
 
 PROLOG 
© 1996-2001 Faraón Llorens Página iii 
 
 
 
 Estos apuntes pretenden ser un documento de apoyo para los estudiantes que 
realizan las prácticas en el lenguaje de programación Prolog, en alguna de las 
asignaturas de lógica impartidas por el departamento de Ciencia de la Computación e 
Inteligencia Artificial de la Universidad de Alicante: Lógica de Primer Orden, Lógica 
Computacional y Ampliación de Lógica. 
 
 El Prolog descrito, tanto la sintaxis como los operadores básicos, siguen el 
estándar de Edimburgo [Clocksin y Mellish, 1987] así como las especificaciones ISO 
[Covington, 1993] y [Deransart y otros, 1996]. 
 
 Se trata de una breve exposición de la forma de trabajo, de las características 
principales y de los predicados predefinidos estándar del lenguaje Prolog. No se trata de 
una completa descripción de la sintaxis y la semántica de Prolog ni de la forma de 
programar en dicho lenguaje. Para ello existen excelentes libros, algunos de ellos 
referenciados en la bibliografía. Son muy recomendables los libros [Clocksin y Mellish, 
1987], [Bratko, 1990] y [Sterling y Shapiro, 1994], y para un nivel más avanzado [O'Keefe, 1990] 
 
 No se pretende explorar toda la potencia del lenguaje de programación lógica 
Prolog. Eso sobrepasaría las pretensiones de nuestras asignaturas. Simplemente 
queremos mostrar a los estudiantes cómo pueden escribir programas (bases de 
conocimientos) con el lenguaje de la lógica, por medio de hechos y reglas. 
Posteriormente podemos ejecutar estos programas realizando preguntas que el sistema 
nos responderáa partir de la información que conoce. Es decir, no vamos a estudiar 
Prolog desde el punto de vista de un lenguaje de programación, sino como una 
aplicación directa de la lógica de primer orden. 
 
 Por todo ello, únicamente vamos a describir un pequeño subconjunto de 
predicados predefinidos, en especial aquellos con marcado carácter lógico, que no 
interfieren en el control, no entraremos en detalle en los predicados de entrada/salida. 
Todos los ejemplos han sido probados utilizando SWI-Prolog [Wielemaker, 2001], que es 
el interprete/compilador utilizado en las clases prácticas. 
 
 Para cualquier duda o sugerencia podéis dirigiros a la dirección de correo 
electrónico: 
 
logica@dccia.ua.es 
 
 Más información se puede encontrar en el sitio web: 
 
http://www.dccia.ua.es/logica/prolog 
 
 
 PROLOG 
© 1996-2001 Faraón Llorens Página 1 
 
1. PROGRAMACIÓN LÓGICA 
 
 El lenguaje de programación PROLOG (“PROgrammation en LOGique”) fue 
creado por Alain Colmerauer y sus colaboradores alrededor de 1970 en la Universidad 
de Marseille-Aix1, si bien uno de los principales protagonistas de su desarrollo y 
promoción fue Robert Kowalski2 de la Universidad de Edimburgh. Las investigaciones 
de Kowalski proporcionaron el marco teórico, mientras que los trabajos de Colmerauer 
dieron origen al actual lenguaje de programación, construyendo el primer interprete 
Prolog. David Warren3, de la Universidad de Edimburgh, desarrolló el primer 
compilador de Prolog (WAM – “Warren Abstract Machine”). Se pretendía usar la lógica 
formal como base para un lenguaje de programación, es decir, era un primer intento de 
diseñar un lenguaje de programación que posibilitara al programador especificar sus 
problemas en lógica. Lo que lo diferencia de los demás es el énfasis sobre la 
especificación del problema. Es un lenguaje para el procesamiento de información 
simbólica. PROLOG es una realización aproximada del modelo de computación de 
Programación Lógica sobre una máquina secuencial. Desde luego, no es la única 
realización posible, pero sí es la mejor elección práctica, ya que equilibra por un lado la 
preservación de las propiedades del modelo abstracto de Programación Lógica y por el 
otro lado consigue que la implementación sea eficiente. 
 
 El lenguaje PROLOG juega un importante papel dentro de la Inteligencia 
Artificial, y se propuso como el lenguaje nativo de las máquinas de la quinta generación 
("Fifth Generation Kernel Language", FGKL) que quería que fueran Sistemas de 
Procesamiento de Conocimiento. La expansión y el uso de este lenguaje propició la 
aparición de la normalización del lenguaje Prolog con la norma ISO (propuesta de junio 
de 1993). 
 
 PROLOG es un lenguaje de programación para ordenadores que se basa en el 
lenguaje de la Lógica de Primer Orden y que se utiliza para resolver problemas en los 
que entran en juego objetos y relaciones entre ellos. Por ejemplo, cuando decimos 
"Jorge tiene una moto", estamos expresando una relación entre un objeto (Jorge) y otro 
objeto en particular (una moto). Más aún, estas relaciones tienen un orden específico 
(Jorge posee la moto y no al contrario). Por otra parte, cuando realizamos una pregunta 
(¿Tiene Jorge una moto?) lo que estamos haciendo es indagando acerca de una relación. 
Además, también solemos usar reglas para describir relaciones: "dos personas son 
hermanas si ambas son hembras y tienen los mismos padres". Como veremos más 
adelante, esto es lo que hacemos en Prolog. 
 
 
1 A. Colmerauer. Les Systèmes-Q, ou un formalisme pouranalyser et synthétiser des phrases sur ordinateur. Internal 
Report 43, Computer Science Dpt., Université de Montreal, septiembre, 1970. 
A. Colmerauer, H. Kanoui, P. Roussel y R. Pasero. Un Systeme de Communication Homme-Machine en Français, 
Groupe de Recherche en Intelligence Artificielle, Université d’Aix-Marseille, 1973. 
 
2 R. Kowalski. Predicate Logic as a Programming Language. En Proc. IFIP, Amsterdam, 1974. 
 
3 D. Warren. The runtime environment for a prolog compiler using a copy algorithm. Technical Report 83/052, 
SUNY and Stone Brook, New York, 1983. 
 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 2 © 1996-2001 Faraón Llorens 
 Una de las ventajas de la programación lógica es que se especifica qué se tiene 
que hacer (programación declarativa), y no cómo se debe hacer (programación 
imperativa). A pesar de esto, Prolog incluye algunos predicados predefinidos meta-
lógicos, ajenos al ámbito de la Lógica de Primer Orden, (var, nonvar, ==, ...), otros 
extra-lógicos, que tienen un efecto lateral, (write, get, ...) y un tercer grupo que nos 
sirven para expresar información de control de como realizar alguna tarea ( el corte, ... ). 
Por tanto, Prolog ofrece un sistema de programación práctico que tiene algunas de las 
ventajas de claridad y declaratividad que ofrecería un lenguaje de programación lógica 
y, al mismo tiempo, nos permite un cierto control y operatividad. 
 
 PROLOG 
© 1996-2001 Faraón Llorens Página 3 
 
2. PROLOG Y EL LENGUAJE DE LA LÓGICA DE PRIMER 
ORDEN 
 
 La Lógica de Primer Orden analiza las frases sencillas del lenguaje (fórmulas 
atómicas o elementales) separándolas en Términos y Predicados. Los términos hacen 
referencia a los objetos que intervienen y los predicados a las propiedades o relaciones 
entre estos objetos. Además, dichas fórmulas atómicas se pueden combinar mediante 
Conectivas permitiéndonos construir fórmulas más complejas, llamadas fórmulas 
moleculares. 
 
2.1. PREDICADOS 
 
 Se utilizan para expresar propiedades de los objetos, predicados monádicos, y 
relaciones entre ellos, predicados poliádicos. En Prolog los llamaremos hechos. 
Debemos tener en cuenta que: 
 
• Los nombres de todos los objetos y relaciones deben comenzar con una letra 
minúscula. 
• Primero se escribe la relación o propiedad: predicado 
• Y los objetos se escriben separándolos mediante comas y encerrados entre 
paréntesis: argumentos. 
• Al final del hecho debe ir un punto ("."). 
 
��simbolo_de_predicado(arg1,arg2,...,argn). 
 
 
 Tanto para los símbolos de predicado como para los argumentos, utilizaremos en 
Prolog constantes atómicas. 
 
 
 Ejemplos (ej01.pl): 
 
/* Predicados monádicos: PROPIEDADES */ 
 
/* mujer(Per) <- Per es una mujer */ 
mujer(clara). 
mujer(chelo). 
 
/* hombre(Per) <- Per es un hombre */ 
hombre(jorge). 
hombre(felix). 
hombre(borja). 
 
/* moreno(Per) <- Per tiene el pelo de color oscuro */ 
moreno(jorge). 
 
 
/* Predicados poliádicos: RELACIONES */ 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 4 © 1996-2001 Faraón Llorens 
 
/* tiene(Per,Obj) <- Per posee el objeto Obj */ 
tiene(jorge,moto). 
 
/* le_gusta_a(X,Y) <- a X le gusta Y */ 
le_gusta_a(clara,jorge). 
le_gusta_a(jorge,clara). 
le_gusta_a(jorge,informatica). 
le_gusta_a(clara,informatica). 
 
/* es_padre_de(Padre,Hijo-a) <- Padre es el padre de Hijo-a */ 
es_padre_de(felix,borja). 
es_padre_de(felix,clara). 
 
/* es_madre_de(Madre,Hijo-a) <- Madre es la madre de Hijo-a */ 
es_madre_de(chelo,borja). 
es_madre_de(chelo, clara). 
 
/* regala(Per1,Obj,Per2) <- Per1 regala Obj a Per2 */ 
regala(jorge, flores, clara). 
 
 
2.2. TÉRMINOS 
 
 Los términos pueden ser constantes o variables, y suponemos definido un 
dominio no vacío en el cual toman valores (Universo del Discurso). En la práctica se 
toma como dominio el Universo de Herbrand. Para saber cuántos individuos del 
universo cumplen una determinada propiedad o relación, cuantificamos los términos. 
 
 Las constantes se utilizan para dar nombre a objetos concretos del dominio, 
dicho de otra manera, representan individuos conocidos de nuestro Universo. Además, 
como ya hemos dicho, las constantes atómicas de Prolog también se utilizan para 
representar propiedades y relaciones entre los objetos del dominio. Hay dos clases de 
constantes: 
 
• Átomos: existen tres clases de constantesatómicas: 
- Cadenas de letras, dígitos y subrayado (_) empezando por letra 
minúscula. 
 - Cualquier cadena de caracteres encerrada entre comillas simples ('). 
 - Combinaciones especiales de signos: "?-", ":-", ... 
 
 
• Números: se utilizan para representar números de forma que se puedan 
realizar operaciones aritméticas. Dependen del ordenador y la 
implementación4. 
- Enteros: en la implementación de Prolog-2 puede utilizarse cualquier 
entero que el intervalo [-223,223-1]=[-8.388.608,8.388.607]. 
 
4 Los ordenadores, vía hardware, resuelven eficientemente el manejo de los números y de las operaciones aritméticas, 
por tanto, en la práctica, la programación lógica lo deja en sus manos, trabajando en una aritmética estándar 
independiente del lenguaje. 
 PROLOG 
© 1996-2001 Faraón Llorens Página 5 
- Reales: decimales en coma flotante, consistentes en al menos un dígito, 
opcionalmente un punto decimal y más dígitos, opcionalmente E, un 
«+» o «-» y más dígitos. 
 
 
 Ejemplos de constantes: 
 
 átomos válidos átomos no válidos números válidos nº no válidos 
 
 f 2mesas -123 123- 
 vacio Vacio 1.23 .2 
 juan_perez juan-perez 1.2E3 1. 
 'Juan Perez' _juan 1.2E+3 1.2e3 
 a352 352a 1.2E-3 1.2+3 
 
 
 Las variables se utilizan para representar objetos cualesquiera del Universo u 
objetos desconocidos en ese momento, es decir, son las incógnitas del problema. Se 
diferencian de los átomos en que empiezan siempre con una letra mayúscula o con el 
signo de subrayado (_). Así, deberemos ir con cuidado ya que cualquier identificador 
que empiece por mayúscula, será tomado por Prolog como una variable. Para trabajar 
con objetos desconocidos cuya identidad no nos interesa, podemos utilizar la variable 
anónima (_). Las variables anónimas no están compartidas entre sí. 
 
 Ejemplos de variables: X 
 Sumando 
 Primer_factor 
 _indice 
 _ (variable anónima) 
 
 Una variable está instanciada cuando existe un objeto determinado representado 
por ella. Y está no instanciada cuando todavía no se sabe lo que representa la variable. 
Prolog no soporta asignación destructiva de variables, es decir, cuando una variable es 
instanciada su contenido no puede cambiar. Como veremos más adelante, la 
manipulación de datos en la programación lógica se realiza por medio de la unificación. 
 
 Explícitamente Prolog no utiliza los símbolos de cuantificación para las 
variables, pero implícitamente sí que lo están. En general, todas las variables que 
aparecen están cuantificadas universalmente, ya que proceden de la notación en forma 
clausal, y, por tanto, todas las variables están cuantificadas universalmente aunque ya no 
escribamos explícitamente el cuantificador (paso 6ª de la transformación a forma 
clausal : eliminación de cuantificadores universales). Pero veamos que significado 
tienen dependiendo de su ubicación. Si las fórmulas atómicas de un programa lógico 
contienen variables, el significado de estas es : 
• Las variables que aparecen en los hechos están cuantificadas universalmente ya que 
en una cláusula todas las variables que aparecen están cuantificadas universalmente 
de modo implícito. 
 
gusta(jorge,X). equivale a la fórmula ∀ x gusta(jorge,x) 
 
y significa que a jorge le gusta cualquier cosa 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 6 © 1996-2001 Faraón Llorens 
 
• Las variables que aparecen en la cabeza de las reglas (átomos afirmados) están 
cuantificadas universalmente. Las variables que aparecen en el cuerpo de la regla 
(átomos negados), pero no en la cabeza, están cuantificadas existencialmente. 
 
abuelo(X,Y) :- padre(X,Z), padre(Z,Y). equivale a la fórmula 
∀ x ∀ y ∀ z [abuelo(x,y) ∨ ¬padre(x,z) ∨ ¬padre(z,y)] 
∀ x ∀ y [abuelo(x,y) ∨ ∀ z ¬[padre(x,z) ∧ padre(z,y)] ] 
∀ x ∀ y [abuelo(x,y) ∨ ¬∃ z [padre(x,z) ∧ padre(z,y)] ] 
∀ x ∀ y [ ∃ z [padre(x,z) ∧ padre(z,y)] → abuelo(x,y) ] 
 
que significa que para toda pareja de personas, una será el abuelo de otra si existe alguna 
persona de la cuál el primero es padre y a su vez es padre del segundo 
 
• Las variables que aparecen en las preguntas están cuantificadas existencialmente. 
 
?- gusta(jorge,X) equivale a la fórmula ∀ x ¬gusta(jorge,x) ≡ ¬∃ x gusta(jorge,x) 
 
y que pregunta si existe algo que le guste a jorge, ya que utilizamos refutación y por tanto 
negamos lo que queremos demostrar. 
 
 
2.3. CONECTIVAS LÓGICAS 
 
 Puede que nos interese trabajar con sentencias más complejas, fórmulas 
moleculares, que constarán de fórmulas atómicas combinadas mediante conectivas. Las 
conectivas que se utilizan en la Lógica de Primer Orden son: conjunción, disyunción, 
negación e implicación. 
 
 La conjunción, “y”, la representaremos poniendo una coma entre los objetivos 
“,” y consiste en objetivos separados que Prolog debe satisfacer, uno después de otro: 
 
��X , Y 
 
 Cuando se le da a Prolog una secuencia de objetivos separados por comas, 
intentará satisfacerlos por orden, buscando objetivos coincidentes en la Base de Datos. 
Para que se satisfaga la secuencia se tendrán que satisfacer todos los objetivos. 
 
 
 La disyunción, “o”, tendrá éxito si se cumple alguno de los objetivos que la 
componen. Se utiliza un punto y coma “;” colocado entre los objetivos: 
 
��X ; Y 
 
 La disyunción lógica también la podemos representar mediante un conjunto de 
sentencias alternativas, es decir, poniendo cada miembro de la disyunción en una 
cláusula aparte, como se puede ver en el ejemplo es_hijo_de. 
 PROLOG 
© 1996-2001 Faraón Llorens Página 7 
 
 
 La negación lógica no puede ser representada explícitamente en Prolog, sino que 
se representa implícitamente por la falta de aserción : “no”, tendrá éxito si el objetivo X 
fracasa. No es una verdadera negación, en el sentido de la Lógica, sino una negación 
“por fallo”. La representamos con el predicado predefinido not o con \+: 
 
��not(X) 
��\+ X 
 
 La implicación o condicional, sirve para significar que un hecho depende de un 
grupo de otros hechos. En castellano solemos utilizar las palabras “si ... entonces ...”. En 
Prolog se usa el símbolo “:-” para representar lo que llamamos una regla: 
 
��cabeza_de_la_regla :- cuerpo_de_la_regla. 
 
 La cabeza describe el hecho que se intenta definir; el cuerpo describe los 
objetivos que deben satisfacerse para que la cabeza sea cierta. Así, la regla: 
C :- O1, O2, ..., On. 
puede ser leída declarativamente como: 
“La demostración de la cláusula C se sigue de la demostración 
de los objetivos O1, O2, ..., On.” 
o procedimentalmente como: 
 “Para ejecutar el procedimiento C, se deben llamar para 
su ejecución los objetivos O1,O2,...,On.” 
 
 Otra forma de verla es como una implicación lógica “al revés” o “hacia atrás”: 
cuerpo_de_la_regla → cabeza_de_la_regla 
 
 Un mismo nombre de variable representa el mismo objeto siempre que aparece 
en la regla. Así, cuando X se instancia a algún objeto, todas las X de dicha regla también 
se instancian a ese objeto ( ámbito de la variable ). 
 
 Por último, daremos una serie de definiciones. Llamaremos cláusulas de un 
predicado tanto a los hechos como a las reglas. Una colección de cláusulas forma una 
Base de Conocimientos. 
 
 Ejemplos (ej01.pl): 
 
/* Conjunción de predicados */ 
le_gusta_a(clara,jorge), le_gusta_a(clara,chocolate). 
 
/* Disyunción de predicados */ 
le_gusta_a(clara,jorge); le_gusta_a(jorge,clara). 
 
/* Negación de predicados */ 
not(le_gusta_a(clara,jorge)). 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 8 © 1996-2001 Faraón Llorens 
/* o también como */ 
\+ le_gusta_a(clara,jorge). 
 
/* Condicional: REGLAS */ 
 
/* novios(Per1,Per2) <- Per1 y Per2 son novios */ 
novios(X,Y) :- le_gusta_a(X,Y), 
 le_gusta_a(Y,X). 
 
/* hermana_de(Per1,Per2) <- Per1 es la hermana de Per2 */ 
hermana_de(X,Y) :- mujer(X), 
 es_padre_de(P,X),es_madre_de(M,X), 
 es_padre_de(P,Y), es_madre_de(M,Y). 
 
/* Ejemplo de disyunción con ; y con diferentes cláusulas */ 
/* 1. con ; sería : */ 
es_hijo_de(X,Y) :- (es_padre_de(Y,X) ; es_madre_de(Y,X)). 
 
/* 2. con cláusulas diferentes quedaría: */ 
es_hijo_de(X,Y) :- es_padre_de(Y,X). 
es_hijo_de(X,Y) :- es_madre_de(Y,X). 
 PROLOG 
© 1996-2001 Faraón Llorens Página 9 
 
3. ESTRUCTURA DE UN PROGRAMA 
 
 El hecho de programar en Prolog consiste en dar al ordenador un Universo finito 
en forma de hechos y reglas, proporcionando los medios para realizar inferencias de un 
hecho a otro. A continuación, si se hacen las preguntas adecuadas, Prolog buscará las 
respuestas en dicho Universo y las presentará en la pantalla. La programación en Prolog 
consiste en: 
 
 • declarar algunos HECHOS sobre los objetos y sus relaciones, 
 • definir algunas REGLAS sobre los objetos y sus relaciones, y 
 • hacer PREGUNTAS sobre los objetos y sus relaciones. 
 
 Programa Prolog: Conjunto de afirmaciones (hechos y reglas) representando 
los conocimientos que poseemos en un determinado dominio o campo de nuestra 
competencia. 
 
 Ejecución del programa: Demostración de un Teorema en este Universo, es 
decir, demostración de que una conclusión se deduce de las premisas (afirmaciones 
previas). 
 
Programa Prolog 
Base de Conocimientos 
+ 
Motor de Inferencia 
 
 
 Un sistema Prolog está basado en un comprobador de teoremas por resolución 
para cláusulas de Horn. La regla de resolución no nos dice que cláusulas elegir ni que 
literales unificar dentro de cada cláusula. La estrategia de resolución particular que 
utiliza Prolog es una forma de resolución de entrada lineal (árbol de búsqueda 
estándar). Para la búsqueda de cláusulas alternativas para satisfacer el mismo objetivo, 
Prolog adopta una estrategia de primero hacia abajo (recorrido del árbol en 
profundidad). Por todo esto, el orden de las cláusulas (hechos y reglas) de un 
determinado procedimiento es importante en Prolog, ya que determina el orden en que 
las soluciones serán encontradas, e incluso puede conducir a fallos en el programa. Más 
importante es, si cabe, el orden de las metas a alcanzar dentro del cuerpo de una regla. 
 
3.1. PREGUNTAS 
 
 Las preguntas son las herramientas que tenemos para recuperar la información 
desde Prolog. Al hacer una pregunta a un programa lógico queremos determinar si esa 
pregunta es consecuencia lógica del programa. Prolog considera que todo lo que hay en 
la Base de Datos es verdad, y lo que no, es falso. De manera que si Prolog responde 
“yes” es que ha podido demostrarlo, y si responde “no” es que no lo ha podido 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 10 © 1996-2001 Faraón Llorens 
demostrar (no debe interpretarse como “falso” si no que con lo que Prolog conoce no 
puede demostrar su veracidad). 
 
 Cuando se hace una pregunta a Prolog, éste efectuará una búsqueda por toda la 
Base de Datos intentando encontrar hechos que coincidan con la pregunta. Dos hechos 
“coinciden” (se pueden unificar) si sus predicados son el mismo (se escriben de igual 
forma) y si cada uno de los respectivos argumentos son iguales entre sí. 
 
��?- simbolo_de_predicado(arg1,arg2,...,argn). 
 
 
 Ejemplos (ej01.pl): 
 
?- le_gusta_a(clara,jorge). 
yes 
 
?- le_gusta_a(jorge,cafe). 
no 
 
?- capital_de(madrid,españa). 
no 
 
 Cuando a Prolog se le hace una pregunta con una variable, dicha variable estará 
inicialmente no instanciada. Prolog entonces recorre la Base de Datos en busca de un 
hecho que empareje con la pregunta: los símbolos de predicado y el número de 
argumentos sean iguales, y emparejen los argumentos. Entonces Prolog hará que la 
variable se instancie con el argumento que esté en su misma posición en el hecho. 
Prolog realiza la búsqueda por la Base de Datos en el orden en que se introdujo. Cuando 
encuentra un hecho que empareje, saca por pantalla los objetos que representan ahora 
las variables, y marca el lugar donde lo encontró. Prolog queda ahora a la espera de 
nuevas instrucciones, sacando el mensaje “More (y/n) ?”5: 
- si pulsamos “n”+<RETURN> cesará la búsqueda, 
- si pulsamos “y”+<RETURN> reanudará la búsqueda comenzando donde había 
dejado la marca; decimos que Prolog está intentando resatisfacer la pregunta. 
 
 Ejemplos (ej01.pl): 
 
?- le_gusta_a(jorge,X). 
X=clara 
More (y/n)? y 
X=informatica 
More (y/n)? y 
no 
 
 La conjunción y el uso de variables pueden combinarse para hacer preguntas 
muy interesantes: 
 
?- le_gusta_a(clara,jorge),le_gusta_a(jorge,cafe). 
no 
?- le_gusta_a(clara,X),le_gusta_a(jorge,X). 
 
5 Depende de la implementación. Lo descrito aquí es como funciona el Prolog-2. El SWI-Prolog no saca mensaje y 
queda a la espera. Para activar la nueva búsqueda de soluciones basta con pulsar ";". Con <↵ > finaliza. 
 PROLOG 
© 1996-2001 Faraón Llorens Página 11 
X=informatica 
More (y/n)? n 
yes 
 
 Hemos buscado algo que le guste tanto a Clara como a Jorge. Para ello, primero 
averiguamos si hay algo que le guste a Clara, marcándolo en la Base de Conocimientos 
e instanciando la variable X. Luego, averiguamos si a Jorge le gusta ese objeto X ya 
instanciado. Si el segundo objetivo no se satisface, Prolog intentará resatisfacer el 
primer objetivo. Es importante recordar que cada objetivo guarda su propio marcador de 
posición. 
 
?- le_gusta_a(clara,informatica); le_gusta_a(jorge,cafe). 
yes 
?- le_gusta_a(clara,cafe); le_gusta_a(jorge,cafe). 
no 
?- le_gusta_a(clara,X); le_gusta_a(jorge,X). 
X=jorge 
More (y/n)? y 
X=informatica 
More (y/n)? y 
X=clara 
More (y/n)? y 
X=informatica 
More (y/n)? y 
no 
?- not(le_gusta_a(clara,jorge)). 
no 
?- not(le_gusta_a(jorge,cafe)). 
yes 
?- hermana_de(clara,borja). 
yes 
?- hermana_de(borja,X). 
no 
?- hermana_de(clara,X). 
X=borja 
More (y/n)? n 
yes 
 
 
 Ejercicio: 
 
 Piensa que ocurriría si a la pregunta de que si queremos más soluciones le 
contestamos que sí. ¿ Cómo lo solucionarías ? 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 12 © 1996-2001 Faraón Llorens 
 
4. SINTAXIS 
 
 La sintaxis de un lenguaje describe la forma en la que se nos está permitido 
juntar palabras entre sí. Los programas en Prolog se construyen a partir de términos. Un 
término es una constante, una variable o una estructura. Todo término se escribe como 
una secuencia de caracteres. Para escribir un comentario lo encerraremos entre los 
signos /* y */ o desde el símbolo % hasta el final de línea. Así, Prolog pasa por alto los 
comentarios, pero los debemos añadir a nuestros programas para aclararlos y que el 
propio programa quede documentado (Ver apartado 10.2 Estilo De Programación En 
Prolog). 
 
��/* ... comentario ... */ 
 
��% comentario de una sola línea 
 
 Ejemplo : 
 
/* Esto es un comentario 
 de más de una línea */ 
 
% mujer(Per) <- Per es una mujer 
mujer(clara). % Esto es también comentario 
mujer(chelo). 
 
 
4.1. CARACTERES 
 
 Los nombres de constantes y variables se construyen a partir de cadenas de 
caracteres. Prolog reconoce dos tipos de caracteres: 
 
• Imprimibles: hacen que aparezca un determinado signo en la pantalla del ordenador. 
Se dividen en cuatro categorías: 
letras mayúsculas: A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, 
V, W, X, Y, Z. 
letras minúsculas: a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z. 
dígitos numéricos: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. 
signos: ! " # $ % & ' ( ) = - ^ | / \ { } [ ] _ @ + * ; : < > , . ? 
 
• No imprimibles: no aparecen en forma de signo en la pantalla, pero realizan una 
determinada acción: nueva línea, retorno de carro, ... 
 
 Cada carácter tiene un entero entre 0 y 127 asociado a él, este es su código 
ASCII ("American Standard Code for Information Interchange"). 
 
 
 PROLOG 
© 1996-2001Faraón Llorens Página 13 
4.2. ESTRUCTURAS 
 
 Una estructura es un único objeto que se compone de una colección de otros 
objetos, llamados componentes, lo que facilita su tratamiento. Una estructura se escribe 
en Prolog especificando su nombre, y sus componentes (argumentos). Las componentes 
están encerradas entre paréntesis y separadas por comas; el nombre se escribe justo 
antes de abrir el paréntesis: 
 
nombre ( comp1, comp2, ..., compn ) 
 
 Por ejemplo, podemos tener una estructura con el nombre libro, que tiene tres 
componentes: titulo, autor y año de edición. A su vez el autor puede ser una estructura 
con dos componentes: nombre y apellido. 
 
libro(logica_informatica, autor(jose, cuena), 1985) 
 
 Como se puede ver, en Prolog, la sintaxis para las estructuras es la misma que 
para los hechos. Como podrás comprobar cuando trabajes más a fondo en Prolog, hay 
muchas ventajas en representar incluso los mismos programas Prolog como estructuras. 
Las estructuras se verán con más detalle en el apartado 8.3 Componentes De 
Estructuras. 
 
 
4.3. OPERADORES 
 
 En Prolog están predefinidos los operadores aritméticos y relacionales típicos, 
con la precedencia habitual entre ellos: 
 
^ 
mod 
* / 
+ - 
= \= =< >= < > 
 
 Para poder leer expresiones que contengan operadores necesitamos conocer los 
siguientes atributos: 
 
 * POSICIÓN: Prefijo: el operador va delante de sus argumentos. 
 Infijo: el operador se escribe entre los argumentos. 
 Postfijo: el operador se escribe detrás de sus argumentos. 
 
* PRECEDENCIA: Nos indica el orden en que se realizan las operaciones. El 
operador más prioritario tendrá una precedencia 1 y el 
menos, 1201 (depende de la implementación). 
 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 14 © 1996-2001 Faraón Llorens 
*ASOCIATIVIDAD: Sirve para quitar la ambigüedad en las expresiones en las 
que hay dos operadores, uno a cada lado del argumento, 
que tienen la misma precedencia. 
 
 
 Para conocer las propiedades de los operadores ya definidos podemos utilizar el 
predicado predefinido: 
 
��current_op(?Precedencia,?Especificador,?Nombre) 
 
donde: Precedencia es un entero indicando la clase de precedencia, 
 Especificador es un átomo indicando la posición y la asociatividad, y 
 Nombre es un átomo indicando el nombre que queremos que tenga el operador. 
 
 
Operador Símbolo Precedencia Especificador 
Potencia ^ ó ** 200 xfx 
Producto * 400 yfx 
División / 400 yfx 
División entera // 400 yfx 
Resto división entera mod 400 yfx 
Suma + 500 yfx 
Signo positivo + 500 fx 
Resta - 500 yfx 
Signo negativo - 500 fx 
Igualdad = 700 xfx 
Distinto \= 700 xfx 
Menor que < 700 xfx 
Menor o igual que =< 700 xfx 
Mayor que > 700 xfx 
Mayor o igual que >= 700 xfx 
Evaluación aritmética is 700 xfx 
Tabla 1: Operadores aritméticos y relacionales predefinidos en SWI-Prolog 
 
 Para la posición-asociatividad utilizamos átomos especiales del tipo: 
xfx xfy yfy yfx xf yf fx fy 
que nos ayudan a ver el uso del posible operador, representando f al operador, x un 
argumento indicando que cualquier operador del argumento debe tener una clase de 
precedencia estrictamente menor que este operador, e y un argumento indicando que 
puede contener operadores de la misma clase de precedencia o menor. 
 
 Ejemplo: 
 
El operador - declarado como yfx determina que la expresión a - b - c sea interpretada 
como (a - b) - c, y no como a - (b - c) ya que la x tras la f exige que el argumento que va tras el 
primer - contenga un operador de precedencia estrictamente menor: 
 
 7 - 3 - 2 (7 - 3) -2 = 4 - 2 = 2 correcta 
 PROLOG 
© 1996-2001 Faraón Llorens Página 15 
 7 - (3 - 2) = 7 - 1 = 6 incorrecta 
 
 Gráficamente sería: 
-
37
-
2 7
23
-
-
correcta incorrecta
 
 
 
 Si queremos declarar en Prolog un nuevo operador que sea reconocido por el 
sistema con una posición, clase de precedencia y asociatividad determinadas, 
utilizaremos el predicado predefinido op, cuya sintaxis es: 
 
��op(+Precedencia,+Especificador,+Nombre). 
 
 
 Al trabajar con expresiones aritméticas y relacionales, los argumentos de estas 
estructuras deben ser constantes numéricas o variables instanciadas a constantes 
numéricas. 
 
 
 Ejemplo (ej02.pl): 
 
/* horoscopo(Signo,DiaIni,MesIni,DiaFin,MesFin) <- 
 pertenecen al signo del horoscopo Signo los nacidos 
 entre el DiaIni del MesIni y el DiaFin del MesFin */ 
horoscopo(aries,21,3,21,4). 
horoscopo(tauro,21,4,21,5). 
horoscopo(geminis,21,5,21,6). 
horoscopo(cancer,21,6,21,7). 
horoscopo(leo,21,7,21,8). 
horoscopo(virgo,21,8,21,9). 
horoscopo(libra,21,9,21,10). 
horoscopo(escorpio,21,10,21,11). 
horoscopo(sagitario,21,11,21,12). 
horoscopo(capricornio,21,12,21,1). 
horoscopo(acuario,21,1,21,2). 
horoscopo(piscis,21,2,21,3). 
 
/* signo(Dia,Mes,Signo) <- los nacidos el Dia de Mes pertenecen al 
 signo del zodiaco Signo */ 
signo(Dia,Mes,Signo) :- horoscopo(Signo,D1,M1,D2,M2), 
 ( ( Mes=M1, Dia>=D1) ; ( Mes=M2, Dia=<D2) ). 
 
?- signo(8, 5, tauro). 
yes 
?- signo(7, 8, acuario). 
no 
?- signo(7, 8, Signo). 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 16 © 1996-2001 Faraón Llorens 
Signo=leo 
More (y/n)? y 
no 
 
 Ejercicio: 
 
 Piensa que ocurrirá si preguntamos ?- signo(7,X,Signo). 
 
Y si preguntamos ?- signo(X,7,Signo) . ¿ Por qué ? 
 
El ejemplo contesta afirmativamente a preguntas del tipo ?- signo(74,4,tauro). 
Modifica el ejemplo para que trabaje con el número de días correcto para cada mes. 
 
 
 Los operadores no hacen que se efectúe ningún tipo de operación aritmética. El 
predicado de evaluación es el operador infijo is: 
 
��-Numero is +Expresion 
 
donde: Expresion es un término que se interpreta como una expresión aritmética, 
con todos sus valores instanciados. 
 Numero puede ser una variable o una constante numérica. 
 
 Ejemplo (ej03.pl): 
 
/* poblacion(Prov,Pob) <- la población, en miles de habitantes, 
 de la provincia Prov es Pob */ 
poblacion(alicante,1149). 
poblacion(castellon,432). 
poblacion(valencia,2066). 
 
/* superficie(Prov,Sup) <- la superficie, en miles de km2, de la 
 provincia Prov es Sup */ 
superficie(alicante,6). 
superficie(castellon,7). 
superficie(valencia,11). 
 
/* densidad(Prov,Den) <- la densidad de población, habitantes/km2, 
 de la provincia Prov es Den */ 
densidad(X,Y) :- poblacion(X,P), 
 superficie(X,S), 
 Y is P/S. 
 
?- densidad(alicante, X). 
X=191’500 
 
?- 6=4+2. 
no 
?- 6 is 4+2. 
yes 
?- N is 4+2. 
N=6 
?- N is N+1. 
no 
?- N=4, N is 4+1. 
no 
 
 PROLOG 
© 1996-2001 Faraón Llorens Página 17 
 
 Prolog también incorpora funciones aritméticas (abs, sig, min, max, random, 
round, integer, float, sqrt, sin, cos, tan, log, log10, exp, ...). 
 
 Ejemplos: 
 
?- X is abs(-7.8). 
X=7.8 
?- X is min(9,2*3+1). 
X=7 
?- X is random(10). 
X=5 
?- X is random(10). 
X=6 
?- X is random(10). 
X=8 
?- X is sqrt(9). 
X=3 
?- X is sqrt(10). 
X=3.16228 
?- X is sin(2). 
X=0.909297 
?- X is sin(2*pi/4). 
X=1 
?- X is log(1000). 
X=6.90776 
?- X is log(e). 
X=1 
?- X is log(e**5). 
X=5 
?- X is log10(1000). 
X=3 
 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 18 © 1996-2001 Faraón Llorens 
 
5. ESTRUCTURAS DE DATOS 
 
5.1. ÁRBOLES 
 
 Es más fácil entender la forma de una estructura complicada si la escribimos 
como un árbol en el que el nombre es un nodo y los componentes son las ramas. 
 
 Ejemplo: libro(titulo(prolog), autores(clocksin, mellish)) 
 
libro
titulo autores
prolog clocksin mellish 
 
 
5.2. LISTAS 
 
 Las listas son unas estructuras de datos muy comunes en la programación no 
numérica. Una lista es una secuencia ordenada de elementos que puede tener cualquier 
longitud. Los elementos de una lista pueden ser cualquier término (constantes, variables, 
estructuras) uotras listas. 
 
 Las listas pueden representarse como un tipo especial de árbol. Una lista puede 
definirse recursivamente como: 
 * una lista vacía [], sin elementos, o 
 * una estructura con dos componentes: 
 cabeza: primer argumento 
 cola: segundo argumento, es decir, el resto de la lista. 
 
 El final de una lista se suele representar como una cola que contiene la lista 
vacía. La cabeza y la cola de una lista son componentes de una estructura cuyo nombre 
es “.”. 
 
 Ejemplo: 
 
 Así, la lista que contiene un solo elemento a es 
 
. ( a, [] ) 
 
y la lista de tres elementos [a, b, c] podría escribirse 
 
. ( a, . ( b, . ( c, [] ) ) ) 
 
 siempre terminando con la lista vacía. 
 PROLOG 
© 1996-2001 Faraón Llorens Página 19 
 
·
b
c
[]
[]
·
·
·
a a
 
 
 En Prolog utilizaremos una notación más sencilla de las listas que dispone a los 
elementos de la misma separados por comas, y toda la lista encerrada entre corchetes. 
Así, las listas anteriores quedarían como [a] y [a, b, c], que es un tipo de notación más 
manejable. Existe, también, una notación especial en Prolog para representar la lista con 
cabeza X (elemento) y cola Y (lista): 
 
��[ X | Y ] 
 
 Ejemplos: 
 
Lista Cabeza (elemento) Cola (lista) 
[a, b, c] A [b, c] 
[a] a [ ] 
[ ] (no tiene) (no tiene) 
[ [el, gato], maullo] [el, gato] [maullo] 
[el, [gato, maullo] ] el [ [gato, maullo] ] 
[el, [gato, maullo], 
ayer] 
el [ [gato, maullo], 
ayer] 
[X+Y, x+y] X+Y [x+y] 
 
 
 Diseño de procedimientos de manejo de listas: 
 
 Vamos a utilizar la técnica de refinamientos sucesivos para el diseño de 
procedimientos de manejo de listas. Como no sabemos de antemano el tamaño de las 
listas deberemos utilizar la recursividad para recorrer las listas. 
 
 Ejemplo: 
 
 Procedimiento miembro que comprueba si un determinado elemento pertenece a una 
lista. 
 
 Esquema de la relación: 
 miembro(Elem, Lista) <- el término Elem pertenece a la lista Lista 
 
 Definición intuitiva: 
 Una determinada carta está en un mazo de cartas si es la primera o si está en el resto 
del mazo. 
 
 1ª aproximación: traducción literal 
miembro(E,L) :- L=[X|Y]), X=E. 
miembro(E,L) :- L=[X|Y]), miembro(E,Y). 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 20 © 1996-2001 Faraón Llorens 
 
 2ª aproximación: recogida de parámetros 
miembro(E,[X|Y]) :- X=E. 
miembro(E,[X|Y]) :- miembro(E,Y). 
 
 3ª aproximación: unificación de variables 
miembro(X,[X|Y]). 
miembro(E,[X|Y]) :- miembro(E,Y). 
 
 4ª aproximación: ahorro de espacio en memoria (variable anónima) 
miembro(X,[X|_]). 
miembro(X,[_|Y]) :- miembro(X,Y). 
 
 
 Operaciones con listas: (ej04.pl) 
 
/* miembro(Elem,Lista) <- el término Elem pertenece a Lista */ 
miembro(X,[X|_]). 
miembro(X,[_|Y]) :- miembro(X,Y). 
 
/* nel(Lista,N) <- el numero de elementos de la lista Lista es N */ 
nel([],0). 
nel([X|Y],N) :- nel(Y,M), 
 N is M+1. 
 
/* es_lista(Lista) <- Lista es una lista */ 
es_lista([]). 
es_lista([_|_]). 
 
/* concatena(L1,L2,L3) <- concatenación de las listas L1 y L2 
 dando lugar a la lista L3 */ 
concatena([],L,L). 
concatena([X|L1],L2,[X|L3]) :- concatena(L1,L2,L3). 
 
/* ultimo(Elem,Lista) <- Elem es el ultimo elemento de Lista */ 
ultimo(X,[X]). 
ultimo(X,[_|Y]) :- ultimo(X,Y). 
 
/* inversa(Lista,Inver) <- Inver es la inversa de la lista Lista */ 
inversa([],[]). 
inversa([X|Y],L) :- inversa(Y,Z), 
 concatena(Z,[X],L). 
 
/* borrar(Elem,L1,L2) <- se borra el elemento Elem de la lista L1 
 obteniéndose la lista L2 */ 
borrar(X,[X|Y],Y). 
borrar(X,[Z|L],[Z|M]) :- borrar(X,L,M). 
 
/* subconjunto(L1,L2) <- la lista L1 es un subconjunto de lista L2 */ 
subconjunto([X|Y],Z) :- miembro(X,Z), 
 subconjunto(Y,Z). 
subconjunto([],Y). 
 
/* insertar(Elem,L1,L2) <- se inserta el elemento Elem en la lista L1 
 obteniéndose la lista L2 */ 
insertar(E,L,[E|L]). 
insertar(E,[X|Y],[X|Z]) :- insertar(E,Y,Z). 
 
/* permutacion(L1,L2) <- la lista L2 es una permutación de lista L1 */ 
permutacion([],[]). 
permutación([X|Y],Z) :- permutacion(Y,L), 
 insertar(X,L,Z). 
 PROLOG 
© 1996-2001 Faraón Llorens Página 21 
 
 Preguntas: 
 
?- miembro(d,[a,b,c,d,e]). 
yes 
 
?- miembro(d,[a,b,c,[d,e]]). 
no 
 
?- miembro(d,[a,b,c]). 
no 
 
?- miembro(E,[a,b]). 
E=a 
More (y/n)? y 
E=b 
More (y/n)? y 
no 
 
?- nel([a,b,[c,d],e],N). 
N=4 
 
?- es_lista([a,b,[c,d],e]). 
yes 
 
?- concatena([a,b,c],[d,e],L). 
L=[a,b,c,d,e] 
 
?- concatena([a,b,c],L,[a,b,c,d,e]). 
L=[d,e] 
 
?- concatena(L1,L2,[a,b]). 
L1=[], L2=[a,b] 
More (y/n)? y 
L1=[a], L2=[b] 
More (y/n)? y 
L1=[a,b], L2=[] 
More (y/n)? y 
no 
 
 Ejercicios: 
 
 1.- Comprueba el funcionamiento de las restantes operaciones con listas y prueba con 
diferentes tipos de ejemplos. 
 
 
 2.- Escribe un procedimiento que obtenga el elemento que ocupa la posición n de una 
lista o la posición que ocupa el elemento e: 
?- elemento(E,3,[a,b,c,d]). 
E=c 
 
?- elemento(c,N,[a,b,c,d]). 
N=3 
 
 
 3.- Modifica el procedimiento borrar para que borre el elemento que ocupa la posición n 
de la lista: 
?- borrar(3,[a,b,c,d],L). 
L=[a,b,d] 
 
 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 22 © 1996-2001 Faraón Llorens 
 Prolog ya incorpora procedimientos de manejo de listas (is_list, append, 
member, delete, select, nth0, nth1, last, reverse, flatten, length, merge, ...). 
Hemos visto como se definían algunos de ellos para comprender mejor su 
funcionamiento y que en un futuro seamos capaces de crear nuevos procedimientos a la 
medida que necesitemos. 
 
 Podemos utilizar predicados predefinidos de ordenación de listas: 
 
��sort(+Lista,-ListaOrdenada) 
��msort(+Lista,-ListaOrdenada) 
 
 Ordenan los elementos de la lista Lista y la devuelven en ListaOrdenada. El 
primero elimina los elementos repetidos, mientras que el segundo no. 
 
 Ejemplos: 
 
?- sort([b,f,a,r,t,r,h,a,r],L). 
L = [a, b, f, h, r, t] 
?- msort([b,f,a,r,t,r,h,a,r],L). 
L = [a, a, b, f, h, r, r, r, t] 
 
 
 PROLOG 
© 1996-2001 Faraón Llorens Página 23 
 
6. ESTRUCTURAS DE CONTROL 
 
6.1. RECURSIÓN 
 
 Las definiciones recursivas se encuentran frecuentemente en los programas 
Prolog. Fijémonos en cómo algunos predicados de manejo de listas vistos en el punto 
anterior están definidos recursivamente, es decir, el cuerpo de la cláusula se llama a sí 
mismo. En la recursividad debemos tener cuidado en que se cumplan las “condiciones 
de límite” (punto de parada cuando utilizamos recursividad). Podemos observar que en 
la llamada de la cláusula recursiva al menos uno de los argumentos crece o decrece, para 
así poder unificar en un momento dado con la cláusula de la condición de parada. 
 
 Ejemplo: 
 
 Procedimiento que calcula el número de elementos de una lista: 
� Condición de parada: lista vacía 
 nel([],0). 
� Evolución de los parámetros: lista con un elemento menos 
 nel([_|Y],N) :- nel(Y,M), N is M+1. 
 
 
 En la recursión encontramos dos partes: 
• la primera parte en la que descendemos y construimos el árbol hasta encontrar 
el valor que unifica con la condición de parada 
• una segunda parte en la que ascendemos por el árbol asignando valores a las 
variables que teníamos pendientes en las sucesivas llamadas. 
 
 Ejemplo: 
?- nel([a,[b,c],d],N).
?- nel([[b,c],d],M1).
?- nel([d],M2).
?- nel([],M3).
M3=0
M2=M3+1=1
M1=M2+1=2
N=M1+1=3
N=3
 
?- trace,nel([a,[b,c],d],N),notrace. 
 Call: ( 6) nel([a, [b, c], d], _G309) ? creep 
 Call: ( 7) nel([[b, c], d], _L104) ? creep 
 Call: ( 8) nel([d], _L117) ? creep 
 Call: ( 9) nel([], _L130) ? creep 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 24 © 1996-2001 Faraón Llorens 
 Exit: ( 9) nel([], 0) ? creep 
 ^ Call: ( 9) _L117 is 0 + 1 ? creep 
 ^ Exit: ( 9) 1 is 0 + 1 ? creep 
 Exit: ( 8) nel([d], 1) ? creep 
 ^ Call: ( 8) _L104 is 1 + 1 ? creep 
 ^ Exit: ( 8) 2 is 1+ 1 ? creep 
 Exit: ( 7) nel([[b, c], d], 2) ? creep 
 ^ Call: ( 7) _G309 is 2 + 1 ? creep 
 ^ Exit: ( 7) 3 is 2 + 1 ? creep 
 Exit: ( 6) nel([a, [b, c], d], 3) ? creep 
 
N = 3 
Yes 
 
?- trace(nel),nel([a,[b,c],d],N). 
 nel/2: call redo exit fail 
T Call: ( 7) nel([a, [b, c], d], _G292) 
T Call: ( 8) nel([[b, c], d], _L241) 
T Call: ( 9) nel([d], _L254) 
T Call: ( 10) nel([], _L267) 
T Exit: ( 10) nel([], 0) 
T Exit: ( 9) nel([d], 1) 
T Exit: ( 8) nel([[b, c], d], 2) 
T Exit: ( 7) nel([a, [b, c], d], 3) 
 
N = 3 
Yes 
 
 
 Deberemos tener cuidado de no escribir recursiones circulares (entrada en un 
bucle que no terminaría nunca) y de evitar la recursión a izquierdas (cuando una regla 
llama a un objetivo que es esencialmente equivalente al objetivo original), que causarían 
que Prolog no terminara nunca. 
 
 Recursión circular: 
 
padre(X,Y) :- hijo(Y,X). 
hijo(A,B) :- padre(B,A). 
 
 Recursión a izquierdas: 
 
persona(X) :- persona(Y), madre(X,Y). 
persona(adán). 
 
6.2. UNIFICACIÓN 
 
 La unificación («matching») aplicada junto con la regla de resolución es lo que 
nos permite obtener respuestas a las preguntas formuladas a un programa lógico. La 
unificación constituye uno de los mecanismos esenciales de Prolog, y consiste en buscar 
instancias comunes a dos átomos, uno de los cuales está en la cabeza de una cláusula y 
el otro en el cuerpo de otra cláusula. Prolog intentará hacerlos coincidir (unificarlos) 
mediante las siguientes reglas: 
 
• Una variable puede instanciarse con cualquier tipo de término, y naturalmente 
con otra variable. Si X es una variable no instanciada, y si Y está instanciada a 
 PROLOG 
© 1996-2001 Faraón Llorens Página 25 
cualquier término, entonces X e Y son iguales, y X quedará instanciada a lo 
que valga Y. Si ambas están no instanciadas, el objetivo se satisface y las dos 
variables quedan compartidas (cuando una de ellas quede instanciada también 
lo hará la otra). 
 
• Los números y los átomos sólo serán iguales a sí mismos. Evidentemente, 
también se pueden instanciar con una variable. 
 
• Dos estructuras son iguales si tienen el mismo nombre y el mismo número de 
argumentos, y todos y cada uno de estos argumentos son unificables. 
 
 El predicado de igualdad (=) es un operador infijo que intentará unificar ambas 
expresiones. Un objetivo con el predicado no igual (\=) se satisface si el = fracasa, y 
fracasa si el = se satisface. 
 
 Ejemplos: 
 
?- X=juan, X=Y. 
X=juan, Y=juan 
 
?- X=Y, X=juan. 
X=juan, Y=juan 
 
?- juan=juan. 
yes 
 
?- juan=pepe. 
no 
 
?- 1024=1024. 
yes 
 
?- 
amigo(pepe,juan)=amigo(pepe,X). 
X=juan 
 
?- amigo(pepe,juan)=Y. 
Y=amigo(pepe,juan) 
 
?- 9 \= 8. 
yes 
 
?- letra(C)=palabra(C). 
no 
 
?- 'juan'=juan. 
yes 
 
?- “juan”=juan. 
no 
 
?- f(X,Y)=f(A). 
no 
 
 
6.3. REEVALUACIÓN 
 
 La reevaluación («backtracking») consiste en volver a mirar lo que se ha hecho 
e intentar resatisfacer los objetivos buscando una forma alternativa de hacerlo. Si se 
quieren obtener más de una respuesta a una pregunta dada, puede iniciarse la 
reevaluación pulsando la tecla «y» cuando Prolog acaba de dar una solución y pregunta 
«More (y/n) ?», con lo que se pone en marcha el proceso de generación de soluciones 
múltiples. 
 
 Vamos a ver dos conceptos ya utilizados y relacionados directamente con la 
reevaluación: 
 
• Satisfacer un objetivo: cuando Prolog intenta satisfacer un objetivo, busca en la Base 
de Conocimientos desde su comienzo, y: 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 26 © 1996-2001 Faraón Llorens 
 
- si encuentra un hecho o la cabeza de una regla que pueda unificar con el 
objetivo, marca el lugar en la base de conocimientos e instancia todas las 
variables previamente no instanciadas que coincidan. Si es una regla lo 
encontrado, intentará satisfacer los subobjetivos del cuerpo de dicha regla. 
 
- si no encuentra ningún hecho o cabeza de regla que unifique, el objetivo ha 
fallado, e intentaremos resatisfacer el objetivo anterior. 
 
• Resatisfacer un objetivo: Prolog intentará resatisfacer cada uno de los subobjetivos 
por orden inverso, para ello intentará encontrar una cláusula alternativa para el 
objetivo, en cuyo caso, se dejan sin instanciar todas las variables instanciadas al 
elegir la cláusula previa. La búsqueda la empezamos desde donde habíamos dejado el 
marcador de posición del objetivo. 
 
 
 Ejemplo (ej05.pl): 
 
/* animal(Anim) <- Anim es un animal */ 
animal(mono). 
animal(gallina). 
animal(araña). 
animal(mosca). 
animal(cocodrilo). 
 
/* gusta(X,Y) <- a X le gusta Y */ 
gusta(mono,banana). 
gusta(araña,mosca). 
Gusta(alumno,logica). 
gusta(araña,hormiga). 
gusta(cocodrilo,X) :- animal(X). 
gusta(mosca,espejo). 
 
/* regalo(X,Y) <- Y es un buen regalo para X */ 
regalo(X,Y) :- animal(X), gusta(X,Y). 
 
?- regalo(X,Y). 
X=mono, Y=banana 
More (y/n)? y 
 
X=araña, Y=mosca 
More (y/n)? y 
 
X=araña, Y=hormiga 
More (y/n)? y 
 
X=mosca, Y=espejo 
More (y/n)? y 
 
X=cocodrilo, Y=mono 
More (y/n)? y 
 
X=cocodrilo, Y=araña 
More (y/n)? y 
 
X=cocodrilo, Y=mosca 
More (y/n)? y 
 
X=cocodrilo, Y=cocodrilo 
 PROLOG 
© 1996-2001 Faraón Llorens Página 27 
More (y/n)? y 
no 
 
 Ejercicio: 
 
 Alterar el orden de los hechos de la base de conocimientos anterior, añadir nuevos 
hechos y/o reglas y estudiar como se van generando las sucesivas respuestas. Intenta entender 
por qué Prolog genera estas respuestas y en este determinado orden (estrategias de 
resolución). Te puede ayudar si activas la opción de traza mediante el predicado predefinido 
trace, lo que te permitirá ir viendo los pasos que sigue prolog para obtener las distintas 
respuestas. 
 
 
6.4. EL CORTE 
 
 El corte permite decirle a Prolog cuales son las opciones previas que no hace 
falta que vuelva a considerar en un posible proceso de reevaluación. 
 
��! 
 
Es un mecanismo muy delicado, y que puede marcar la diferencia entre un 
programa que funcione y uno que no funcione. Su utilidad vienen dada por: 
 
- Optimización del tiempo de ejecución: no malgastando tiempo intentando 
satisfacer objetivos que de antemano sabemos que nunca contribuirán a una 
solución. 
 
- Optimización de memoria: al no tener que registrar puntos de reevaluación para 
un examen posterior. 
 
 El corte se representa por el objetivo “!” que se satisface inmediatamente y no 
puede resatisfacerse de nuevo. Es decir, se convierte en una valla que impide que la 
reevaluación la atraviese en su vuelta hacia atrás, convirtiendo en inaccesibles todos los 
marcadores de las metas que se encuentran a su izquierda. 
 
~~~, ! , ~~~ 
 
Se trata de una impureza en lo referente al control. Esto es, el control en Prolog 
es fijo y viene dado de forma automática por la implementación del lenguaje: recursión, 
unificación y reevaluación automática. De esta manera Prolog nos proporciona la 
ventaja de centrarnos en los aspectos lógicos de la solución, sin necesidad de considerar 
aspectos del control. Además, el corte puede conducirnos a programas difíciles de leer y 
validar. 
 
 Los usos comunes del corte se pueden dividir en tres áreas según la intención 
con la que lo hayamos colocado: 
 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 28 © 1996-2001 Faraón Llorens 
 1).- CONFIRMACIÓN DE LA ELECCIÓN DE UNA REGLA: se informa a 
Prolog que va por buen camino, por tanto, si ha pasado el corte ha encontrado la regla 
correcta para resolver el objetivo. Si las metas siguientes fracasan, deberá fracasar el 
objetivo. El uso del corte con esta finalidad es semejante a simular un “if-then-else” ( si 
b entonces c sino d ): 
 
 a :- b, !, c. 
 a :- d. 
 
que expresado sin utilizar el corte quedaría: 
 
 a :- b, c. 
 a :- not(b), d. 
 
en la cual puede que Prolog acabe intentando satisfacer b dos veces. Así, debemos 
sopesar las ventajas de un programa claro sin cortes frente a uno que sea más rápido. 
 
 Ejemplo (ej06.pl): 
 
/*sumatorio(Num,Sum) <- Sum es el sumatorio desde 1 hasta Num */ 
sumatorio(1,1) :- !. 
sumatorio(N,S) :- N1 is N-1, 
 sumatorio(N1,S1), 
 S is N+S1. 
 
 Ejercicio: 
 
 Estudia que ocurriría si no hubiésemos puesto el corte en la primera cláusula. 
 
 
 2).- ADVERTENCIA DE QUE SE VA POR MAL CAMINO: se informa a 
Prolog que haga fracasar el objetivo sin intentar encontrar soluciones alternativas. Se 
utiliza en combinación con el predicado de fallo fail, el cual siempre fracasa como 
objetivo, lo que hace que se desencadene el proceso de reevaluación. 
 
 3).- TERMINACIÓN DE LA GENERACIÓN DE SOLUCIONES MÚLTIPLES: 
se informa a Prolog que deseamos finalizar la generación de soluciones alternativas 
mediante reevaluación. 
 
 Ejemplo (ej06.pl): 
 
/* natural(Num) <- Num es un numero perteneciente a los Naturales */ 
natural(0). 
natural(X) :- natural(Y), 
 X is Y+1. 
 
/* diventera(Dividendo,Divisor,Cociente) <- Cociente es el resultado 
 de la division entera de Dividendo entre Divisor */ 
diventera(A,B,C) :- natural(C), 
 Y1 is C*B, 
 Y2 is (C+1)*B, 
 Y1 =< A, Y2 > A, !. 
 
 PROLOG 
© 1996-2001 Faraón Llorens Página 29 
 Este programa Prolog va generando números naturales hasta encontrar un C que 
cumpla la condición: 
B*C =< A < B*(C+1) 
siendo A el dividendo y B el divisor de la división. La regla natural va generando 
infinitos números naturales, pero sólo uno de ellos es el que nos interesa y será el que 
pase la condición. Así, el corte al final de la regla impide que en un posible proceso de 
reevaluación entremos en un bucle infinito: hemos encontrado la única solución y no 
hay ninguna razón para volver a buscar otra. 
 
 Discusión del "corte" 
 
 Mientras que un corte puede ser inofensivo, o incluso beneficioso, cuando se 
utiliza una regla de una forma dada, el mismo corte puede provocar un comportamiento 
extraño si la regla se utiliza de otra forma. Así, el siguiente predicado (ej06.pl): 
 
/* concatena(L1,L2,L3) <- concatenacion de las listas L1 y L2 
 dando lugar a la lista L3 */ 
concatena([],L,L) :- !. 
concatena([X|L1],L2,[X|L3]) :- concatena(L1,L2,L3). 
 
cuando consideramos objetivos de la forma 
 
 ?- concatena([a,b,c],[d,e],X). 
 X=[a,b,c,d,e] 
 ?- concatena([a,b,c],X,[a,b,c,d,e]). 
 X=[d,e] 
 
el corte resulta muy adecuado, pero si tenemos el objetivo 
 
 ?- concatena(X,Y,[a,b,c]). 
 X=[], Y=[a,b,c] 
 More (y/n)? y 
 no 
 
ante la petición de nuevas soluciones, la respuesta es “no”, aunque de hecho existan 
otras posibles soluciones a la pregunta. 
 
 La conclusión sería que si se introducen cortes para obtener un comportamiento 
correcto cuando los objetivos son de una forma, no hay garantía de que los resultados 
sean razonables si empiezan a aparecer objetivos de otra forma. Sólo es posible utilizar 
el corte de una forma fiable si se tiene una visión clara de cómo se van a utilizar las 
reglas. 
 
 Ejemplos de uso del corte (ej06.pl): 
 
/* borrar(Elem,L1,L2) <- L2 es la lista resultado de borrar todas las 
 ocurrencias del elemento Elem de la lista L1 */ 
borrar(_,[],[]). 
borrar(E,[E|L1],L2) :- !, borrar(E,L1,L2). 
borrar(E,[A|L1],[A|L2]) :- borrar(E,L1,L2). 
 
/* sust(E1,E2,L1,L2) <- L2 es la lista resultado de sustituir en lista 
 L1 todas las ocurrencias del elemento E1 por E2 */ 
sust(_,_,[],[]). 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 30 © 1996-2001 Faraón Llorens 
sust(E1,E2,[E1|L1],[E2|L2]) :- !, sust(E1,E2,L1,L2). 
sust(E1,E2,[Y|L1],[Y|L2]) :- sust(E1,E2,L1,L2). 
 
/* union(L1,L2,L3) <- L3 es la lista-conjunto unión de las 
 listas-conjuntos L1 y L2 */ 
union([],L,L). 
union([X|L1],L2,L3) :- miembro(X,L2), !, 
 union(L1,L2,L3). 
union([X|L1],L2,[X|L3]) :- union(L1,L2,L3). 
 
?- borrar(a,[a,b,c,d,a,b,a,d],L). 
L=[b,c,d,b,d] 
 
?- sust(a,b,[a,b,c,d,a,b],L). 
L=[b,b,c,d,b,b] 
 
?- union([a,b,c],[a,d,f,b],L). 
L=[c,a,d,f,b] 
 
 
6.5. PREDICADOS DE CONTROL 
 
Existen una serie de predicados predefinidos que ayudan cuando queremos 
utilizar estructuras de control. Vamos a ver alguno de ellos. 
 
��fail 
 
Siempre falla. 
 
��true 
 
Siempre tiene éxito 
 
��repeat 
 
Permite simular bucles junto con la combinación corte-fail. 
 
 Ejemplo (ej08.pl): 
 
 /*-----------------------------------------------------------*/ 
 /* PROGRAMA PRINCIPAL */ 
 
menu :- cabecera, 
 repeat, 
 leer(Formula), 
 hacer(Formula). 
 
hacer(X) :- integer(X), X=0. 
hacer('A') :- cabecera, ayuda, !, fail. 
hacer('a') :- cabecera, ayuda, !, fail. 
hacer(Formula) :- fbf(Formula), 
 formaNormal(Formula,FNC,FND), 
 escribirFormasNormales(FNC,FND),!, fail. 
 PROLOG 
© 1996-2001 Faraón Llorens Página 31 
 
 /* Fin Programa Principal */ 
 /*-----------------------------------------------------------*/ 
 
 
��+Condicion -> +Accion 
 
Permite simular la estructura condicional: Si-Entonces y Si-Entonces-Sino. 
 
 Ejemplo : 
 
ejemplo :- write(‘Escribe s o n’),nl, 
 read(Respuesta), 
 ( (Respuesta=’s’) -> 
 write(‘Has respondido afirmativamente’) 
 ; 
 write(‘Has respondido negativamente’) 
 ). 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 32 © 1996-2001 Faraón Llorens 
 
7. PREDICADOS DE ENTRADA Y SALIDA 
 
 Vamos a introducir una nueva ampliación sobre Prolog que no tiene nada que 
ver con la lógica. Hasta ahora, el único modo de comunicar información a y desde 
Prolog es a través del proceso de unificación entre nuestras preguntas y las cláusulas del 
programa. Pero puede que estemos interesados en una mayor interacción entre programa 
y usuario, aceptando entradas del usuario y presentando salidas al mismo. Así, aparecen 
los predicados de Entrada/Salida, que para mantener la consistencia del sistema 
cumplen: 
 
 - se evalúan siempre a verdad 
 - nunca se pueden resatisfacer: la reevaluación continua hacia la izquierda 
- tiene un efecto lateral (efecto no lógico durante su ejecución): entrada o salida 
de un carácter, término, ... 
 
 
7.1. LECTURA Y ESCRITURA DE TÉRMINOS 
 
��write(+Termino) 
 
Si Termino está instanciada a un término, lo saca por pantalla. Si Termino no 
está instanciada, se sacará por pantalla una variable numerada de forma única (por 
ejemplo _69). 
 
��nl 
 
Nueva Línea: la salida posterior se presenta en la siguiente línea de la pantalla. 
 
��write_ln(+Termino) 
 
Equivalente a write(+Termino),nl 
 
��writef(+Formato,+Argumentos) 
 
Escritura con formato 
 
��tab(+X) 
 
Desplaza el cursor a la derecha X espacios. X debe estar instanciada a un entero 
(una expresión evaluada como un entero positivo). 
 
 PROLOG 
© 1996-2001 Faraón Llorens Página 33 
��display(+Termino) 
 
Se comporta como “write”, excepto que pasa por alto cualquier declaración de 
operadores que se haya hecho. 
 
��read(-Termino) 
 
Lee el siguiente término que se teclee desde el ordenador. Debe ir seguido de un 
punto “.” y un “retorno de carro”. Instancia Termino al término leído, si Termino no 
estaba instanciada. Si Termino si que está instanciada, los comparará y se satisfará o 
fracasará dependiendo del éxito de la comparación. 
 
 
 Ejemplos (ej07.pl): 
 
/* ibl(L) <- imprime la lista L de forma bonita, es decir 
 saca por pantala los elementosa de la lista 
 separados por un espacio y terminado en salto 
 de línea */ 
ibl([]) :- nl. 
ibl([X|Y]) :- write(X), 
 tab(1), 
 ibl(Y). 
 
/* Diferencia entre write, display e ibl */ 
?- write(8+5*6), nl, display(8+5*6). 
8+5*6 
+(8,*(5,6)) 
yes 
 
?- write(8*5+6), nl, display(8*5+6). 
8*5+6 
+(*(8,5),6) 
yes 
 
?- X=[esto,es,una,lista],write(X),nl,display(X),nl,ibl(X). 
[esto,es,una,lista] 
.(esto,.(es,.(una,.(lista,[])))) 
esto es una listayes 
 
?- writef('Atomo = %w\nNúmero = %w\n',[pepe,4.5]). 
Atomo = pepe 
Número = 4.5 
yes 
 
 
7.2. LECTURA Y ESCRITURA DE CARACTERES 
 
 El carácter es la unidad más pequeña que se puede leer y escribir. Prolog trata a 
los caracteres en forma de enteros correspondientes a su código ASCII. 
 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 34 © 1996-2001 Faraón Llorens 
��put(+Caracter) 
 
Si Caracter está instanciada a un entero entre 0..255, saca por pantalla el carácter 
correspondiente a ese código ASCII. Si Caracter no está instanciada o no es entero, 
error. 
 
��get(-Caracter) 
 
Lee caracteres desde el teclado, instanciando Caracter al primer carácter 
imprimible que se teclee. Si Caracter ya está instanciada, los comparará satisfaciéndose 
o fracasando. 
 
��get0(-Caracter) 
 
Igual que el anterior, sin importarle el tipo de carácter tecleado. 
 
��skip(+Caracter) 
 
Lee del teclado hasta el carácter Caracter o el final del fichero. 
 
 
 Ejemplos (ej07.pl): 
 
/* escribe_cadena(L) <- escribe en pantalla la lista L de 
 códigos ASCII en forma de cadena de 
 caracteres */ 
escribe_cadena([]). 
escribe_cadena([X|Y]) :- put(X), 
 escribe_cadena(Y). 
 
?- escribe_cadena([80,114,111,108,111,103]). 
Prolog 
yes 
 
?- put(80),put(114),put(111),put(108),put(111),put(103). 
Prolog 
yes 
 
 
7.3. LECTURA Y ESCRITURA EN FICHEROS 
 
 Existe un fichero predefinido llamado user. Al leer de este fichero se hace que la 
información de entrada venga desde el teclado, y al escribir, se hace que los caracteres 
aparezcan en la pantalla. Este el modo normal de funcionamiento. Pero pueden 
escribirse términos y caracteres sobre ficheros utilizando los mismos predicados que se 
acaban de ver. La única diferencia es que cuando queramos escribir o leer en un fichero 
debemos cambiar el canal de salida activo o el canal de entrada activo, 
respectivamente. 
 PROLOG 
© 1996-2001 Faraón Llorens Página 35 
 
 Posiblemente queramos leer y escribir sobre ficheros almacenados en discos 
magnéticos. Cada uno de estos tendrá un nombre de fichero que utilizamos para 
identificarlo. En Prolog los nombres de ficheros se representan como átomos. Los 
ficheros tienen una longitud determinada, es decir, contienen un cierto número de 
caracteres. Al final del fichero, hay una marca especial de fin de fichero. Cuando la 
entrada viene del teclado, puede generarse un fin de fichero tecleando el carácter de 
control ASCII 26 o control-Z. Se pueden tener abiertos varios ficheros, si conmutamos 
el canal de salida activo sin cerrarlos (told), permitiéndonos escribir sobre ellos en 
varios momentos diferentes, sin destruir lo escrito previamente. 
 
��tell(+NomFichero) 
 
Si NomFichero está instanciada al nombre de un fichero, cambia el canal de 
salida activo. Crea un nuevo fichero con ese nombre. Si NomFichero no está instanciada 
o no es un nombre de fichero, producirá un error. 
 
��telling(?NomFichero) 
 
Si NomFichero no está instanciada, la instanciará al nombre del fichero que es el 
canal de salida activo. Si NomFichero está instanciada, se satisface si es el nombre del 
fichero actual de salida. 
 
��told 
 
Cierra el fichero para escritura, y dirige la salida hacia la pantalla. 
 
��see(+NomFichero) 
 
Si NomFichero está instanciada al nombre de un fichero, cambia el canal de 
entrada activo al fichero especificado. La primera vez que se satisface, el fichero pasa a 
estar abierto y empezamos al comienzo del fichero. Si NomFichero no está instanciada o 
no es un nombre de fichero, producirá un error. 
 
��seeing(?NomFichero) 
 
Si NomFichero no está instanciada, la instanciará al nombre del fichero que es el 
canal de entrada activo. Si NomFichero está instanciada, se satisface si es el nombre del 
fichero actual de entrada. 
 
��seen 
 
Cierra el fichero para lectura, y dirige la entrada hacia el teclado. 
 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 36 © 1996-2001 Faraón Llorens 
 
 
 Ejemplos: 
 
/* Secuencia normal de escritura */ 
... , tell(fichero), write(X), told, ... 
 
/* Conmutación de ficheros */ 
... , tell(fichero), write(A), tell(user), write(B), 
 tell(fichero), write(C), told. 
 
/* Secuencia normal de lectura */ 
... , see(fichero), read(X), seen, ... 
 PROLOG 
© 1996-2001 Faraón Llorens Página 37 
 
8. MODIFICACIÓN DE LA BASE DE CONOCIMIENTOS 
 
 
 Vamos a estudiar una serie de predicados predefinidos en Prolog que nos 
permitirán manipular la Base de Conocimientos consultando, añadiendo, eliminando o 
modificando cláusulas. 
 
 
8.1. ADICIÓN DE BASES DE CONOCIMIENTO EXTERNAS 
 
 En Prolog los ficheros se utilizan principalmente para almacenar programas y no 
perderlos al apagar el ordenador. Si queremos que Prolog lea nuevas cláusulas de un 
fichero que hemos preparado previamente, podemos utilizar los predicados consult y 
reconsult. Esto será conveniente cuando tengamos que trabajar con programas de 
tamaño considerable y no queramos teclear cada vez todas las cláusulas. Así, podremos 
crear el programa con un editor de textos y guardarlo para posteriores usos, con la 
ventaja añadida de que lo podremos modificar y ampliar en cualquier momento. 
 
��consult(+Fichero) 
 
 El predicado predefinido consult añade las cláusulas existentes en el fichero de 
nombre Fichero a la base de conocimientos de Prolog, al final de las ya existentes, sin 
destruir las anteriores. Como argumento pasamos un átomo con el nombre del fichero 
del que queremos leer las cláusulas. Recordemos que un átomo está formado por letras, 
dígitos y el carácter subrayado. Si queremos que contenga otros caracteres (los dos 
puntos «:» para la unidad, la barra invertida «\» para el directorio o el punto «.» para la 
extensión6) deberemos encerrarlo entre comillas simples. 
 
��reconsult(+Fichero) 
 
 El predicado predefinido reconsult actúa como el consult excepto que, de existir 
cláusulas para un mismo predicado (nombre y aridad), las nuevas sustituyen a las 
existentes7. Se suele utilizar para la corrección de errores mientras se está realizando el 
programa, ya que de esta manera la nueva versión sustituye a la anterior errónea. 
También es interesante cuando queremos asegurarnos que se utilizan las cláusulas que 
vamos a leer, y no otras posibles con el mismo nombre que tuviese el sistema de alguna 
consulta anterior. 
 
 
6 Por defecto, SWI-Prolog asume la extensión «.pl» y Prolog-2 toma la extensión «.pro». Pero esto dependerá del 
sistema Prolog utilizado y se puede personalizar. 
 
7 SWI-Prolog no tiene un predicado resonsult, ya que al consultar un fichero ya almacenado, automáticamente es 
reconsultado 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 38 © 1996-2001 Faraón Llorens 
 La mayor parte de las implementaciones permiten una notación especial que 
permite consultar una lista de ficheros, uno tras otro: la notación en forma de lista. 
Consiste en poner los nombres de los ficheros en una lista y darla como objetivo a 
satisfacer. Si se quiere consultar un fichero, se pone el nombre en la lista tal cual, 
mientras que si se quiere reconsultar se pone el nombre precedido de un signo “-”. 
 
 Ejemplos: 
 
?- consult(fichero). 
fichero consulted 
 
?- reconsult(fichero). 
fichero reconsulted 
 
?- [fichero1,-fichero2,-'prueba','a:prueba2']. 
fichero1 consulted 
fichero2 reconsulted 
prueba reconsulted 
a:prueba2 consulted 
 
?- consult(‘prac1.pro’). 
prac1.pro consulted 
 
?- reconsult(‘a:prac1’). 
a:prac1 reconsulted 
 
?- [‘lpo\prac1’]. 
lpo\prac1 consulted 
 
?- [-‘a:\lpo\prac1.pro’]. 
a:\lpo\prac1.pro reconsulted 
 
 
8.2. MANIPULACIÓN DE LA BASE DE CONOCIMIENTOS 
 
 Veamos ahora los predicados predefinidos que podemos utilizar para ver 
(listing), obtener (clause), añadir (assert) o quitar (retract y abolish)cláusulas de 
nuestra base de conocimientos: 
 
��listing 
��listing(+Predicado) 
 
 Todas las cláusulas que tienen como predicado el átomo al que está instanciada 
la variable Predicado son mostradas por el fichero de salida activo (por defecto la 
pantalla). El predicado de aridad 0 listing (sin parámetro) muestra todas las cláusulas de 
la Base de Conocimientos. 
 
 Ejemplos : 
 
?- listing(asignatura). 
/* asignatura/1 */ 
asignatura(logica) . 
 PROLOG 
© 1996-2001 Faraón Llorens Página 39 
asignatura(programacion) . 
asignatura(matematicas) . 
/* asignatura/2 */ 
asignatura(logica,lunes) . 
asignatura(programacion,martes) . 
asignatura(matematicas,miercoles) . 
yes 
 
?- listing(asignatura/2). 
asignatura(logica,lunes) . 
asignatura(programacion,martes) . 
asignatura(matematicas,miercoles) . 
yes 
 
 
��clause(?Cabeza,?Cuerpo) 
 
 Se hace coincidir Cabeza con la cabeza y Cuerpo con el cuerpo de una cláusula 
existente en la Base de Conocimientos. Por lo menos Cabeza debe estar instanciada. Un 
hecho es considerado como una cláusula cuyo cuerpo es true. 
 
 
��assert(+Clausula) 
��asserta(+Clausula) 
��assertz(+Clausula) 
 
 Estos predicados permiten añadir nuevas cláusulas a la base de conocimientos. 
El predicado asserta la añade al principio (letra «a») y assertz la añade al final (letra 
«z») de cualquier otra cláusula del mismo tipo que hubiese en la base de conocimientos. 
En todos los casos, Clausula debe estar previamente instanciada a una cláusula. Dicha 
cláusula queda incorporada a la base de conocimientos y no se pierde aunque se haga 
reevaluación. 
 
 Ejemplos : 
 
?- asignatura(X) 
no 
 
?- assert(asignatura(logica)). 
yes 
 
?- asserta(asignatura(matematicas)). 
yes 
 
?- assertz(asignatura(programacion)). 
yes 
 
?- asignatura(X). 
X = matematicas 
More (y/n)? y 
X = logica 
More (y/n)? y 
X = programacion 
More (y/n)? y 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 40 © 1996-2001 Faraón Llorens 
no 
 
 
��retract(+Clausula) 
��retractall(+Clausula) 
 
 Este predicado nos permite eliminar una cláusula de nuestra base de 
conocimientos. Para ello, Clausula debe estar instanciada y se quitará la primera 
cláusula de la base de conocimientos que empareje con ella. Si se resatisface el objetivo, 
se irán eliminando, sucesivamente, las cláusulas que coincidan. Con retractall se 
eliminarán todas. 
 
 Ejemplos : 
 
?- listing(asignatura). 
/* asignatura/1 */ 
asignatura(matematicas) . 
asignatura(logica) . 
asignatura(programacion) . 
yes 
 
?- retract(asignatura(logica)). 
yes 
 
?- listing(asignatura). 
/* asignatura/1 */ 
asignatura(matematicas) . 
asignatura(programacion) . 
yes 
 
?- retract(asignatura(X)). 
X = matematicas 
More (y/n)? n 
yes 
 
?- listing(asignatura). 
/* asignatura/1 */ 
asignatura(programacion) . 
yes 
 
 
��abolish(+Predicado/Aridad) 
��abolish(+Predicado,+Aridad) 
 
 Retira de la Base de Conocimientos todas las cláusulas del predicado Predicado. 
Debe estar identificado completamente el predicado : nombre y aridad. 
 
 Ejemplos : 
 
?- listing(asignatura). 
/* asignatura/1 */ 
asignatura(logica) . 
asignatura(programacion) . 
 PROLOG 
© 1996-2001 Faraón Llorens Página 41 
asignatura(matematicas) . 
/* asignatura/2 */ 
asignatura(logica,lunes) . 
asignatura(programacion,martes) . 
asignatura(matematicas,miercoles) . 
yes 
 
?- abolish(asignatura/1). 
yes 
 
?- listing(asignatura). 
/* asignatura/2 */ 
asignatura(logica,lunes) . 
asignatura(programacion,martes) . 
asignatura(matematicas,miercoles) . 
yes 
 
?- abolish(asignatura,2). 
yes 
 
?- listing(asignatura). 
yes 
 
 
8.3. COMPONENTES DE ESTRUCTURAS 
 
 Como ya hemos comentado anteriormente Prolog considera los hechos y las 
reglas, e incluso los mismos programas, como estructuras. Veamos ahora una de sus 
ventajas : el considerar a las propias cláusulas como estructuras nos permite 
manipularlas (construir, modificar, eliminar, añadir, ...) con los predicados de 
construcción y acceso a los componentes de las estructuras functor, arg, =.. y name. 
 
 Así, la siguiente regla la considera Prolog constituida como la estructura de la 
figura : 
 
abuelo(Abuelo, Nieto) :- padre(Abuelo, Padre), padre(Padre, Nieto). 
 
:-
abuelo
Abuelo
,
Padre
padrepadre
Padre
Nieto
NietoAbuelo
 
 
��functor(?Estructura,?Nombre,?Aridad) 
 
 Estructura es una estructura con nombre Nombre y aridad (número de 
argumentos) Aridad. Se puede utilizar básicamente de dos maneras : 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 42 © 1996-2001 Faraón Llorens 
- teniendo Estructura instanciada, y por tanto hace corresponder a Nombre con el 
nombre de dicha estructura y Aridad con un entero que indica el número de 
argumentos. 
- cuando Nombre y Aridad están instanciados, por lo que Estructura queda 
instanciada a una estructura con el nombre y el número de argumentos dados. 
 
 Ejemplos : 
 
?- functor(logica,F,N). 
F = logica, N = 0 
 
?- functor(3+2,F,N). 
F = +, N = 2 
 
?- functor([a,b,c],F,N). 
F = . , N = 2 
 
?- functor(E,libro,2). 
E = libro(_,_) 
 
?- functor(3+2+1,+,3). 
no 
 
?- functor(3+2+1,+,2). 
yes 
 
��arg(?Posicion,?Estructura,?Argumento) 
 
 El argumento de la estructura Estructura que ocupa la posición Posicion es 
Argumento. Se debe utilizar con, por lo menos, los dos primeros argumentos 
instanciados, y sirve para acceder a un determinado argumento de una estructura. 
 
 Ejemplos : 
 
?- arg(2,1+2+3,Arg). 
Arg = 1+2 
 
?- arg(1,[a,b,c],Arg). 
Arg = a 
 
?- arg(2,p(x,f(y)),Arg). 
Arg = f(y) 
 
?- arg(1,asignatura(logica,lunes),logica). 
yes 
 
��?Estructura =.. ?Lista 
 
 El predicado univ (=..) nos permite acceder a argumentos de estructuras de las 
que no conocemos de antemano el número de componentes. Si Estructura está 
instanciada, Lista será una lista cuyo primera componente (cabeza) es el functor de la 
estructura y el resto (cola) los distintos argumentos de dicha estructura. Si Lista está 
instanciada, creará una estructura cuyo functor será la cabeza de la lista, y cuyos 
argumentos serán los distintos elementos de la lista. 
 PROLOG 
© 1996-2001 Faraón Llorens Página 43 
 
 Ejemplos : 
 
?- p(x,f(y),z) =.. L. 
L = [p,x,f(y),z] 
 
?- E =.. [+,2,3]. 
E = 2+3 
 
?- Clausula =.. [asignatura,logica,lunes,11]. 
Clausula = asignatura(logica,lunes,11) 
 
 
��name(?Atomo,?Lista) 
 
 Atomo es un átomo formado por los caracteres de la lista Lista (códigos ASCII). 
Puede, tanto crear un átomo con los caracteres de la lista de códigos ASCII, como crear 
la lista de caracteres correspondientes al átomo. 
 
 Ejemplos : 
 
?- name(logica,L). 
L = “logica” 
 
?- name(Atomo,[80,114,111,108,111,103]). 
Prolog 
 
?- name(hola,“hola”). 
yes 
 
LÓGICA DE PRIMER ORDEN, LÓGICA COMPUTACIONAL y AMPLIACIÓN DE LÓGICA 
Página 44 © 1996-2001 Faraón Llorens 
 
9. DEPURACIÓN DE PROGRAMAS PROLOG 
 
 Por último, veremos una serie de predicados predefinidos para supervisar el 
funcionamiento de los programas Prolog durante su ejecución que nos permitirán la 
depuración y corrección de nuestros programas, ya que es raro que nuestros programas 
funcionen a la primera. Muchos de estos errores son fácilmente identificables y por 
tanto se pueden corregir sin dificultad. En cambio hay tipos de errores difíciles de 
detectar, y siempre es de agradecer cualquier tipo de ayuda que nos pueda prestar el 
interprete. Estos predicados son : trace, notrace, spy, nospy, debugging, debug y 
nodebug. 
 
 Los errores en programación pueden ser clasificados en dos grandes grupos : 
errores sintácticos y errores semánticos. 
 
• Los errores sintácticos hacen referencia a la estructura gramatical de las 
sentencias (falta del punto al final de un hecho o una regla, no cerrar comillas 
en una cadena, ...), y Prolog nos informa de ellos inmediatamente que 
consultamos el programa. La gran mayoría de los errores cometidos son de 
este tipo, pero sin embargo son fáciles de localizar y corregir. 
Ejemplo : 
hombre[jorge).

Continuar navegando

Materiales relacionados