Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

42
Ingenier´ ıa de Requerimientos (IDR) (pr´ acticas) Facultad de Inform´ atica - 4A El lenguaje de programaci´ on Visual Prolog Javier Ib´ nez (Despacho D-109) Germ´ an Vidal (Despacho D-242) Edificio DSIC Curso 2005/2006

Transcript of Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Page 1: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Ingenierıa de Requerimientos (IDR)

(practicas)

Facultad de Informatica - 4A

El lenguaje de programacion Visual Prolog

Javier Ibanez (Despacho D-109)

German Vidal (Despacho D-242)

Edificio DSIC

Curso 2005/2006

Page 2: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Parte I

Presentacion del lenguaje

1

Page 3: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

1.- Caracterısticas del lenguaje

Visual Prolog es un lenguaje de programacion de quinta generacion especialmenteorientado al desarrollo de aplicaciones de bases de datos, interfaces basadas en lenguajenatural, parsers y compiladores, sistemas expertos, etc.

Los tiempos de desarrollo de una aplicacion en Visual Prolog pueden llegar a serhasta 10 veces menor que en otro lenguaje de programacion como C o Pascal, debidoal alto nivel de abstraccion del lenguaje. Pese a ello, dispone de un compilador capazde generar codigo maquina tan eficiente como un buen compilador de C.

Por otro lado, Visual Prolog es un lenguaje “abierto”, es decir, permite generarrutinas que se pueden invocar desde aplicaciones escritas en C, C++ o ensamblador.De forma analoga, una aplicacion en Visual Prolog puede invocar rutinas escritas enlos lenguajes C, C++, Pascal o ensamblador.

2.- Caracterısticas del entorno

Visual Prolog dispone de las siguientes herramientas:

Entorno de Desarrollo Visual (VDE): es una herramienta para asistir al programadoren el desarrollo, depuracion y mantenimiento de las aplicaciones, ası como en eluso de los recursos graficos. Incorpora herramientas para crear y mantener elcodigo asociado a las ventanas, dialogos, menus, etc.

Interfaz de Programacion Visual (VPI): consiste en dominios y predicados (inde-pendientes de la plataforma hardware) para el manejo de dialogos, ventanas,facilidades para dibujo, para el manejo de menus, ası como todas las facilidadesde la API (Application Programming Interface) de la plataforma subyacente.

Visual Prolog permite desarrollar aplicaciones para MS DOS, Extended DOS,Windows 3.1, Windows 3.11, Windows 95, Windows NT y para las versiones de16 y 32 bits de OS/2. El codigo generado es portable de una plataforma a otradirectamente.

Dispone de editores graficos para la preparacion de ventanas, dialogos, bitmaps,iconos, etc.

Dispone de un editor sensible al lenguaje (Prolog y C).

El compilador incorpora distintos analisis de programas (e.g. determinismo) yrealiza varios tipos de optimizaciones de codigo (asignacion de registros, LCO,“peep-hole”, etc.)

Incorpora un gestor de base de datos con mas de 50 predicados para desarrollar ymantener grandes bases de datos compartidas (permitiendo el acceso multiusuarioa los ficheros).

2

Page 4: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Interfaz con otros lenguajes: Visual Prolog permite generar rutinas que se puedenllamar desde otros lenguajes (C, C++, Pascal y ensamblador), ası como invocarrutinas escritas en otros lenguajes. Ası, se permite el desarrollo de aplicacionesmultilenguaje, de forma que el programador pueda aprovechar lo mejor de cadalenguaje de programacion.

3.- ¿Para que se puede usar Visual Prolog?

Las principales aplicaciones para las que el lenguaje resulta particularmente ade-cuado son:

Desarrollo de prototipos

Procesadores de lenguajes: tanto lenguajes de programacion (desarrollo de inter-pretes o compiladores) como lenguaje natural

Construccion de interfaces para el lenguaje natural, permitiendo extender ası lasaplicaciones existentes con una interfaz mucho mas amigable

Implementacion de Bases de Datos, empleando el mismo lenguaje de programacionpara el desarrollo de la aplicacion y para la gestion de la BD

Construccion de sistemas expertos

Generacion de planes

Control y monitorizacion de procesos industriales

Simulacion, Investigacion Operativa, etc.

4.- ¿En que se diferencia Prolog de otros lenguajes?

Prolog es declarativo: en lugar de especificar paso a paso como debe trabajar elordenador, un programa Prolog consta de una descripcion del problema.

Prolog usa hechos y reglas, es decir, un programa esta formado por una lista desentencias logicas.

Prolog puede realizar deducciones a partir de los hechos y reglas del programa.

El control en la ejecucion de un programa Prolog es automatico, en oposicion a lapractica mayorıa de lenguajes de programacion.

Prolog tiene una sintaxis muy simple, lo que simplifica mucho su aprendizaje.

Prolog es un lenguaje de muy alto nivel: una aplicacion Prolog contiene, en gen-eral, una decima parte de las instrucciones necesarias para desarrollar la mismaaplicacion en C o Pascal.

3

Page 5: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Parte II

Fundamentos de Prolog

4

Page 6: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

1.- PROgramando en LOGica

En Prolog, las soluciones se alcanzan deduciendo logicamente una cosa de algo yaconocido. Un programa Prolog no es una secuencia de acciones, sino una coleccion dehechos, junto con una secuencia de reglas para extraer conclusiones a partir de loshechos.

Prolog es un lenguaje declarativo, lo que significa que un programa escrito en Prologesta mucho mas cercano al lenguaje natural que los lenguajes imperativos (Basic, C,Pascal, etc).

El lenguaje incluye una maquina de inferencia, que no es mas que un procedimientogeneral para razonar acerca de la informacion. Esta maquina de inferencia se encarga deresponder a las preguntas que se realicen al sistema, intentando deducir la informaciona partir de los hechos conocidos y de las reglas del programa.

Aunque Prolog no permite escribir programas mediante sentencias del lenguaje nat-ural (el compilador serıa increiblemente complejo), la sintaxis esta bastante cercana.Concretamente, se usa un subconjunto de la logica de predicados para representar lainformacion. Por ejemplo:

Lenguaje natural: Logica de PredicadosUn coche es divertido. divertido(coche).Una rosa es roja. roja(rosa).

A Juan le gusta un coche si es divertido. gusta(juan,Coche) si divertido(Coche).

1.1. Sentencias: hechos y reglas

Un programador de Prolog define objetos y relaciones. Luego, define cuando dichasrelaciones son ciertas. Por ejemplo, la sentencia:

Juan tiene un perro.

muestra una relacion entre los objetos “Juan” y “perro”; la relacion es “tiene”. Unaposible regla para definir cuando la sentencia anterior es cierta, es:

Juan tiene un perro si el perro es un pastor aleman.

Hechos: lo que es conocido

En Prolog, una relacion entre objetos recibe el nombre de predicado. En el lenguajenatural, una relacion se expresa mediante sentencias. Por ejemplo:

Juan tiene un perro.Elena tiene un coche.Juan tiene un libro.

5

Page 7: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Por el contrario, en Prolog usamos un sımbolo de predicado que contiene (entre parente-sis) los distintos objetos a los que afecta dicho predicado. Por ejemplo, las tres sentenciasanteriores se expresarıan ası:

tiene(juan,perro).tiene(elena,coche).tiene(juan,libro).

Los hechos no solo pueden expresar relaciones entre objetos, sino tambien propiedadesde los mismos. Por ejemplo, las sentencias del lenguaje natural “Juan es alto.” o “Elenaes rubia.” se expresarıan en Prolog ası:

alto(juan).rubia(elena).

Reglas: lo que se puede inferir de los hechos

Las reglas nos permiten deducir hechos a partir de otros hechos. Por ejemplo, dadaslas reglas:

Pedro tiene todo lo que tiene Juan.Ana es rubia si lo es Elena.

y los hechos anteriores, podemos deducir los nuevos hechos:

Pedro tiene un perro.Pedro tiene un libro.Ana es rubia.

Las reglas anteriores se codificarıan en Prolog ası:

tiene(pedro,Algo) :- tiene(juan,Algo).rubia(ana) :- rubia(elena).

El sımbolo “:-” se pronuncia simplemente “si”, y sirve para separar las dos partes dela regla: la cabeza y el cuerpo. Desde el punto de vista logico, el sımbolo “:-” equivalea una implicacion de derecha a izquierda (⇐=).

1.2. Consultas

Una vez que Prolog dispone de una serie de hechos y reglas, podemos proceder arealizar consultas (“queries”) al sistema. Por ejemplo, podemos preguntar cosas como:

6

Page 8: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Juan tiene un perro?

que, codificado en Prolog, es:

tiene(juan,perro).

Dada esta consulta, Prolog responde:

yes

ya que existe un hecho que dice exactamente eso. De la misma forma, podemos pre-guntar:

Que tiene Juan?

que, en la sintaxis de Prolog, es:

tiene(juan,Que).

Fijaos en que juan comienza en minuscula, mientras que Que comienza en mayuscula. Elmotivo es que juan es un objeto constante, mientras que Que representa una variable. EnProlog, las variables siempre comienzan con una letra mayuscula o con un subrayado.

Prolog siempre responde a las consultas buscando hechos (o reglas) adecuados desdeel principio del programa hasta el final. Concretamente, las respuestas de Prolog a laconsulta anterior son:

Que = perroQue = libro2 Solutions

ya que ha encontrado los hechos:

tiene(juan,perro).tiene(juan,libro).

Si le preguntamos a Prolog:

Que tiene Pedro?

tiene(pedro,Que).

el sistema contesta:

Que = perro

7

Page 9: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Que = libro2 Solutions

ya que Prolog sabe que Pedro tiene lo mismo que Juan, y Juan tiene un perro y unlibro.

Ejemplo

Cargad el programa ch02e01.pro1 en el sistema Prolog y ejecutarlo:

PREDICATESnondeterm likes(symbol,symbol)

CLAUSESlikes(ellen,tennis).likes(john,football).likes(tom,baseball).likes(eric,swimming).likes(mark,tennis).likes(bill,Activity) :- likes(tom, Activity).

GOALlikes(bill,baseball).

El sistema contesta con yes. Lo que ha hecho es combinar la regla:

likes(bill,Activity) :- likes(tom, Activity).

con el hecho:

likes(tom,baseball).

para deducir que:

likes(bill,baseball).

Probad ahora con esta consulta:

likes(bill,tennis).

El sistema contesta no, ya que:

1. no hay ningun hecho que afirme que a Bill le gusta el tenis, y

2. usando la regla del programa y los hechos, no es posible deducirlo.1Se encuentra en el directorio Vip\Doc\Lang\Examples.

8

Page 10: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

1.3. Variables: sentencias generales

El uso de variables en Prolog nos permite escribir sentencias de caracter general.Por ejemplo, la sentencia “Pedro tiene todo lo que tiene Juan” se puede escribir enProlog ası:

tiene(pedro,Algo) :- tiene(juan,Algo).

Recordad que las variables deben comenzar por un caracter en mayuscula o por unsubrayado (‘ ’).

2.- Del lenguaje natural a los programas Prolog

2.1. Clausulas: hechos y reglas

En Prolog, existen unicamente dos tipos de “sentencias”: hechos y reglas. Am-bos tipos de sentencias se conocen como clausulas. El nucleo de un programa Prologesta compuesto por una secuencia de clausulas.

Mas acerca de los hechos

Un hecho representa una instancia simple de una propiedad de un objeto o unarelacion entre objetos.

Prolog no necesita mirar en ningun otro sitio para confirmar la validez de un hecho.Ademas, los hechos pueden utilizarse para realizar deducciones (mediante reglas).

Mas acerca de las reglas

Las reglas sirven para describir lo que se puede deducir a partir de otra informa-cion. Es decir, una regla indica que una propiedad (o relacion) es cierta si ciertaspropiedades (o relaciones) son ciertas.Veamos algunos ejemplos de reglas:

1. Considerad la frase del lenguaje natural:

Diana es vegetariana y solo come lo que su doctor le ha dicho que coma.

Dado un menu y la regla anterior, es posible concluir si Diana puede ordenar undeterminado item del menu o no. Esta regla se podrıa escribir en Prolog ası:

diana_puede_comer(Item) :- vegetal(Item), en_lista_doctor(Item).

La coma entre objetivos se lee “y”.

2. Supongamos que disponemos de los siguientes hechos:

9

Page 11: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

father(bill,mark).father(tom,diane).mother(ellen,mark).

y queremos escribir una regla que defina la relacion parent(Person1,Person2)de forma que sea cierta si Person1 es el padre de Person2, o bien Person1 es lamadre de Person2. En Prolog, la escribirıamos ası:

parent(Person1,Person2) :- father(Person1,Person2).parent(Person1,Person2) :- mother(Person1,Person2).

3. Un ultimo ejemplo. La frase “Una persona puede comprar un coche si a la personale gusta el coche y el coche esta en venta” se escribirıa en Prolog ası:

puede_comprar(Nombre,Modelo) :-persona(Nombre),coche(Modelo),gusta(Nombre,Modelo),en_venta(Modelo).

4. Cargad el programa ch02e02.pro y probad con distintos objetivos. Por ejemplo,can buy(Who,What), can buy(judy,What), can buy(kelly,What), ycan buy(Who,hot rod).

2.2. Predicados (relaciones)

Al nombre de una relacion lo llamamos predicado, mientras que los objetos querelaciona se llaman argumentos.

Aquı hay algunos ejemplos de predicados Prolog con cero o mas argumentos:

pred(integer,symbol)persona(nombre,apellido,edad)runinsert_mode

Un predicado persona se podrıa usar en una consulta del tipo persona(Nombre,perez,22)para averiguar cual es el nombre de Perez.

Sin embargo, ¿para que puede servir un predicado sin argumentos? Su utilidadpuede consistir en provocar la ejecucion del cuerpo de una regla (cuya cabeza sea, porejemplo, run), o bien para que un programa se comporte de distintas formas en funcionde si un predicado se encuentra o no presente (como, por ejemplo, insert mode).

10

Page 12: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

2.3. Variables (clausulas generales)

En una consulta simple, las variables nos pueden servir para que que Prolog en-cuentre un dato. Por ejemplo, la consulta:

tiene(X,coche).

nos devuelve en la variable X el nombre de la persona que tiene un coche (o de laspersonas que lo tienen, si hay mas de una).

La eleccion de un nombre adecuado para las variables suele hacer el programa maslegible. Por ejemplo, la consulta anterior estarıa mejor ası:

tiene(Persona,coche).

Como se asignan valores a las variables

Como habreis podido observar, en Prolog no existe una instruccion de asignacion.Esto resulta una de las diferencias fundamentales entre Prolog y el resto de lenguajesde programacion.

Las variables en Prolog toman valores al ser “igualadas” a constantes en loshechos o reglas del programa.

Hasta el momento en que una variable toma un valor, se dice que esta desinstanciada;cuando ha tomado un valor, se dice que esta instanciada (a dicho valor). Sin embargo,una variable solo permanece instanciada hasta el momento en que obtenemos unasolucion. Despues, se desinstancia, y se procede a buscar nuevas soluciones.

Como consecuencia, no es posible utilizar las variables de Prolog para almacenarinformacion.

Cargad el ejemplo ch02e03.pro:

PREDICATESnondeterm likes(symbol,symbol)

CLAUSESlikes(ellen,reading).likes(john,computers).likes(john,badminton).likes(leonard,badminton).likes(eric,swimming).likes(eric,reading).

Considerad esta consulta: ¿hay alguna persona a la que le guste leer y nadar?

likes(Person, reading), likes(Person, swimming).

11

Page 13: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

En la primera parte (objetivo) de la consulta, la variable Person esta desinstanciada,es decir, su valor es desconocido antes de que Prolog intente encontrar una solucion. Elsegundo argumento, reading, es conocido. De esta forma, Prolog busca algun hechoque se pueda igualar o ajustar (haga “matching”) con la primera parte de la consulta, ylo hace en el orden en que estos aparecen escritos en el programa. Ası, el primer hechodel programa:

likes(ellen,reading).

se puede igualar a likes(Person,reading), ya que reading en la consulta es iguala reading en el hecho, asignandole ademas el valor ellen a la variable Person. Almismo tiempo, Prolog se “anota” hasta donde ha llegado en la busqueda de hechos quese pudieran igualar al primer objetivo de la consulta.

Ahora hay que resolver el segundo objetivo de la consulta (recordad que la coma seinterpreta como un “y”). Ya que ahora Person se ha instanciado a ellen, Prolog debebuscar algo que se ajuste a:

likes(ellen,swimming).

Prolog comienza la busqueda desde el principio del programa, pero no consigue igualarlocon nada. Por tanto, el segundo objetivo de la consulta no es cierto cuando Person tomael valor ellen.

Entonces, Prolog desinstancia la variable Person, e intenta buscar una solucionalternativa para el primer objetivo. Para ello, comienza a buscar un hecho que sepueda igualar de nuevo a:

likes(Person,reading).

a partir del punto que se habıa anotado al encontrar la solucion anterior. Este mecan-ismo de “vuelta atras” (backtracking) lo veremos con detalle mas adelante.El primer hecho que se ajusta a la forma del primer objetivo es ahora:

likes(eric,reading).

Entonces, la variable Person se instancia a eric, y Prolog se dispone a buscar un hechoen el programa que se ajuste con el segundo objetivo de la consulta, que ahora es:

likes(eric,swimming).

En este caso, Prolog tiene exito (con la ultima clausula del programa), y nos devuelvela solucion:

Person = eric1 Solution

12

Page 14: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Variables anonimas

Cuando solo deseamos extraer cierta informacion de una consulta, se usa un tipoespecial de variables denominadas variables anonimas. En Prolog, una variable anonimase denota por un sımbolo de subrayado (‘ ’).Veamos un ejemplo. Cargad el programa ch02e04.pro. En la consulta:

parent(Parent,_).

la variable anonima se interpreta como “cualquier cosa”. Es decir, estamos preguntando:¿Quien es padre o madre de alguien? A lo que Prolog responde:

Parent = billParent = sueParent = joe3 Solutions

Probad con la consulta parent(Parent,X) y comprobad cual es la diferencia.Las variables anonimas tambien se pueden usar en los hechos. Por ejemplo, los

hechos:

tiene(_,zapatos).respira(_).

estarıan expresando las sentencias del lenguaje natural:

Todo el mundo tiene zapatos.Todo el mundo respira.

Finalmente, tened en cuenta que una variable anonima se puede igualar a cualquiercosa, aunque su nombre no es relevante (no se produce ninguna instanciacion). Esdecir, un objetivo:

father(_,_).

se puede igualar perfectamente al hecho:

father(bill,joe).

ya que las dos apariciones de ‘ ’ en el objetivo se consideran variables distintas.

2.4. Objetivos (consultas)

Aunque ambas palabras resultan equivalentes, en lo sucesivo nos referiremos a unaconsulta como un objetivo. En el caso de que un objetivo conste de varias partes, comoen:

likes(Person,reading), likes(Person,swimming).

diremos que se trata de un objetivo compuesto, y a cada parte la llamaremos subobjetivo.Los objetivos compuestos nos permiten obtener la “interseccion” de varios subob-

jetivos.

13

Page 15: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Objetivos compuestos: conjunciones y disyunciones

Como hemos visto, es posible usar un objetivo compuesto para encontrar una solu-cion tal que el subobjetivo A y el subobjetivo B sean ciertos (una conjuncion). Ademas,tambien es posible buscar una solucion tal que el subobjetivo A o el subobjetivo Bsean ciertos. Para ello, separamos los subobjetivos por un punto y coma (‘;’).

El ejemplo ch02e05.pro ilustra esta idea. Cargad el programa y ejecutar el objetivo.La respuesta de Prolog es:

Make = ford, Odometer = 90000, Years_on_road = 4, Body = gray1 Solution

Sin embargo, este objetivo resulta poco natural. A menudo, nos interesan mas pregun-tas del tipo:

¿Hay algun coche que cueste menos de $25,000?

Para ello, lanzarıamos el objetivo:

car(Make,Odometer,Years_on_road,Body,Cost), /* subobjetivo A, y */Cost < 25000 /* subobjetivo B */

Por el contrario, si deseamos averigurar algo como esto:

¿Hay algun coche que cueste menos de $25,000,o algun camion que cueste menos de $20,000?

podrıamos formular el objetivo:

car(Make,Odometer,Years_on_road,Body,Cost), Cost < 25000 ;/* subobjetivo A, o */

truck(Make,Odometer,Years_on_road,Body,Cost), Cost < 20000./* subobjetivo B */

2.5. Comentarios

Los comentarios en un programa Prolog se pueden escribir de dos formas distintas:

si se trata de un comentario que ocupa varias lıneas, debemos comenzarlo con /*y terminarlo con */

cuando el comentario es breve, podemos usar el sımbolo %, el cual provoca quetodo lo que quede a su derecha en la misma lınea se considere un comentario.

14

Page 16: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

3.- ¿Cuando dos objetos se pueden “ajustar”?

Hemos venido usando frases como “buscar un hecho que se ajuste con un objetivo”o “la variable se puede igualar a la constante”, etc. En este punto vamos a explicar conun poco mas de detalle en que consiste este mecanismo.Obiviamente, dos estructuras identicas se pueden ajustar. Por ejemplo:

parent(tom,bill) se ajusta a parent(tom,bill)

Sim embargo, usualmente nos encontramos con variables involucradas. Por ejemplo:

parent(tom,X) se ajusta a parent(tom,bill)

tomando, ademas, la variable X el valor bill.Cuando una variable se encuentra instanciada, se comporta exactamente igual a

una constante. Es decir, si X se ha instanciado a bill, entonces:

parent(tom,X) se ajusta a parent(tom,bill)

pero

parent(tom,X) no se ajusta a parent(tom,joe)

Por otra parte, dos variables desinstanciadas siempre se pueden ajustar. Por ejemplo:

parent(tom,X) se ajusta a parent(tom,Y)

instanciando las variables X e Y una a otra. Mientras esta instanciacion sea valida, lasvariables X e Y se trataran como si fueran una unica variable (dos punteros a una mismaposicion de memoria), de forma que si una toma un valor, la otra tambien lo tomara deforma inmediata.

La tecnica con la que igualamos (o ajustamos) un objetivo con la cabeza de unaclausula puede considerarse como un mecanismo de paso de parametros (bidireccional)en Prolog. Ası, dada una llamada:

parent(tom, Y)

y una clausula encabezada por:

parent(X, joe)

tenemos que parent(tom, Y) se ajusta a parent(X, joe), instanciando la variable Xa tom y la variable Y a joe. Esto se corresponde con el paso del parametro tom a lavariable X, y el paso del parametro joe a la variable Y en el momento de la llamada.

En Prolog, los valores a los que se instancian las variables se pueden pasar en dosmodos: entrada (input) y salida (output). Si una variable en la cabeza de una clausula

15

Page 17: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

recibe un valor desde el objetivo, se dice que es un argumento de entrada y se denotapor (i). Si la variable sirve para devolver un valor al objetivo, se dice que es un argu-mento de salida, y se denota por (o). A la declaracion de los distintos modos de unpredicado lo llamamos patron de flujo de datos.

Por ejemplo, la clausula:

doble(X,Y) :- Y = X+X.

permite calcular el doble de un numero (X). Su patron de flujo de datos es (i,o), esdecir, la X es de entrada, y la Y de salida.

16

Page 18: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Parte III

Programas Visual Prolog

17

Page 19: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

A diferencia de otras versiones de Prolog, Visual Prolog es un compilador de Prolog contipos. Esto significa que hay que declarar los tipos de los objetos sobre los que actuacada predicado. De esta forma, el compilador Prolog puede generar codigo maquinatan eficiente como un programa compilado en C o Pascal.

En esta parte, revisamos las principales secciones que forman parte de un programaVisual Prolog.

1.- Secciones basicas de un programa Visual Prolog

En general, un programa Visual Prolog incluye cuatro secciones basicas: clauses,predicates, domains, y goal.

La seccion clauses forma el nucleo de un programa Visual Prolog. Aquı es dondeaparecen los hechos y las reglas con los que el sistema va a trabajar para ejecutarun objetivo.

La seccion predicates contiene la declaracion de los predicados definidos en laseccion clauses, indicando el tipo de sus argumentos.

La seccion domains se emplea para declarar dominios (tipos de datos) que noesten predefinidos en el sistema.

La seccion goal contiene el objetivo inicial que provoca el comienzo de la ejecuciondel programa (algo ası como el cuerpo principal del programa).

1.1. La seccion “clauses”

La Parte II se ha centrado en las clausulas (hechos y reglas), como escribirlas,cual es su significado, etc. Si habeis entendido que son los hechos y las reglas, y comoescribirlos en Prolog, ya conoceis que aparece en la seccion clauses.

Una restriccion del lenguaje es que todas las clausulas que definan un mismo pred-icado deben aparecer consecutivamente en el programa. Una secuencia de clausulasdefiniendo un mismo predicado, se llama un procedimiento.

Cuando Prolog intenta resolver un objetivo, comienza a recorrer todas las clausulasde la seccion clauses en el orden de aparicion de las mismas. Cada vez que encuentrauna clausula a la que se pueda igualar el objetivo, se anota la posicion de la mismapara la busqueda de soluciones alternativas (backtracking).

Sintaxis de las reglas

Una regla esta compuesta por dos partes: la cabeza y el cuerpo, separados por elsımbolo “:-” (que se interpreta como un “si”). La sintaxis generica para una regla es:

cabeza :- subobjetivo1, subobjetivo2, ..., subobjetivoN.

18

Page 20: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Los subobjetivos en el cuerpo de una regla se pueden interpretar como llamadas aprocedimiento, las cuales, si tienen exito, provocaran que ciertas variables se instanciena ciertos valores.

Es decir, desde el punto de vista procedural, la regla anterior se interpreta ası:“para ejecutar el procedimiento cabeza, hay que ejecutar las llamadas a procedimientosubobjetivo1, subobjetivo2,. . . , subobjetivoN”.

Para ejecutar una regla con exito, todos los subobjetivos del cuerpo deben de poderejecutarse tambien con exito. Si al menos uno de ellos falla, Prolog intenta la ejecucionde otra regla alternativa (si la hay). En esto consiste el mecanismo de backtracking, queveremos con detalle en la Parte IV.

1.2. La seccion “predicates”

Si definimos un predicado en la seccion clauses, debemos declararlo en la seccionpredicates, o bien Visual Prolog nos dara un error. Declarar un predicado sirve paradecirle al sistema cual es el tipo de los argumentos de un predicado.

Visual Prolog incluye un numero importante de predicados predefinidos (“built-inpredicates”), como, por ejemplo, write, read, +, sqrt, etc. Este tipo de predicados nodeben ser declarados en la seccion predicates. Podeis encontrar informacion sobre lospredicados predefinidos en el menu de ayuda de Visual Prolog.

Como declarar predicados definidos por el usuario

Una declaracion de predicado comienza con el nombre del predicado. A continuacion,entre parentesis, aparecen los tipos de sus (cero o mas) argumentos.

nombrePredicado(tipo_arg1,tipo_arg2,...,tipo_argN)

Fijaos en que, a diferencia de lo que ocurre en la seccion clauses, aquı no terminamosla declaracion con un punto.

El nombre de un predicado debe comenzar con una letra (minuscula), seguida decualquier numero de letras, dıgitos o subrayados. Los nombres de predicado tienen unalongitud maxima de 250 caracteres.

En los nombres de los predicados no pueden aparecer espacios en blanco, signos ar-itmeticos, asteriscos, u otros caracteres no alfanumericos (unicamente son validos a..z,A..Z y 0..9). Aquı teneis algunos ejemplos de nombres correctos e incorrectos:

Nombres de predicado correctos Nombres incorrectosfact [fact]is a *is a*has a has/apatternCheckList pattern-Check-Listchoose Menu Item choose Menu ItempredicateName predicate<Name>first in 10 10 first in

19

Page 21: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Los argumentos de un predicado deben pertenecer a un dominio. El dominio puedeser un dominio estandar, o bien un dominio definido en la seccion domains. Veamosalgunos ejemplos:

1. Si declaramos un predicado mi predicado en la seccion predicates como sigue:

predicatesmi_predicado(symbol, integer)

entonces no es necesario declarar los dominios de sus argumentos en la secciondomains, ya que symbol e integer son dominios estandar. Sin embargo, sideclaramos el predicado ası:

predicatesmi_predicado(nombre, numero)

entonces necesitaremos declarar los dominios nombre y numero en la secciondomains. Por ejemplo, si queremos definirlos simplemente del tipo symbol einteger, respectivamente, lo harıamos ası:

domainsnombre = symbolnumero = integer

predicatesmi_predicado(nombre, numero)

2. El siguiente fragmento de programa muestra una declaracion de dominios y pred-icados algo mas compleja:

domainsperson, activity = symbolcar, make, color = symbolmileage, years_on_road, cost = integer

predicateslikes(person, activity)parent(person, person)can_buy(person, car)car(make, mileage, years_on_road, color, cost)green(symbol)ranking(symbol, integer)

Cuando declaramos un argumento del tipo symbol, estamos indicandole al compi-lador que solo podra contener una constante alfanumerica, mientras que integerhace referencia a un numero entero. Mas adelante veremos una lista exhaustivade los distintos tipos de dominios estandar.

20

Page 22: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

1.3. La seccion “domains”

La seccion domains nos permite conseguir esencialmente dos cosas. En primerlugar, podemos darle nombres particulares a ciertos dominios, pese a que estos ya estenpredefinidos (dominios estandar). De esta forma se facilita la legibilidad del programa,y se detecta un mayor numero de errores en tiempo de compilacion. En segundo lugar,nos permite declarar estructuras de datos complejas que no estan predefinidas. Veamosalgunos ejemplos.

1. Supongamos que queremos declarar un predicado que vamos a usar para escribirla siguiente relacion:

Paco es un hombre de 45 anos.

Usando los dominios estandar, podrıamos declarar el siguiente predicado:

predicatespersona(symbol, symbol, integer)

Aunque la declaracion es correcta, resultarıa mucho mas legible el codigo si lohacemos ası:

domainsnombre, sexo = symboledad = integer

predicatespersona(nombre, sexo, edad)

Ademas, con una declaracion de esta forma, el compilador detectarıa que la sigu-iente clausula es incorrecta:

mismo_sexo(X,Y) :-persona(X,Sex,_),persona(Sex,Y,_).

mientras que con la declaracion original la compilarıa sin problemas (ya que losdos primeros argumentos eran symbol).

2. Cargad ahora el programa ch03e01.pro.

Este programa nos permite sumar y multiplicar enteros. Por ejemplo, el objetivo:

add_em_up(32,54,Sum).

tiene exito con la solucion:

21

Page 23: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Sum = 861 Solution

(es decir, la suma de 32 y 54), mientras que un objetivo:

multiply_em(31,13,Product).

nos devuelve:

Product = 4031 Solution

Supongamos ahora que deseamos duplicar el producto de 31 y 17, por ejemplo,con un objetivo de esta forma:

multiply_em(31,17,Sum), add_em_up(Sum,Sum,Answer).

Aunque esperarıamos una respuesta como esta:

Sum = 527, Answer = 10541 Solution

lo que ocurre es que se produce un error de tipos! El problema consiste en queel predicado add em up espera dos argumentos de tipo sum, y se le han pasadodos argumentos de tipo product (pese a que internamente ambos son de tipointeger).

3. Para terminar, cargad el programa ch03e02.pro. Los dominios predefinidos bytey ulong representan, respectivamente, un entero sin signo de 8 bits y un enterosin signo de 32 bits (los discutiremos con detalle mas adelante).

Ejecutad ahora el programa probando alternativamente los siguientes objetivos:

car(renault, 13, 40000, red, 12000).car(ford, 90000, gray, 4, 25000).car(1, red, 30000, 80000, datsun).

En los tres casos se produce un error de tipos. Aunque los datos pertenezcan aun mismo dominio, gracias a la declaracion de dominios es posible detectar quese han intercambiado los argumentos.

22

Page 24: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

1.4. La seccion “goal”

Esencialmente, la seccion goal contiene lo mismo que aparece en el cuerpo decualquier regla, es decir, no es mas que una secuencia de subobjetivos.

La unica diferencia es que la secuencia de subobjetivos en la seccion goal se ejecutaautomaticamente al ejecutar el programa (serıa equivalente al “cuerpo principal” delprograma).

Si alguno de los subobjetivos de goal falla, el programa completo falla (pese a que,desde un punto de vista externo, esto no marca ninguna diferencia, simplemente setermina la ejecucion).

2.- Mas sobre las declaraciones y las reglas

Visual Prolog dispone de varios dominios estandar que se pueden emplear en ladeclaracion de los predicados. Estos dominios no deben declararse en la seccion do-mains.

Los dominios estandar para los numeros enteros son:

Dominio Rangoshort -32768 .. 32767ushort 0 .. 65535long -2147483648 .. 2147483647ulong 0 .. 4294967295integer -32768 .. 32767 (para plataformas de 16 bits)

-2147483648 .. 2147483647 (para plataformas de 32 bits)unsigned 0 .. 65535 (para plataformas de 16 bits)

0 .. 4294967295 (para plataformas de 32 bits)byte 0 .. 255word 0 .. 65535dword 0 .. 4294967295

En general, los dominios integer y unsigned suelen ser suficientes y, ademas, se adap-tan bien a la plataforma en que se este trabajando.

Es posible declarar nuevos dominios usando las palabras reservadas signed/unsignedy byte/word/dword. Por ejemplo,

domainsi8 = signed byte

crea un nuevo dominio i8 cuyo rango es -128 .. 127.La siguiente tabla muestra el resto de dominios estandar de Visual Prolog.

23

Page 25: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Dominio Descripcionchar Un caracter, implementado como un unsigned byte.

Sintacticamente, se escribe como un caracter entre comil-las simples: ’a’.

real Un numero en coma flotante, implementado mediante 8bytes; es equivalente al double de C. Su sintaxis es:

[+|-] DDDDD [.] DDDDDDD [e [+|-] DDD]

El rango permitido es de 1e-307 a 1e+308.string Una secuencia de caracteres, implementada como un puntero

a un vector de bytes, como en C. Se aceptan dos formatos: a)una secuencia de letras, numeros y subrayados, siempre queel primer caracter sea una letra minuscula, o b) cualquiersecuencia de caracteres entre comillas dobles: “The Game”.Los strings tienen un lımite de 255 caracteres.

symbol Una secuencia de caracteres, implementada como un punteroa una entrada de una tabla de sımbolos. La sintaxis es lamisma que en el caso de los strings.

Los objetos de tipo symbol y string se pueden intercambiar sin problemas. Sin embar-go, Visual Prolog los almacena de forma distinta: un objeto de tipo symbol se almacenaen una tabla de sımbolos, y se identifica unicamente por la direccion en la que esta al-macenado (el ajuste entre este tipo de objetos resulta muy eficiente); un objeto detipo string se almacena como un vector de caracteres (con lo que el ajuste entre estetipo de objetos es algo mas lento, ya que tiene que comparar los dos strings caracter acaracter).

La eleccion de uno u otro dominio dependera del uso que le vayamos a dar en elprograma. Por ejemplo, si no vamos a necesitar acceder a los caracteres del objeto, lomas adecuado serıa definirlo como symbol.

Observad que las secciones predicates, clauses y goal son obligatorias en todoslos programas. La seccion domains, por ejemplo, es opcional. Concretamente, si todoslos dominios empleados en la seccion predicates son estandar, la seccion domains noes necesaria.

Veamos algunos ejemplos.

1. Cargad el programa ch03e04.pro. Este programa funciona como un mini-directoriode telefonos. La seccion domains no es necesaria, ya que solo se han empleadodominios estandar.

Probad a ejecutar los siguientes objetivos:

phone_number("Carol", Number).phone_number(Who, "438-8400").phone_number("Albert", Number).

24

Page 26: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

phone_number(Who, Number).

Supongamos ahora que Kim se va a vivir con Dorothy, y que por tanto pasana tener el mismo numero de telefono. Actualiza el programa con este hecho yprueba luego el objetivo:

phone_number(Who, "438-8400").

La solucion deberıa ser:

Who = DorothyWho = Kim2 Solutions

2. Cargad ahora el programa ch03e05.pro que ilustra el uso del dominio char.Probad a ejecutar los objetivos:

isletter(’%’).isletter(’Q’).

a los que Prolog responde No y Yes, respectivamente. Probad ahora con los sigu-ientes objetivos:

(a) isletter(’x’).(b) isletter(’2’).(c) isletter("hello").(d) isletter(a).(e) isletter(X).

Los objetivos (c) y (d) deben dar un error de tipos, mientras que (e) nos da unmensaje de error del tipo Free variable, indicandonos que si le pasamos comoargumento una variable desinstanciada, no es posible comprobar si es posterior a‘a’ o anterior a ‘z’.

Aridad multiple

La aridad de un predicado es el numero de argumentos que tiene. Podemos definirvarios predicados con el mismo nombre y distinta aridad. Visual Prolog permite ladefinicion de un predicado con distintas aridades, exigiendo unicamente que sus defini-ciones deben aparecer agrupadas tanto en la seccion predicates como en la seccionclauses. Por lo demas, cada version del predicado con una aridad distinta se consideracomo un predicado completamente distinto.

En el programa ch03e06.pro podeis ver un ejemplo del uso de un mismo predicadocon distintas aridades.

25

Page 27: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Conversion de tipos automatica

Cuando Visual Prolog iguala dos variables, estas no tiene que pertenecer necesari-amente al mismo dominio. De la misma forma, las variables se pueden instanciar avalores de un dominio distinto. Concretamente, las siguientes conversiones de tipos sonautomaticas:

Entre objetos de tipo symbol y string.

Entre cualquiera de los dominios para los enteros (incluyendo ademas el tiporeal). Cuando un caracter se convierte a un valor numerico, el numero sera suvalor ASCII.

3.- Otras secciones del programa

Vamos a introducir brevemente las secciones (opcionales) database, constants yglobal (que seran vistas con detalle mas adelante).

3.1. La seccion “database”

Un programa Visual Prolog es un conjunto de hechos y reglas. A menudo, mien-tras se esta ejecutando el programa resulta conveniente actualizar (anadir, borrar omodificar) alguno de los hechos del programa. En estos casos, los hechos del programaconstituyen lo que se denomina la base de datos interna.

Visual Prolog incluye una seccion database en la que se deben declarar aquelloshechos que queremos que formen parte de la base de datos interna. Ademas, disponemosde una serie de predicados predefinidos para facilitar el uso de la base de datos.

3.2. La seccion “constants”

En un programa, es posible definir constantes simbolicas dentro de la seccion con-stants. La sintaxis es la siguiente:

constants<id> = <definicion>

donde <id> es el nombre de la constante simbolica, y <definition> es el valor que leestamos asignando a dicha constante. Por ejemplo, podemos encontrar una declaracionde constantes como esta:

constantscero = 0uno = 1dos = 2cien = (10*(10-1)+10)pi = 3.141592653

26

Page 28: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Como es habitual, antes de realizar la compilacion del programa, Visual Prolog reem-plaza la aparicion de cada constante simbolica en el codigo por su valor.

Existen, sin embargo, unas pocas restricciones sobre el uso de constantes simbolicas:

La definicion de una constante no puede autoreferenciarse. Por ejemplo:

error = 2*error

generarıa un mensaje de error.

El sistema no distingue entre mayusculas y minusculas en los nombre de con-stantes. Por tanto, aunque se declare una constante:

constantsDos = 2

en el programa habra que emplearla en minusculas (para evitar que se confundacon una variable). Es decir, escribiremos:

goalA = dos, write(A).

y no:

goalA = Dos, write(A).

(lo que producirıa un error).

Pueden aparecer varias secciones de declaracion de constantes en un programa,pero estas deben declararse siempre antes de la primera vez que se usen.

La declaracion de una constante es valida desde el punto en el que se definehasta el final del fichero fuente, pero no pueden declararse varias constantes conel mismo identificador.

3.3. Secciones globales

Visual Prolog permite la declaracion de una serie de secciones globales. En principio,las secciones son locales al fichero (modulo) en el que aparecen. Sin embargo, es posibledeclarar al principio de un programa las secciones global domains, global predicatesy global database, de forma que sean visibles en todos los ficheros (modulos) de laaplicacion.

27

Page 29: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

3.4. Directivas de compilacion

Aunque estas se pueden ver con detalle en el manual del entorno de desarrollo delVisual Prolog (VDE), vamos a introducir aquı la mas popular: la directiva include.

La directiva include se emplea para evitar tener que escribir repetidamente unamisma serie de procedimientos. Por ejemplo, podemos crearnos una librerıa con lospredicados Prolog que usemos mas frecuentemente en nuestras aplicaciones.

De esta forma, supongamos que hemos creado un fichero MI LIB.PRO que contienelas secciones domains, predicates y clauses que definen los predicados que usamoscon mas frecuencia.

Ahora, al escribir un nuevo programa, podemos incluir dichos predicados simple-mente escribiendo:

include "mi_lib.pro"

en cualquier frontera del programa. Entendemos por “frontera” cualquier punto delprograma en el que podrıa aparecer una seccion domains, database, predicates,clauses o goal.

28

Page 30: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Parte IV

Unificacion y backtracking

29

Page 31: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

En esta parte vamos a tratar cuatro temas:

En primer lugar, veremos el mecanismo de unificacion. Cuando se intenta igualar(o ajustar) un objetivo con una clausula, hacemos uso de la unificacion. Estemecanismo incluye cosas propias de otros lenguajes tradicionales, tales como elpaso de parametros, la seleccion por casos, la construccion y acceso a estructurasde datos o la asignacion.

A continuacion, nos centramos en el mecanismo de backtracking, la tecnica medi-ante la que Prolog controla la busqueda de soluciones para los objetivos.

Despues, introduciremos un predicado predefinido que se puede emplear paramodificar la estrategia de backtracking, consiguiendo ası programas mas efi-cientes.

Finalmente, y con la intencion de clarificar los conceptos introducidos hasta elmomento, revisaremos algunos de los principales elementos de Prolog desde unpunto de vista procedural.

1.- El mecanismo de unificacion

Cargad el programa ch04e01.pro. Consideremos el objetivo:

written_by(X, Y).

Cuando se ejecuta este objetivo, Prolog intenta encontrar una clausula en el programa(en el orden de aparicion) cuya cabeza se pueda igualar al objetivo. Entonces, le asignavalores a las variables desinstanciadas, de forma que ambos, el objetivo y la cabeza dela clausula, se hagan identicos. A este proceso le llamamos unificacion.

En nuestro caso concreto, ya que el objetivo tiene como argumentos dos variablesdesinstanciadas X e Y, este unificara con cualquier clausula cuya cabeza contenga elpredicado written by. Por ejemplo, se produce la siguiente unificacion:

written_by( X , Y ).| |

written_by(fleming, "DR NO").

instanciando la variable X al valor fleming y la variable Y al valor "DR NO". En esteinstante, aparece por pantalla la solucion:

X = fleming, Y = "DR NO"

y el sistema se dispone a buscar otras soluciones al objetivo (si las hay). Para ello, sedesinstancian las variables, y se intenta buscar otra clausula con cuya cabeza unifiqueel objetivo, por ejemplo:

written_by( X , Y ).| |

written_by(melville, "MOBY DICK").

30

Page 32: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Ası, Visual Prolog muestra por pantalla una nueva solucion:

X = melville, Y = "MOBY DICK"

De nuevo, desinstancia las variables e intenta buscar una nueva solucion. En este caso,sin embargo, ya no hay mas clausulas que unifiquen con el objetivo, y por tanto muestrafinalmente el mensaje:

2 Solutions

y termina la ejecucion del programa.

Consideremos ahora el objetivo:

written_by(X, "MOBY DICK").

Prolog comienza a buscar clausulas con las que unificar, y prueba con la primera:

written_by( X , "MOBY DICK").| |

written_by(fleming, "DR NO" ).

Sin embargo, puesto que "MOBY DICK" y "DR NO" son dos strings distintos, el intentode unificacion falla, y Visual Prolog prueba con otra clausula:

written_by( X , "MOBY DICK").| |

written_by(melville, "MOBY DICK").

que sı tiene exito, instanciando la variable X a melville.

Considerad ahora el objetivo:

long_novel(X).

Cuando Visual Prolog ejecuta este objetivo, comienza por buscar una clausula cuyacabeza unifique con el. En este caso, selecciona la unica clausula para long novel:

long_novel(Title) :-written_by(_, Title),book(Title, Length),Length>300.

Ya que tanto la variable X como Title estan desinstanciadas, entonces long novel(X)unifica con long novel(Title) instanciandose una variable a la otra.

Ahora, Visual Prolog intenta ejecutar los subobjetivos en el cuerpo de la clausulaanterior, comenzando por written by( , Title). Fijaos en que, puesto que el autor dellibro no es importante (solo queremos combrobar que dicho tıtulo existe), empleamosuna variable anonima. Este objetivo unifica con el primer hecho para written by:

31

Page 33: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

written_by( _ , Title ).| |

written_by(fleming, "DR NO").

instanciando la variable Title a "DR NO". Prolog intenta ahora la ejecucion del sigu-iente subobjetivo book(Title, Lenght) con la instanciacion realizada, es decir, intentala ejecucion de:

book("DR NO", Length)

El intento de unificacion con el hecho book("MOBY DICK", 250) falla, puesto que "DRNO" y "MOBY DICK" no unifican. Con la segunda clausula de book sı que hay exito:

book("DR NO", Length).| , |

book("DR NO", 310 ).

instanciando la variable Length a 310. Finalmente, ejecutamos Length >300 que, conla instanciacion anterior, se convierte en:

310 > 300

que tiene exito.

En este punto, todos los subobjetivos de long novel han sido ejecutados con exito y,por tanto, la llamada inicial termina con exito. ¿Cual sera el valor de la variable Xdel objetivo inicial? Puesto que X se ha instanciado a Title, y Title a su vez se hainstanciado a "DR NO", Visual Prolog devuelve:

X = "DR NO"1 Solution

2.- Backtracking

Para ilustrar la forma en que procede el mecanismo de backtracking (“vuelta atras”),podemos compararlo con la busqueda de la salida en un laberinto. Para encontrarla, unmetodo tradicional consiste en girar a la izquierda en cada ramificacion del camino. Sillegamos a un camino sin salida, debemos volver atras hasta la ultima ramificacion quepasamos, y probar ahora con el camino que quede a su derecha, repitiendo de nuevo elproceso de girar a la izquierda en cada nueva ramificacion. Este metodo nos garantizaque tarde o temprano habremos explorado todas las posibilidades y que, por tanto,encontraremos la salida (si la hay).

En un programa Prolog se permite la definicion de varias clausulas para cada pred-icado. De esta forma, cuando se intenta ejecutar un objetivo, puede ocurrir que esteunifique con la cabeza de varias clausulas del programa, dando lugar a una ramificacionen el camino de ejecucion. Prolog prueba las distintas clausulas en el orden de apari-cion. Cuando encuentra una con la que el objetivo unifica, toma ese camino y pone una

32

Page 34: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

“marca” en la siguiente clausula del programa. A esta marca la llamaremos punto debacktracking. Ası, en caso de que llegue a un fallo (es decir, a un camino sin salida),puede volver atras hasta el ultimo punto de backtracking que haya pasado, y tomar lasiguiente alternativa.

Veamos un ejemplo. Cargad el programa ch04e02.pro que define una relacionlikes(bill,X) que dice que a bill le gusta X si se trata de una comida que sabebien, junto con un par de conjuntos de hechos para las relaciones food y tastes.

Para ver como funciona el mecanismo de backtracking, podeis lanzar el siguienteobjetivo al programa:

likes(bill, What).

Comprobad el resultado que os muestra Visual Prolog, e intentad realizar una traza dela ejecucion a mano, teniendo en cuenta las siguientes reglas:

1. Cuando Prolog comienza la ejecucion del objetivo, siempre empieza a recorrer lasclausulas de programa en el orden de aparicion en busca de una que unifique.

2. Cuando se realiza una nueva llamada (subobjetivo en el cuerpo de alguna clausu-la), vuelve a comenzar de nuevo la busqueda desde el principio del programa.

3. Cuando una llamada encuentra un hecho con el que unifica, decimos que la lla-mada ha tenido exito, y se ejecuta la siguiente llamada pendiente.

4. Una vez que una variable se ha instanciado a un valor, la unica forma de desin-stanciarla es mediante backtracking (mas alla del punto en el que tomo dichovalor).

2.1. Busqueda exhaustiva de soluciones en Visual Prolog

Como ya hemos comentado, gracias al mecanismo de backtracking, Visual Prologno solo computa la primera solucion a un objetivo, sino todas las soluciones posibles.

Cargad ahora el programa ch04e03.pro, que contiene hechos acerca de los nombresy edades de los jugadores de un club de tenis. Si deseamos calcular los jugadores de untorneo para ninos de 9 anos, podemos ejecutar el siguiente objetivo compuesto:

player(Person1, 9),player(Person2, 9),Person1 <> Person2.

que se interpreta ası: “buscar dos personas distintas de nueve anos que sean miembrosdel club de tenis”.

Probad primero a generar todas las respuestas sin tener en cuenta el ultimo subobjetivoPerson1 <>Person2 (hacedlo a mano, y luego comprobad el resultado lanzando elobjetivo correspondiente). Las soluciones computadas serıan estas:

33

Page 35: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Person1 = peter, Person2 = peterPerson1 = peter, Person2 = chrisPerson1 = peter, Person2 = susanPerson1 = chris, Person2 = peterPerson1 = chris, Person2 = chrisPerson1 = chris, Person2 = susanPerson1 = susan, Person2 = peterPerson1 = susan, Person2 = chrisPerson1 = susan, Person2 = susan9 Solutions

Si ahora ejecutamos el objetivo completo, las soluciones obtenidas son unicamente:

Person1 = peter, Person2 = chrisPerson1 = peter, Person2 = susanPerson1 = chris, Person2 = peterPerson1 = chris, Person2 = susanPerson1 = susan, Person2 = peterPerson1 = susan, Person2 = chris6 Solutions

ya que debe cumplirse que Person1 <>Person2. Sin embargo, aun existe el problemade que, por ejemplo, la solucion:

Person1 = peter, Person2 = chris

y la solucion:

Person1 = chris, Person2 = peter

son equivalentes. Mas adelante veremos como controlar el backtracking para evitar estetipo de soluciones.

2.2. Ejecucion de programas y backtracking

Los siguientes principios basicos rigen la ejecucion de un programa Prolog:

1. Los subobjetivos de un objetivo se deben de ejecutar de izquierda a derecha (enel orden en que aparecen).

2. La busqueda de clausulas del programa con las que unificar un subobjetivo serealiza en el orden de aparicion de las mismas en el programa (de arriba a abajo).

3. Cuando un subobjetivo unifica con la cabeza de una regla, los subobjetivos en elcuerpo de la misma son los siguientes subobjetivos a ejecutar.

4. Cuando un subobjetivo unifica con un hecho, decimos que este ha tenido exito yproseguimos la ejecucion con el siguiente subobjetivo pendiente.

34

Page 36: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

El uso de estas reglas da lugar a un esquema de ejecucion como el que sigue. Tecleadel siguiente programa:

predicatesp(symbol)q(symbol)r(symbol)s(symbol)t(symbol)

clausess(a).t(a).

p(X) :- q(X), r(X).q(X) :- s(X).r(X) :- t(X).

goalp(Sol).

Ahora, la secuencia de objetivos que se producirıa es la siguiente (aparece subrayadoel subobjetivo que ejecutamos):

p(X).|

q(X),r(X).|

s(X),r(X).| % X se instancia a a

r(a).|

t(a).|

FIN (con la solucion X = a)

Fijaos en que, en cada paso, se sustituye el subobjetivo a ejecutar por la secuencia desubobjetivos de la clausula con la que hemos unificado dicho subobjetivo (en caso deque sea una regla), o bien desaparece (en caso de que la clausula sea un hecho).

Sin embargo, cuando existen distintas clausulas definiendo cada predicado, la secuenciade objetivos no es lineal (como en el caso anterior), sino que se produce una estructuraen forma de arbol. Cargad el programa ch04e05.pro. La ejecucion del objetivo:

can_swim(What).

da lugar al siguiente arbol de objetivos:

35

Page 37: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

FALLO!

lives(zebra,in water).

is a(What,ungulate),lives(What,in water).

FALLO!

lives(herring,in water).

EXITO!

lives(shark,in water).

!!!!!!!!

aaaaaaaa

is a(What,fish),lives(What,in water).

aaaaaaaa

type(X,animal),is a(What,X), lives(What,in water).

can swim(What).

La ejecucion del programa consitirıa en recorrer el arbol anterior en preorden (izquierda-raız-derecha) hasta alcanzar la hoja de EXITO, que generarıa la solucion:

What = shark1 Solution

En la representacion de la ejecucion mediante un arbol, cada uno de los puntos en quese produce una ramificacion se corresponde con los llamados puntos de backtracking. Esdecir, cada vez que se produce un fallo, hay que retroceder en el arbol hasta la ultimaramificacion que hemos dejado atras.

2.3. Controlando la busqueda de soluciones

A menudo, la busqueda automatica de todas las soluciones para cada objetivo re-sulta innecesario. Prolog dispone de dos predicados predefinidos que permiten controlarla busqueda de soluciones: fail y el operador de corte (escrito como un sımbolo deadmiracion !).

El predicado fail

Prolog realiza backtracking cada vez que una llamada falla. En ciertas situaciones,es necesario forzar el backtracking de cara a obtener soluciones alternativas. El efec-to de un subobjetivo fail es exactamente equivalente a una llamada 2 = 3, es decir,simplemente produce un fallo.

Cargad el programa ch04e06.pro:

DOMAINSname = symbol

36

Page 38: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

PREDICATESnondeterm father(name, name)everybody

CLAUSESfather(leonard,katherine).father(carl,jason).father(carl,marilyn).everybody :-father(X,Y),write(X," is ",Y,"’s father\n"),fail.

everybody.

Comencemos por anadir la siguiente clausula al programa:

prueba :- father(X, Y), write(X," is ",Y,"’s father\n").

Si lanzamos ahora el objetivo:

goalprueba.

la solucion de Prolog es:

leonard is katherine’s fatheryes

Fijaos en que existen mas soluciones, pero Visual Prolog no nos las proporciona. Cuandoel objetivo que lanzamos desde la seccion goal tiene varias soluciones alternativas parasus variables, Prolog sı que las proporciona todas. Por ejemplo, dado el objetivo:

goalfather(X,Y).

se obtienen las soluciones:

X = leonard, Y = katherineX = carl, Y = jasonX = carl, Y = marilyn3 Solutions

La cuestion es, ¿como podemos obtener varias soluciones a un subobjetivo si no apareceen la seccion goal? La respuesta consiste en emplear el predicado predefinido fail.Considerad esta regla del programa:

everybody :-father(X,Y),write(X," is ",Y,"’s father\n"),fail.

everybody.

37

Page 39: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Dado un objetivo:

goaleverybody.

Prolog ejecuta father(X,Y), obteniendo la primera solucion para X e Y, y muestra elmensaje:

leonard is katherine’s father

Sin embargo, luego debe ejecutar el subobjetivo fail, que produce un fallo, con el con-siguiente backtracking para encontrar soluciones alternativas a father(X,Y) (desin-stanciando las variables). Ası se genera una nueva solucion, y se muestra el mensaje:

carl is jason’s father

De nuevo llegamos a la ejecucion de fail, y tras producirse el backtracking se muestrael mensaje:

carl is marilyn’s father

Finalmente, ejecutamos de nuevo fail y, puesto que no existen mas soluciones alter-nativas para la llamada a father(X,Y), se retrocede a buscar soluciones alternativaspara el objetivo inicial everybody. Este unifica con el hecho everybody, cuyo unicoefecto es terminar la ejecucion con exito.

El predicado de corte

Prolog dispone de un predicado predefinido de corte, que se escribe mediante unsigno de exclamacion (‘!’).

Su funcionamiente es el siguiente:

se puede usar como un subobjetivo mas;

su ejecucion siempre tiene exito;

cuando se produce backtracking en una clausula que contenıa un corte, desapare-cen las soluciones alternativas para todos los subobjetivos que aparezcan a laizquierda del corte en el cuerpo de la clausula, ası como para el predicado que sedefine en la cabeza de la clausula.

Existen dos usos principales del corte:

1. Si en determinado punto del programa sabemos con seguridad que ya no va aser posible encontrar una solucion, el corte puede servir para ahorrar tiempo yespacio en la ejecucion (este tipo de cortes se llaman cortes verdes).

2. En ocasiones, aunque un predicado que hemos definido pueda tener varias solu-ciones alternativas, puede ocurrir que solo nos interese una de ellas. Esto se puedeconseguir tambien empleando el corte (en este caso se llama un corte rojo, ya quealtera la logica del programa).

38

Page 40: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Uso del corte para evitar backtracking a un subobjetivo previo

Consiste en usar una clausula de la forma:

r1 :- a, b, !, c.

Con esta construccion, le estamos diciendo a Prolog que, si encontramos una primerasolucion para a y b, ya tenemos suficiente, no es necesario buscar otras alternativas,aunque c pueda fallar. Cargad el programa ch04e07.pro y vereis un ejemplo de estetipo de uso del corte.

Evitar el backtracking a la siguiente clausula

Podemos usar el corte para decirle a Prolog que ha elegido la clausula correcta, yque debe “olvidar” el resto. Esto se consigue con una construccion del tipo:

r(1) :- !, a, b, c.r(2) :- !, d.r(3) :- !, e.r(_) :- write("este es el caso otherwise").

Ante un objetivo r(1), solo se ejecutara la primera clausula, ya que el corte elimina laposibilidad de seleccionar el resto (concretamente, evitamos la ejecucion de la ultimaclausula). Una situacion similar ocurrirıa ante los objetivos r(2) y r(3), con los quesolo se podrıa ejecutar la segunda y tercera clausula, respectivamente. Para cualquierotro valor, solo se ejecutara la ultima clausula.

En pocas palabras, hemos conseguido un procedimiento determinista, es decir, unprocedimiento que solo puede llevar a cabo una unica accion, sin disponer de alterna-tivas.

Ademas, la construccion tiene un gran parecido con la instruccion “case of” deotros lenguajes. Concretamente, si lo escribimos ası:

r(X) :- X = 1, !, a, b, c.r(X) :- X = 2, !, d.r(X) :- X = 3, !, e.r(_) :- write("este es el caso otherwise").

El subobjetivo (o subobjetivos) que aparecen a la izquierda de los cortes harıan el papelde los distintos casos de una instruccion case of. Es decir, serıa equivalente a:

r(X) = case X of1 : a, b, c;2 : d;3 : e;

otherwise : write("este es el caso otherwise");

39

Page 41: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

Un ejemplo similar podeis encontrarlo en el programa ch04e08.pro. Cargadlo y com-probad su ejecucion con y sin los cortes.

Para finalizar, debemos tener en cuenta que el uso de predicados indeterministas(es decir, aquellos que pueden generar varias soluciones alternativas) puede resultarutil, pero tiene un coste muy elevado en tiempo de ejecucion. Por tanto, siempre quedefinamos un predicado que solo debe generar una solucion (es decir, un predicadodeterminista), debemos asegurarnos de que es ası, aunque sea empleando el predicadode corte. Visual Prolog dispone ademas de una directiva de compilacion check determque, si la activamos, se encargara de darnos un aviso cada vez que encuentre en tiempode compilacion un predicado indeterminista.

El predicado not

Prolog dispone tambien de un predicado predefinido not para realizar la negacionde un subobjetivo. Su interpretacion es muy intuitiva: siempre que un subobjetivo subtenga exito, el subobjetivo not(sub) falla, y viceversa. Podeis encontrar un ejemplo desu uso en el programa ch04e10.pro.

Hay algunas cosas que hay que tener en cuenta al usar el predicado predefinido not:

En el momento de ejecutarse un subobjetivo not(sub), sub no puede contenervariables desinstanciadas (o se producira un error de ejecucion).

Si queremos disponer de variables como argumento de not, deberan ser necesari-amente variables anonimas.

Para finalizar, ahora que ya hemos introducido el uso del corte, cargad de nuevoel programa ch04e03.pro y modificadlo empleando el corte para que no genere dossoluciones del tipo:

Person1 = peter, Person2 = chrisPerson1 = chris, Person2 = peter

sino solo una de ellas (ya que son equivalentes).

4.- Prolog desde un punto de vista procedural

En primer lugar, es importante recordar que Prolog es un lenguaje declarativo yque, por tanto, dispone de un mayor nivel de abstraccion que los lenguajes imperativoscomo C, Pascal, Basic, etc. Como ya hemos comentado, en un programa Prolog debedescribirse el problema, pero no es necesario introducir instrucciones de control quedigan como obtener la solucion al mismo.

Pese a ello, es posible presentar una vision procedural de Prolog, en el estilo de loslenguajes imperativos.

Por ejemplo, la siguiente clausula:

40

Page 42: Javier Ibá˜nez (Despacho D-109) Germán Vidal (Despacho D-242 ...

proced(X) :-write("comienzo"),write(X),write("fin").

se puede ver facilmente como un procedimiento de este tipo:

proced(X);begin

write("comienzo");write(X);write("fin")

end;

En el programa ch04e13.pro podeis encontrar un ejemplo mas avanzado del uso deProlog para formar un procedimiento que se comporte como una instruccion case of.

La habitual instruccion if then else tambien resulta sencilla de implementar en Pro-log. Por ejemplo, el procedimiento:

max(X,Y,Z);beginif X > Y then Z:=X

else Z:=Yend

se podrıa escribir en Prolog ası:

max(X,Y,Z) :- X>Y, Z = X.max(X,Y,Z) :- not(X>Y), Z = Y.

o, de forma mas compacta (usando el corte):

max(X,Y,Z) :- X>Y, !, Z = X.max(X,Y,Z) :- Z = Y.

En general, la vision procedural de Prolog no resulta positiva, ya que suele provocarque se utilice Prolog como un lenguaje imperativo (para lo cual ya disponemos de unagran variedad de lenguajes bastante mas adecuados).

La verdadera potencia de Prolog reside en su componente declarativa, la cual puedepermitir el desarrollo de cierto tipo de aplicaciones donde la heurıstica es fundamental(sistemas expertos, bases de datos avanzadas, redes neuronales, etc.) de forma rapiday eficiente.

41