Está en la página 1de 26

AL LENGUAJE PROLOG

INTRODUCCION

Indice
1. Introducci
on

2. Caractersticas Generales

2.1. Evolucion historica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.2. Esquema general de trabajo en Prolog . . . . . . . . . . . . . . . . . . . . . . . .

2.3. Implementaciones de Prolog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.3.1. SICStus Prolog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.3.2. SWI-Prolog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3. Prolog y el paradigma de la Programaci


on L
ogica

3.1. Sintaxis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3.1.1. Terminos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3.1.2. Programas

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3.1.3. Consultas para la activacion de programas . . . . . . . . . . . . . . . . . . 10


3.1.4. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.2. Semantica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
4. Predicados Predefinidos

15

4.1. Aritmetica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
4.1.1. Operadores aritmeticos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
4.1.2. Predicados aritmeticos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.1.3. Programas aritmeticos en Prolog . . . . . . . . . . . . . . . . . . . . . . . 17
4.2. Entrada/Salida . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4.3. Control: el corte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.3.1. Definicion y propiedades . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.3.2. Usos del corte. Ejemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

1.

Introducci
on

En este documento se realiza una breve introduccion al lenguaje de programacion Prolog, con
el objetivo fundamental de mostrar como se da el paso desde el concepto de programacion
logica pura estudiado en el tema anterior a un lenguaje de programacion real. En efecto,
el lenguaje Prolog se puede ver como una extensi
on de la programacion logica pura, en el
sentido de que, ademas de permitir programar de acuerdo con el paradigma de la programacion
logica, incorpora una serie de elementos adicionales cuyo objetivo es ofrecer una herramienta
de programacion que sea u
til en la practica.
Despues de una descripcion de las caractersticas generales del lenguaje (evolucion historica,
esquema general de trabajo e implementaciones existentes), el apartado 3 estudia el funcionamiento de Prolog desde el punto de vista de la programacion logica pura, basado en la Programacion Logica Definida estudiada en el tema anterior. Su extension, que se realiza mediante la
introduccion de los denominados predicados predefinidos, se resume en el apartado 4.
No se abordan, por lo tanto, mas que algunos de los aspectos mas relevantes del lenguaje.
Para un estudio mas en profundidad de Prolog se recomienda consultar los siguientes libros (los
tres primeros son libros de caracter introductorio, mientras que el u
ltimo trata aspectos mas
avanzados).
L. Sterling and E. Shapiro. The Art of Prolog. The MIT Press, Cambridge, Mass., second
edition, 1994.
W.F. Clocksin and C.S. Mellish. Programming in Prolog. Springer-Verlag, Berlin, fourth
edition, 1994.
I. Bratko. Prolog Programming for Artificial Intelligence. Addison-Wesley, Reading, Massachusetts, third edition, 2001.
R. OKeefe. The Craft of Prolog. The MIT Press, Cambridge, MA, 1990.

2.
2.1.

Caractersticas Generales
Evoluci
on hist
orica

Prolog (del frances, PROgrammation en LOGique) fue el primer lenguaje de programacion basado en el paradigma de la programacion logica. Se implemento por primera vez a principios de
los a
nos setenta en la Universidad de Marsella (Francia), por un equipo dirigido por A. Colmeraeur, utilizando resultados teoricos aportados por R. Kowalski (Universidad de Edimburgo).
Aunque con ciertas dificultades iniciales, debido principalmente a la novedad del paradigma
y a la escasa eficiencia de las implementaciones disponibles, el lenguaje se fue expandiendo
rapidamente, sobre todo en Europa y en Japon (en este u
ltimo pas la programacion logica
se incluyo como parte central del proyecto de ordenadores de quinta generacion de los a
nos
ochenta). En 1995 el lenguaje se normaliza con el correspondiente estandar ISO. En la actualidad Prolog se ha convertido en una herramienta de desarrollo de software practica y de gran
aceptacion para la que se dispone de m
ultiples compiladores, tanto comerciales como de libre
distribucion.
2

2.2.

Esquema general de trabajo en Prolog

El esquema general de trabajo en Prolog es el siguiente:


1. Escribir un programa logico en Prolog.
Como se ha visto en el tema anterior, un programa logico es un conjunto finito de formulas
logicas, que reflejan el conocimiento del que se dispone acerca del problema a resolver.
Por lo tanto, un programa en Prolog estara formado por una serie de formulas logicas
que, evidentemente, tendran que adaptarse a la sintaxis especfica del lenguaje (esta se
detalla mas adelante). Podran asimismo incluirse comentarios:
% El s
mbolo % precede los comentarios en una
unica l
nea
/* Los comentarios en varias l
neas empiezan con /*
y terminan con */
*/
Los programas se pueden escribir mediante cualquier editor de textos, aunque, como se
vera despues, existen editores especiales que facilitan la escritura de programas en Prolog.
Una vez escrito un programa, este se debera guardar en un fichero (la extension habitual
para los programas en Prolog es .pl).
2. Iniciar el sistema Prolog y cargar un programa.
Cuando se inicia un sistema Prolog, este muestra por pantalla una lnea con el siguiente
formato:
?que indica que el sistema esta esperando la introduccion por parte del usuario de alguna
consulta. Para poder trabajar con un programa escrito previamente, es necesario cargar
el fichero correspondiente en el sistema Prolog. Lo anterior se puede hacer de dos formas
distintas:
- interpretando el programa por medio del interprete del lenguaje. Esta solucion es la
mas habitual cuando se esta probando un programa, y la accion se conoce como
consultar un fichero. Para realizarla, basta con utilizar el predicado del sistema
consult, con el nombre del fichero que se quiere cargar:
?- consult(c:/Prolog/prueba.pl).
Lo anterior es equivalente a escribir simplemente el nombre del fichero entre corchetes:
?- [c:/Prolog/prueba.pl].
- compilando el programa por medio del compilador del lenguaje. El codigo compilado
es mas rapido que el codigo interpretado, aunque ofrece menos facilidades en lo que
a depuracion se refiere. La compilacion de un programa se realiza por medio del
predicado del sistema compile:
?- compile(c:/Prolog/prueba.pl).
3

En cualquiera de los dos casos, la respuesta del sistema puede ser de dos tipos:
- si se ha detectado alg
un error sintactico en el programa, el sistema Prolog avisa de ello
mediante un mensaje. En estos casos habra que volver a editar el programa para
corregir los errores que contiene y volver a cargarlo.
- en caso contrario, el sistema responde con la palabra yes, que indica que el programa
se ha cargado correctamente y el sistema esta listo para recibir consultas del usuario.
Nota: la mayora de los sistemas Prolog ofrecen un entorno de programacion interactivo
dotado de men
us mediante los cuales se ofrecen las acciones mas habituales, entre ellas la
carga de ficheros tanto para ser interpretados como para ser compilados (normalmente,
File/Consult... y File/Compile...).
3. Activar un programa desde el sistema Prolog.
Una vez que se ha cargado correctamente un programa, el sistema esta preparado para
recibir las consultas del usuario relativas al problema que se pretende resolver. Para ello
bastara con escribir dichas consultas, siguiendo la sintaxis especfica del lenguaje, en
la lnea de consultas del sistema. El formato de estas consultas as como las posibles
reacciones del sistema ante ellas se detallan mas adelante.
on que permite
Nota: Los sistemas Prolog suelen incorporar un mecanismo de depuraci
seguir paso a paso la ejecucion de las consultas, establecer puntos de corte en la ejecucion,
etc. Su funcionamiento basico es el siguiente:
para entrar en modo de depuracion debe escribirse el predicado del sistema trace
en la lnea de consultas:
?- trace.
A partir de ese momento, las consultas que se realicen se ejecutaran en modo de
depuracion, mostrando una despues de otra todas las llamadas realizadas internamente por el sistema Prolog. Para avanzar en la depuracion, basta con pulsar la tecla
RETURN. Tambien puede pulsarse la tecla h para obtener ayuda sobre las distintas opciones disponibles. En particular, la tecla n permite abandonar el proceso de
depuracion.
para desactivar el modo de depuracion se utiliza el predicado notrace:
?- notrace.
Para una informacion mas detallada sobre el mecanismo de depuracion de Prolog se
recomienda leer el captulo 8 del libro de Clocksin y Mellish citado en la introduccion o
consultar el manual de referencia del sistema Prolog que se este utilizando.
4. Salir del sistema Prolog.
Para salir del sistema Prolog basta con escribir el predicado del sistema halt en la lnea
de comandos:
?- halt.

2.3.

Implementaciones de Prolog

Como se ha comentado previamente, existen muchas implementaciones del lenguaje Prolog,


tanto comerciales como de libre distribucion. La mayora de ellas se adaptan al estandar ISO,
4

por lo que los programas Prolog que se generen de acuerdo con dicho estandar podran ejecutarse
en cualquiera de estos sistemas.
En esta asignatura (y en este documento) se va a utilizar la implementacion comercial denominada SICStus Prolog, para la cual la URJC dispone de una licencia de Campus. A
continuacion se describe brevemente tanto este sistema como otro sistema Prolog, de dominio
p
ublico, denominado SWI-Prolog.
2.3.1.

SICStus Prolog

SICStus Prolog es un compilador de Prolog comercial, desarrollado por el Instituto Sueco de


Ciencias de la Computacion (SICS), compatible con el estandar ISO-Prolog, con facilidades de
depuracion, interfaz con el lenguaje C, estructuracion modular, bibliotecas con las estructuras
de datos mas habituales, etc.
Aunque SICStus Prolog se puede usar directamente (activando el ejecutable correspondiente y
siguiendo el esquema general de trabajo en Prolog descrito mas arriba), lo mas recomendable
es usarlo a traves del editor de textos GNU Emacs (Emacs es un potente editor de textos,
programable y de libre distribucion, que puede obtenerse en la URL http://www.emacs.org).
Para ello, SICStus Prolog incluye en su distribucion un fichero de interfaz con Emacs (.emacs),
que aporta un modo de edicion especial para programas en Prolog, as como acceso directo
desde el editor Emacs a la carga de programas, al sistema SICStus Prolog y a su manual de
ayuda.
As, una vez instalado dicho interfaz, el modo de trabajar en SICStus Prolog a traves del editor
Emacs sera el siguiente:
1. Iniciar Emacs.
El editor Emacs se inicia mediante el ejecutable runemacs.exe, ubicado en el subdirectorio bin del directorio en el que se haya instalado el editor.
2. Crear/editar un programa Prolog.
Tanto para crear un nuevo programa como para modificar un programa ya existente
se usara la opcion del men
u de Emacs File/Open File..., o, alternativamente, la
combinacion de teclas CONTROL-X CONTROL-F. Si el nombre facilitado se corresponde
con un fichero existente, el editor mostrara su contenido en pantalla; en caso contrario,
mostrara una ventana vaca en la que se podra escribir el nuevo programa. Las entradas de
los men
us Edit y File (o las combinaciones de teclas asociadas) ofrecen las opciones
habituales para editar y guardar (CONTROL-X CONTROL-S) el contenido del fichero.
3. Cargar un programa e iniciar el sistema Prolog.
Si el fichero abierto en el punto anterior tiene extension .pl, el interfaz de SICStus
Prolog con Emacs a
nadira automaticamente a la barra de men
us de Emacs una nueva
entrada bajo el nombre Prolog que incluye, entre otras, las opciones pertinentes para
consultar (CONTROL-C CONTROL-F) o compilar el programa correspondiente. Al elegir cualquiera de ellas, no solo se cargara el programa en el sistema sino que ademas
se abrira una nueva ventana con el sistema SICStus Prolog, que permitira realizar las
consultas pertinentes.
5

Tambien es posible acceder desde Emacs al sistema de ayuda de SICStus Prolog:


- el men
u Help/Manuals/Browse Manuals with Info permite acceder a los manuales de
usuario de SICStus.
- la opcion Help on Predicate (CONTROL-C ?) del men
u contextual Prolog antes
citado ofrece ayuda sobre los predicados predefinidos de Prolog.
2.3.2.

SWI-Prolog

SWI-Prolog es un compilador de Prolog de dominio p


ublico dise
nado e implementado en la Universidad de Amsterdam, compatible con el estandar ISO y disponible para distintas plataformas. Se puede obtener en la direccion http://www.swi-prolog.org. La version para Windows

consta de un u
nico fichero ejecutable que instala automaticamente el sistema. Este
se utiliza de
acuerdo con el esquema general de trabajo en Prolog descrito mas arriba.

3.

Prolog y el paradigma de la Programaci


on L
ogica

Como se ha visto previamente, existen muchos modelos distintos de programacion logica, que
se distinguen dependiendo del tipo de Logica utilizada para representar el conocimiento y del
mecanismo de demostracion automatica elegido. El lenguaje Prolog se basa en la Programaci
on
L
ogica Definida estudiada en el tema anterior, pero con ciertas peculiaridades, tanto sintacticas
como semanticas, que se discuten a continuacion.

3.1.

Sintaxis

3.1.1.

T
erminos

Al igual que en Logica de Primer Orden, los terminos en Prolog se clasifican en tres categoras:
constantes, variables y terminos compuestos.
Constantes
Prolog distingue dos tipos de constantes:
N
umeros. Este tipo de constantes se utilizan para representar tanto n
umeros enteros como
n
umeros reales y poder realizar con ellos operaciones aritmeticas.
- La representacion mas corriente de los n
umeros enteros es la notacion decimal habitual
(por ejemplo 0, 1, -320, 539, etc) aunque tambien se pueden representar en otras
bases no decimales.
- Los n
umeros reales se pueden representar tanto en notacion decimal (por ejemplo
1.0, -3.14) como en notacion exponencial (por ejemplo 4.5E6, -0.12e+3, 12.0e-2). En
ambos casos debera haber siempre por lo menos un dgito a cada lado del punto.


Atomos.
Los atomos (no confundir con las formulas atomicas de la LPO) se utilizan para
dar nombre a objetos especficos, es decir, representan individuos concretos. Existen tres
clases principales de atomos:
- cadenas formadas por letras, dgitos y el smbolo de subrayado, que deben empezar
necesariamente por una letra min
uscula.
Cadenas validas: f, pepe1, libro33a, libro_blanco.
Cadenas no validas: 1libro, libro-blanco, _hola, Libro.
- cualquier cadena de caracteres encerrada entre comillas simples.
Ejemplos: SICStus Prolog, Libro-blanco, 28003 Madrid.
Estos atomos son u
tiles cuando se necesita trabajar con constantes que empiecen por
una letra may
uscula o por un dgito.
- existe ademas otro tipo de atomos, compuestos por combinaciones especiales de signos,
de uso menos com
un.
Variables
Las variables en Prolog se representan mediante cadenas formadas por letras, dgitos y el smbolo
de subrayado, pero deben necesariamente empezar por una letra may
uscula o por un smbolo de
subrayado.
Ejemplos: X, Resultado_1, Entrada, _total3, _3bis, _
Las variables que empiezan con un smbolo de subrayado, _, se denominan variables an
onimas,
y se usan cuando se necesita trabajar con variables cuyos posibles valores no interesan. Su
utilidad se describira mas adelante al analizar la construccion de programas y consultas.
T
erminos Compuestos
Los terminos compuestos, o estructuras, se construyen mediante un smbolo de funcion, denominado functor, que se denota mediante un atomo, seguido, entre parentesis, por una serie de
terminos separados por comas, denominados argumentos.
Ejemplos: fecha(1,mayo,2001), punto(X,Y), recta(punto(1,2), punto(3,5))
Nota: al escribir un termino compuesto, no puede haber ning
un espacio entre el functor y
el parentesis abierto previo a los argumentos. Por ejemplo, punto (X,Y) no es un termino
compuesto correcto y producira un error de compilacion.
Prolog tambien permite escribir ciertos terminos compuestos en forma de operadores, generalmente en notacion infija en el caso de functores de aridad 2 y en notacion prefija o postfija en
el caso de functores de aridad 1. Este es el caso de los operadores aritmeticos predefinidos de
Prolog, que se mencionaran mas adelante, y que permiten escribir terminos compuestos de la
forma X+Y o -X en lugar de +(X,Y) o -(X). El programador tambien puede definir sus propios
operadores.
Uno de los terminos compuestos mas importantes y u
tiles que ofrece Prolog son las listas,
secuencias ordenadas de cero o mas elementos, donde los elementos pueden ser cualquier tipo
de termino. Prolog representa las listas teniendo en cuenta su estructura recursiva:
- la lista vaca se representa mediante el atomo [].
7

- toda lista no vaca tiene una cabeza (que sera cualquier termino) y un resto (que sera una
lista), y se representa mediante un termino compuesto de aridad 2, cuyo functor es un
punto y cuyos argumentos son, respectivamente, la cabeza y el resto de la lista.
Ejemplos: la lista compuesta por un u
nico elemento, la constante a, se representa como (a, []).
La lista compuesta por los elementos a, b y c se corresponde con la estructura (a, (b, (c, []))).
Dado que la notacion anterior puede resultar incomoda a la hora de escribir listas complicadas,
Prolog admite tambien una notacion mas sencilla que consiste en enumerar entre corchetes
todos los elementos de la lista, separados por comas. Con esta notacion, las dos listas del
ejemplo anterior se representaran, respectivamente, como [a] y [a, b, c]. Prolog tambien dispone
de otra notacion para las listas, que consiste en representar la lista con cabeza X y resto Y
mediante el termino [X|Y ]. Esta u
ltima notacion es fundamental para poder separar la cabeza
del resto de una lista. Su utilidad en la practica se vera en las clases de problemas.
3.1.2.

Programas

Los programas Prolog son programas logicos definidos, y estan por lo tanto compuestos por
una serie de clausulas de Horn positivas, esto es, hechos y reglas. Hay que tener en cuenta sin
embargo las siguientes diferencias en cuanto a la notacion empleada en la Programacion Logica
Definida:
Los smbolos de predicado se denotan mediante a
tomos, por lo que no pueden empezar,
como ocurre en Programacion Logica, mediante una letra may
uscula. Observese por lo
tanto que el lenguaje Prolog no distingue entre smbolos de predicado, smbolos de funcion y constantes, puesto que todos ellos se representan mediante atomos (el compilador
distingue unos de otros dependiendo del contexto en el que aparecen). Para referirse a un
predicado nombre_predicado se suele emplear la notacion nombre_predicado/n, donde
n indica el n
umero de argumentos del predicado.
Los hechos deben terminar con un punto y omitir el smbolo utilizado en Programacion Logica. As, el hecho A se escribe en Prolog de la forma A..
Las reglas deben tambien terminar con un punto y sustituir el smbolo de la Programacion Logica por el smbolo :-. As, la regla A A1 , . . . , An se escribe en Prolog
de la forma A :- A1 , . . . , An ..
Nota: Al trabajar en Prolog se suele aplicar un convenio estandar para describir el uso de
los predicados (tanto predefinidos como definidos por el programador): en los programas, las
clausulas de cada predicado deberan ir precedidas de un comentario incluyendo una lnea que
describa su uso, as como una descripcion en lenguaje natural de su cometido. El convenio para
describir el uso de un predicado es el siguiente:
nombre_predicado(#NomVar_1, ...., #NomVar_n)
donde NomVar_1, ..., NomVar_n son nombres de variables y el smbolo #, que sirve para indicar
como debe usarse el argumento correspondiente al realizarse una consulta, puede tomar uno de
los tres siguientes valores:
8

+ para indicar que el argumento correspondiente debe estar, en la consulta, instanciado con un
termino no variable (este tipo de argumentos se corresponden por lo tanto con parametros
de entrada).
- para indicar que el argumento correspondiente no debe estar instanciado en la consulta, es
decir, debe ser una variable (este tipo de argumentos se corresponden por lo tanto con
parametros de salida).
? para indicar que el argumento puede estar tanto instanciado como no instanciado (es decir,
se trata de parametros que se pueden usar tanto para entrada como para salida).
Por ejemplo, el predicado predefinido sort/2, que sirve para ordenar listas de elementos, se describe como sort(+Lista1, ?Lista2), indicando as que para utilizarlo el primer argumento debe estar instanciado (debe ser una lista concreta). Por lo tanto, el predicado sort/2 se podra utilizar en consultas de la forma ?- sort([c,v,a], X). o ?- sort([c,v,a], [a,c,v]).,
pero si se intenta hacer una consulta en la que el primer argumento no este instanciado, como
por ejemplo ?- sort(X, [c,v,a])., se producira un error.
Ejemplo: Los programas logicos para el calculo del factorial y la suma de n
umeros naturales
estudiados en el tema anterior eran programas logicos definidos, por lo que se pueden convertir
facilmente en programas Prolog con solo adaptar su sintaxis de acuerdo con lo establecido mas
arriba (ficheros factorial.pl y suma.pl):

PROGRAMA LOGICO
DEFINIDO

PROGRAMA PROLOG
% factorial(?X,?Y)
% cierto si Y es el factorial de X
factorial(0,s(0)).
factorial(s(X),s(X)*Y) :- factorial(X,Y).
% suma(?X,?Y,?Z)
% cierto si Z es la suma de X e Y
suma(X,0,X).
suma(X,s(Y),s(Z)) :- suma(X,Y,Z).

Factorial(0,s(0))
Factorial(s(x),s(x)*y) Factorial(x,y)

Suma(x,0,x)
Suma(x,s(y),s(z)) Suma(x,y,z).

Observese que en los ejemplos anteriores las variables X, Y y Z aparecen a ambos lados de las
respectivas reglas. Existen sin embargo casos en los que una variable aparece solo a un lado de
una regla y sus posibles valores no tienen importancia. En estos casos no es necesario pensar
un nombre de variable sino que basta con usar la variable anonima _.
Ejemplo: Supongase que, dado el predicado factorial, se necesita definir a partir de el un
predicado es_factorial(X) que es cierto si X es el factorial de alg
un n
umero natural. Una
forma de definir este predicado sera estableciendo que X es un factorial siempre y cuando
exista alg
un Y tal que X sea el factorial de ese Y , es decir:
% es_factorial(?X): cierto si X es el factorial de alg
un n
umero
es_factorial(X) :- factorial(Y,X).
Sin embargo, en este caso el posible valor de la variable Y es indiferente, puesto que lo u
nico
que se quiere saber es si X es el factorial de alg
un n
umero, sin importar quien sea este. As, la
definicion anterior se podra sustituir por:
es_factorial(X) :- factorial(_,X).
9

3.1.3.

Consultas para la activaci


on de programas

Al estar Prolog basado en la Programacion Logica Definida, las u


nicas consultas que se pueden
realizar para activar un programa Prolog se corresponden con clausulas de Horn negativas,
esto es, cl
ausulas objetivo (cl
ausulas meta). Se recuerda que estas clausulas, que son de la
forma A1 , . . . , An , se corresponden con la negacion de formulas x1 . . . xp (A1 . . . An ),
p 0, n 1, donde A1 , . . . , An son predicados. En Prolog, las consultas deben terminar siempre
con un punto, y el smbolo de la Programacion Logica debe sustituirse por el smbolo ?-.
As, la consulta A1 , . . . , An se escribe en Prolog de la forma ?- A1 , . . . , An .. Observese
sin embargo que no sera necesario escribir el smbolo ?-, puesto que, como se ha comentado
antes, dicho smbolo aparece directamente en el sistema Prolog.
Ejemplo: Dados los programas para el calculo del factorial y para la suma facilitados previamente, algunas consultas posibles seran las siguientes:
?- factorial(s(s(s(0))), Fact3). Cu
anto vale el factorial de 3?
?- factorial(s(s(0)), s(s(0))). Es cierto que el factorial de 2 es 2?
?- factorial(0,Z), factorial(s(s(0)),Z). Existe alg
un n
umero natural que sea igual
al factorial de 0 y al factorial de 2? Cu
al?
?- suma(s(0), s(0), X). Cu
anto vale la suma 1+1?
?- suma(X, Y, s(s(0))). Que n
umeros existen tales que su suma sea 2?
?- suma(s(0), Y, s(s(s(0)))). Cu
ales son los n
umeros tales que sumados a 1 dan 3?
Las consultas anteriores incluyen variables no anonimas, puesto que el objetivo no es solo saber
si existen n
umeros que cumplan lo pedido sino que se desea ademas conocer su valor. Existen
sin embargo ocasiones en las que las consultas pueden incluir variables anonimas.
Ejemplo: En la u
ltima consulta del ejemplo anterior se pretenda averiguar cual es el n
umero
natural tal que sumado a 1 da 3. Sin embargo, si lo u
nico que se desea saber es si existe alg
un
n
umero natural tal que sumado a 1 de 3, bastara con utilizar una variable anonima:
?- suma(s(0), _, s(s(s(0)))).
3.1.4.

Resumen

Como se acaba de ver, la sintaxis del lenguaje Prolog, aunque se basa en la sintaxis de la Programacion Logica Definida, presenta ciertas diferencias respecto a esta u
ltima. A continuacion
se resumen las mas importantes:
- los smbolos de variable se escriben empezando por una letra may
uscula o por un smbolo de
subrayado.
- los smbolos de predicado se escriben empezando por una letra min
uscula, al igual que los
smbolos de funcion y las constantes.

10

- las clausulas de Horn terminan siempre con un punto. Ademas:


en las reglas, el smbolo se sustituye por el smbolo :-
en los hechos, el smbolo desaparece.
en las cl
ausulas objetivo, el smbolo se sustituye por el smbolo ?-.
La siguiente tabla resume las distintas notaciones para clausulas de Horn vistas hasta el momento:

NOTACION
clausular
logica estandar
prog. logica
Prolog

3.2.

REGLAS
{A1 , . . . , An , A}
x1 . . . xp [(A1 . . . An ) A]
A A 1 , . . . , An
A :- A1 , . . . , An .

HECHOS
{A}
x1 . . . xp (A)
A
A.

METAS
{A1 , . . . , An }
x1 . . . xp (A1 . . . An )
A 1 , . . . , An
?- A1 , . . . , An .

Sem
antica

El mecanismo de demostracion automatica utilizado por Prolog es el sistema de Resoluci


on
SLD estudiado en el tema anterior, pero implementado de acuerdo con las siguientes pautas:
Unificaci
on. Prolog usa el algoritmo de unificacion estandar estudiado en el tema anterior
pero, por razones de eficiencia, no suele incluir el test de ocurrencia. Aunque la omision de
este test puede llevar a la obtencion de resultados erroneos, esto ocurre raramente. Prolog
permite al programador la utilizacion directa de su algoritmo de unificacion mediante los
dos siguientes predicados predefinidos, que se pueden usar en notacion infija:
- el predicado =, que devuelve cierto si las dos expresiones que se le pasan resultan ser,
omitiendo el test de ocurrencia, unificables.
- el predicado \=, que devuelve cierto si el predicado = falla y falso en caso contrario.
Ejemplos:
?- f(X, g(b,c)) = f(Z, g(Y,c)).
Y = b, Z = X ?
yes
?- f(X, g(b,c)) = f(Z, g(Y,d)).
no
?- [a,b,[c,d]] = [X|Y].
X = a, Y = [b,[c,d]] ?
yes
?- 3+5 = 8.
no % 3+5 no es m
as que el t
ermino compuesto +(3,5)
11

?- X = f(X).
X = f(f(f(f(f(f(f(f(f(f(...)))))))))) ?
yes
% no se realiza el test de ocurrencia
Nota: algunas implementaciones de Prolog, como por ejemplo SICStus Prolog, incorporan
un predicado predefinido especial que permite unificar con test de ocurrencia. En SICStus
Prolog este predicado se denomina unify_with_occurs_check.
?- unify_with_occurs_check(X,f(X)).
no
% s
se realiza el test de ocurrencia
Funci
on de selecci
on. Selecciona siempre el literal mas a la izquierda.
Regla de ordenaci
on. Elige las clausulas de acuerdo con el orden en el que estas aparecen
en el programa.
Estrategia de b
usqueda: b
usqueda en profundidad (se recuerda que esta estrategia es muy
eficiente pero tiene el inconveniente de que no es completa, esto es, puede conducir a una
computacion infinita a
un en el caso de que exista una solucion).
Por lo tanto, cuando, una vez cargado un programa logico, se realiza una consulta, Prolog
construye el arbol de Resolucion SLD correspondiente, de acuerdo con la funcion de seleccion y
la regla de ordenacion citadas, haciendo un recorrido en profundidad. As, las posibles respuestas
del sistema ante una consulta son las siguientes:
Si todas las ramas del arbol SLD son ramas fallo, la respuesta del sistema sera no.
Si el arbol SLD tiene alguna rama infinita m
as a la izquierda que cualquier posible rama
exito, la reaccion del sistema dependera de la implementacion concreta de Prolog que se
este utilizando. Algunos sistemas, como por ejemplo SWI-Prolog, presentan un mensaje
de error. Otros, como es el caso de SICStus Prolog, no responden, por lo que es necesario
interrumpir la ejecucion de la consulta mediante CONTROL-C (si se esta usando SICStus
Prolog a traves de Emacs, la composicion de teclas CONTROL-C debera efectuarse dos
veces seguidas). Una vez interrumpida la ejecucion, el sistema muestra por pantalla el
mensaje:
Prolog interruption (h for help)?
y acepta a continuacion una letra que determine la accion a seguir. Las posibles acciones
se pueden consultar pulsando la tecla h, aunque lo mas habitual sera contestar con la
letra a, cuya accion asociada es abortar la ejecucion de la consulta.
En otro caso (es decir, cuando el arbol de Resolucion tiene por lo menos una rama exito
mas a la izquierda que cualquier posible rama infinita):
- Si la consulta realizada no tiene variables (o las que tiene son anonimas), la respuesta
del sistema sera yes, terminandose as la ejecucion de la consulta.
- Si la consulta realizada tiene alguna variable no anonima, el sistema muestra por
pantalla los valores de las variables que se corresponden con la primera rama exito
encontrada al buscar en profundidad en el arbol de Resolucion, y queda a la espera
de nuevas instrucciones por parte del usuario:
12

si se introduce un retorno de carro, el sistema contesta yes y abandona la


b
usqueda de posibles nuevas soluciones.
si se introduce un punto y coma seguido de un retorno de carro, el sistema continua
la b
usqueda de nuevas soluciones en el arbol de Resolucion, con lo que el proceso
se vuelve a repetir, dependiendo la respuesta del resultado de la b
usqueda (no
si termina de recorrer el arbol sin encontrar ninguna nueva solucion ni ninguna
rama infinita, computacion infinita si encuentra una rama infinita o valor de las
variables correspondientes en caso de encontrarse otra solucion).
Como ya se comento en el tema anterior, resulta claro que tanto el orden en el que aparecen
las clausulas en los programas como el orden de los literales dentro de las clausulas pueden
influir no solo en el orden en el que aparecen las soluciones sino tambien en la terminacion de
las consultas que se realizan.
Ejemplo: Considerese el siguiente programa (ancestros.pl), que incluye, ademas de un predicado progenitor(X,Y) que es cierto cuando X es progenitor de Y , cuatro versiones distintas
del predicado ancestro(X,Y), cierto cuando X es un ancestro de Y . Las cuatro versiones varan
dependiendo del orden de sus clausulas y del orden en el que se colocan los literales dentro de
ellas.
% progenitor(?X, ?Y): cierto si X es progenitor de Y
progenitor(pepa, pepito).
progenitor(pepito, pepin).
% ancestro(?X, ?Y): cierto si X es un ancestro de Y
% VERSI
ON 1
ancestro1(X, Y) :- progenitor(X, Y).
ancestro1(X, Y) :- progenitor(X, Z), ancestro1(Z, Y).
% VERSI
ON 2
ancestro2(X, Y) :- progenitor(X, Z), ancestro2(Z, Y).
ancestro2(X, Y) :- progenitor(X, Y).
% VERSI
ON 3
ancestro3(X, Y) :- progenitor(X, Y).
ancestro3(X, Y) :- ancestro3(Z, Y), progenitor(X, Z).
% VERSI
ON 4
ancestro4(X, Y) :- ancestro4(Z, Y), progenitor(X, Z).
ancestro4(X, Y) :- progenitor(X, Y).
Aunque las cuatro definiciones anteriores del predicado ancestro son iguales desde el punto
de vista logico, su comportamiento en Prolog es distinto, ya que daran lugar a arboles de
Resolucion distintos. Por ejemplo, si se intenta averiguar de quien es ancestro pepa, resulta lo
siguiente (compruebense estos resultados mediante la construccion de los arboles de resolucion
SLD correspondientes):
13

Consulta con ancestro1: ofrece las dos posibles soluciones y termina.


?- ancestro1(pepa, D).
D = pepito ? ;
D = pepin ? ;
no
Consulta con ancestro2: ofrece las dos posibles soluciones (en orden inverso al caso
anterior) y termina.
?- ancestro2(pepa, D).
D = pepin ? ;
D = pepito ? ;
no
Consulta con ancestro3: ofrece las dos posibles soluciones, en el mismo orden que
ancestro1, pero si se piden mas soluciones la consulta no termina.
?- ancestro3(pepa, D).
D = pepito ? ;
D = pepin ? ;
% el sistema entra en un bucle, que se interrumpe con CTRL-C CTRL-C
Prolog interruption (h for help)? a
{Execution aborted}
Consulta con ancestro4: no produce ninguna solucion, porque entra directamente en
una rama infinita.
?- ancestro4(pepa, D).
% el sistema entra en un bucle, que se interrumpe con CTRL-C CTRL-C
Prolog interruption (h for help)? a
{Execution aborted}
Aunque no existe ninguna regla general que establezca el orden optimo de las clausulas ni el
orden optimo de los literales dentro de ellas, s suelen ser recomendables los siguientes principios
basicos, basados en la idea de hacer antes lo mas sencillo:
1. Colocar las clausulas que expresan las condiciones de parada de la recursividad antes que
las otras (esto se cumple en las versiones 1 y 3 del ejemplo anterior).
2. Evitar las reglas con recursion a la izquierda, es decir, las reglas tales que el primer literal
de su cuerpo es una llamada recursiva al mismo predicado de la cabeza de la regla (las
versiones 3 y 4 del ejemplo anterior presentan recursion a la izquierda).
De las cuatro versiones del ejemplo anterior, la u
nica que cumple estas dos recomendaciones es
la primera.
Es por otro lado necesario evitar definiciones circulares del estilo:
14

progenitor(X,Y) :- hijo(Y,X).
hijo(A,B) :- progenitor(B,A).
puesto que cualquier consulta a uno de los dos predicados anteriores provocara necesariamente
un bucle infinito.

4.

Predicados Predefinidos

En el apartado anterior se ha resumido el funcionamiento del lenguaje Prolog desde el punto


de vista del paradigma de la Programacion Logica. Sin embargo, las facilidades descritas no
son suficientes para obtener un lenguaje de programacion u
til en la practica: por ejemplo,
todo lenguaje de programacion real necesita facilidades para leer y/o escribir o mecanismos
eficientes para realizar operaciones aritmeticas. Para ello, el lenguaje Prolog incorpora toda una
serie de predicados del sistema o predicados predefinidos (system or built-in predicates) que
ofrecen al usuario facilidades como las citadas as como otro tipo de funcionalidades extra-logicas
o meta-logicas. Estos predicados no pueden ser redefinidos por el programador.
En lo que sigue se describen solo algunos de estos predicados predefinidos, en concreto los relacionados con la realizacion de operaciones aritmeticas, ciertos predicados para entrada/salida
y el predicado de control denominado corte.

4.1.
4.1.1.

Aritm
etica
Operadores aritm
eticos

Prolog tiene predefinidos los operadores aritmeticos mas habituales, mediante los que se pueden
formar expresiones aritmeticas. A continuacion se enumeran algunos de los mas importantes:
X+Y
X-Y
X*Y
X/Y
X//Y
X mod Y
abs(X)
sqrt(X)
log(X)

suma de X e Y
X menos Y
producto de X por Y
cociente real de la division de X por Y
cociente entero de la division de X por Y
resto de la division entera de X por Y
valor absoluto de X
raz cuadrada de X
logaritmo neperiano de X

Tengase en cuenta que los operadores anteriores permiten simplemente construir expresiones
aritmeticas, pero estas no son mas que estructuras (terminos compuestos) que no representan
ning
un valor. Por ejemplo, la expresion 3+5 no es mas que el termino compuesto +(3,5) escrito
en notacion infija. As, no es posible hacer consultas del estilo ?- 3+5., puesto que + no
es un predicado, y si se hiciese la consulta ?- 3+5 = 8., la respuesta de Prolog sera no,
dado que el termino compuesto +(3,5) no es unificable con el termino constante 8.
Para poder evaluar expresiones aritmeticas en Prolog hay que utilizar los predicados aritmeticos
que se describen a continuacion.
15

4.1.2.

Predicados aritm
eticos

Los predicados aritmeticos predefinidos de Prolog se utilizan para evaluar expresiones aritmeticas. El mas habitual es el predicado predefinido is, que se usa en notacion infija de la siguiente
forma:
X is Y

Si Y es una expresion aritmetica, esta se eval


ua y el resultado
se intenta unificar con X.

A la hora de usar este predicado hay que tener en cuenta las siguientes consideraciones:
1. Su uso puede dar lugar a un error en los dos siguientes casos:
a) cuando la parte derecha no es una expresion aritmetica:
?- X is a+1.
{DOMAIN ERROR: _157 is a+1 - arg 2: expected expression, found a}
b) cuando la parte derecha es una expresion aritmetica pero no se puede evaluar:
?- X is 4*Z.
{INSTANTIATION ERROR: _157 is 4*_155 - arg 2}
2. Salvo en los casos anteriores, el resultado del predicado dependera de si la parte izquierda
unifica o no con el resultado obtenido al evaluar la parte derecha:
?- X is sqrt(4).
X = 2.0 ?
yes

?- 5 is 2+3.
yes

?- X is 5, Y is X+1.
X = 5, Y = 6 ?
yes

?- 3+5 is 3+5.
no

La respuesta negativa obtenida en el u


ltimo ejemplo se debe a que la expresion 3+5 de
la parte izquierda (recuerdese que se trata simplemente del termino compuesto +(3,5))
no es unificable con el entero 8, resultante de evaluar la parte derecha.
Ademas del predicado anterior, Prolog incorpora otros predicados comunes para comparaciones
aritmeticas, aunque en algunos casos con una notacion distinta a la habitual: observense en
particular los smbolos para la igualdad/desigualdad (que no pueden ser los habituales = y \=
puesto que estos se utilizan para la unificacion) y la comparacion menor o igual, que se escribe
al reves de lo que suele ser normal en otros lenguajes de programacion (<=).
X
X
X
X
X
X

=:= Y
=\= Y
< Y
=< Y
> Y
>= Y

cierto
cierto
cierto
cierto
cierto
cierto

si
si
si
si
si
si

los valores numericos de X e Y son iguales


los valores numericos de X e Y son distintos
el valor numerico de X es menor que el de Y
el valor numerico de X es menor o igual que el de Y
el valor numerico de X es mayor que el de Y
el valor numerico de X es mayor o igual que el de Y

El funcionamiento de estos predicados es similar al del predicado is: produciran un error


en caso de que alguno de los dos argumentos no sea una expresion aritmetica o, a pesar de
16

serlo, no se pueda evaluar. En caso contrario, el sistema eval


ua las dos expresiones aritmeticas
y devuelve el resultado de la comparacion solicitada.
?- X+3 < sqrt(4).
.. ERROR: ..
4.1.3.

?- 3+5 =:= 8.
yes

?- 1+ 5 > abs(-8).
no

?- 3 =\= 3*a.
.. ERROR: ..

Programas aritm
eticos en Prolog

En el tema anterior, relativo a la Programacion Logica general, se estudiaron varios programas


logicos aritmeticos, como por ejemplo los programas para el calculo de la suma y el factorial
de n
umeros naturales. Se trataba en ambos casos de programas logicos definidos, por lo que
basta con adaptar su sintaxis para obtener los correspondientes programas en Prolog (vease el
apartado 3.1.2 de este documento).
Los programas aritmeticos del estilo de los anteriores se pueden considerar programas logicos
puros, puesto que estan definidos utilizando exclusivamente propiedades logicas, y tienen dos
caractersticas principales:
- Son, por un lado, programas sencillos y vers
atiles. Recuerdese en particular como pueden
utilizarse para varios cometidos distintos -por ejemplo el programa de la suma tambien
sirve para restar- ya que cualquiera de sus argumentos puede usarse tanto de entrada
como de salida (veanse los ejemplos de consultas dados en el apartado 3.1.3).
- Son tambien, sin embargo, inc
omodos de utilizar en la pr
actica y poco eficientes. Su incomodidad proviene del hecho de que los n
umeros naturales se deben manipular mediante
la funcion sucesor, y la ineficiencia se debe al calculo recursivo utilizado para resolver
operaciones aritmeticas elementales.
Una alternativa evidente para mejorar la comodidad y la eficiencia de estos programas es reemplazarlos por otros que hagan uso de las facilidades aritmeticas ofrecidas por Prolog, tanto en
lo que se refiere al uso de sus constantes numericas como al uso de los operadores y predicados
aritmeticos mencionados mas arriba. As, si se desease disponer de un predicado para sumar
n
umeros naturales, bastara con definirlo como sigue, utilizando simplemente el predicado de
evaluacion is:
% suma(+X,+Y,?Z): cierto si Z es la suma de X e Y
suma(X,Y,Z) :- Z is X+Y.
Esta version del predicado suma es claramente mucho mas comoda (permite utilizar directamente n
umeros naturales en notacion decimal) y mucho mas eficiente (utiliza la potencia de
calculo aritmetico del ordenador). Tiene sin embargo la desventaja respecto a la version logica
pura de que pierde la versatilidad de esta. En efecto, como se puede ver en el comentario previo
a la definicion del nuevo predicado, este, a diferencia del anterior, solo se puede usar cuando sus
dos primeros argumentos estan instanciados: si se intenta usar de otra forma se producira un
error. Esto es debido a la utilizacion en el cuerpo de la regla del predicado predefinido is, que,
como se vio antes, requiere que su parte derecha este instanciada.
17

De forma similar, una definicion mas eficiente -aunque menos elegante- del predicado factorial
sera la siguiente:
% factorial(+X, ?Y): cierto si Y es el factorial de X.
factorial(0, 1).
factorial(X, Y) :X >0, X1 is X-1, factorial(X1, FactX1), Y is X*FactX1.
Por el mismo motivo que antes, el predicado anterior solo se podra usar cuando el primer
argumento este instanciado, es decir, el predicado es valido para calcular factoriales, pero no
sirve ya para averiguar si un n
umero es o no el factorial de alg
un otro n
umero. Esta restriccion
no solo afecta al uso directo del predicado, sino tambien a su capacidad para ser usado en la
definicion de otros: por ejemplo, el predicado es_factorial que se describio en el apartado
2.1.2. a partir de la version logica del predicado factorial ya no podra definirse utilizando
esta nueva version. Observese asimismo que en la nueva version se ha introducido, antes de la
llamada recursiva, la comprobacion X>0, necesaria si se quiere evitar que se produzca una rama
infinita en el arbol de Resolucion SLD correspondiente (constr
uyanse como ejercicio los arboles
de Resolucion asociados a una consulta concreta con y sin la comprobacion anterior).

4.2.

Entrada/Salida

El lenguaje Prolog ofrece toda una serie de predicados predefinidos para la realizacion de operaciones de entrada/salida. Se trata de predicados que no tienen sentido desde un punto de vista
puramente logico, sino que producen un efecto colateral (escritura/lectura de alg
un termino,
apertura/cierre de un fichero, etc). A continuacion se describen algunos de los predicados de
entrada/salida mas basicos:
open(+NombreFichero, +Modo, -Fichero)
Si NombreFichero es un nombre de fichero valido, abre el fichero correspondiente de
acuerdo con el modo especificado por Modo, y unifica con Fichero el identificador del
fichero abierto. Los valores para el argumento Modo pueden ser:
read para abrir el fichero en modo lectura.
write para abrir el fichero en modo escritura (si el fichero no existe, lo crea; si ya existe,
su contenido se perdera).
append para abrir el fichero en modo escritura (si el fichero no existe, lo crea; si ya existe,
las operaciones de escritura se realizaran al final del fichero).
close(+Fichero)
Cierra el fichero asociado con el identificador Fichero.
set_input(+Fichero)

set_output(+Fichero)

Convierte al fichero con identificador Fichero en el fichero de lectura (escritura) actual.


current_input(?Fichero)

current_output(?Fichero)

Fichero es el fichero de lectura (escritura) actual.


18

Nota: el fichero por defecto, tanto para lectura como para escritura, es la pantalla, cuyo
identificador es user.
read(?Termino)

read(+Fichero, ?Termino)

Lee el siguiente termino (del fichero de lectura actual o del fichero especificado, previamente abierto en modo lectura) y unifica el resultado con Termino. El termino debe acabar
con un punto y un retorno de carro.
write(?Termino)

write(+Fichero, ?Termino)

Escribe el termino Termino en el fichero de escritura actual o en el fichero especificado


(previamente abierto en modo escritura).
nl

nl(+Fichero)
Escribe un retorno de carro en el fichero de escritura actual o en el fichero especificado
(previamente abierto en modo escritura).

Ejemplos: Se incluyen a continuacion algunos ejemplos tpicos de predicados que realizan operaciones de entrada/salida (fichero entrada-salida.pl):
% pide_numero(-X)
% X es un n
umero le
do del fichero de lectura actual
pide_numero(X) :write(Introduzca un n
umero: ),
nl,
read(X).
% escribe_cuadrado(+X)
% escribe el cuadrado de X en el fichero de escritura actual
escribe_cuadrado(X) :X2 is X*X,
write(El cuadrado de ),
write(X),
write( es ),
write(X2).
% pide un n
umero y escribe su cuadrado por pantalla
cuadrado :pide_numero(X),
escribe_cuadrado(X).
% imprime_lista(+Fichero, +L)
% Si Fichero es un identificador de fichero y L es una lista,
% escribe los elementos de L en el fichero, uno por l
nea
imprime_lista(_Fichero, []).
imprime_lista(Fichero, [C|R]) :write(Fichero, C),
nl(Fichero),
imprime_lista(Fichero, R).
19

% imprime_lista(+L)
% Si L es una lista, imprime por pantalla sus elementos, uno por l
nea
imprime_lista(L) :imprime_lista(user, L). % user es el identificador de la pantalla
% pide una lista y la imprime en un fichero
prueba_fich :write(Introduzca una lista: ), nl,
read(Lista),
open(prueba.txt, write, Prueba),
imprime_lista(Prueba, Lista),
write(la lista se ha escrito en el fichero prueba.txt),
close(Prueba).
A continuacion se reproduce la ejecucion de algunos de los predicados anteriores:
?- cuadrado.
Introduzca un n
umero:
|: 3.
El cuadrado de 3 es 9
yes
?- imprime_lista([esto,es,una,lista]).
esto
es
una
lista
yes
?- prueba_fich.
Introduzca una lista:
|: [h,o,l,a].
la lista se ha escrito en el fichero prueba.txt
yes
La ejecucion de este u
ltimo predicado tiene como efecto colateral la escritura de los elementos
de la lista [h,o,l,a] en el fichero prueba.txt.

4.3.

Control: el corte

Los predicados de control son predicados predefinidos que permiten al programador intervenir
en el mecanismo de b
usqueda de soluciones de Prolog. En este apartado se va a introducir
exclusivamente uno de ellos, el denominado predicado de corte.
20

4.3.1.

Definici
on y propiedades

El corte es un predicado predefinido que se denota mediante un punto de exclamacion (!), no


tiene argumentos, y cuya evaluacion es siempre cierta. Se puede incluir, como un predicado
mas, en el cuerpo de las reglas o en las consultas (por ejemplo a :- b, c, !, d.).
Los cortes permiten al programador intervenir en el control del programa, puesto que su presencia hace que el sistema ignore ciertas ramas del a
rbol SLD correspondiente. En concreto, el
efecto de los cortes en la construccion y recorrido de los arboles de resolucion SLD se produce
cuando el sistema llega a un nodo del arbol cuyo primer predicado es un corte, es decir, un nodo
de la forma ?- !,a1,..,an.. En estos casos ocurre lo siguiente (siendo N el nodo anterior):
1. El predicado de corte siempre se eval
ua como cierto, por lo que el nodo N tendra un u
nico
hijo, que sera igual a N pero sin el corte, es decir, sera de la forma ?- a1,..,an.. La
expansion de este nodo se realiza igual que la expansion de cualquier otro nodo del arbol.
2. Tanto para cada uno de los nodos ascendientes de N que contengan el corte como para el
primer ascendiente que no lo contiene (sea N dicho nodo) se ignoran todas sus posibles
ramas situadas mas a la derecha de la rama que lleva a N.
La siguiente figura ilustra lo anterior. Las ramas tachadas con una raya son aquellas que se
ignoran como consecuencia del corte.



 
  
 
  

Ejemplo. Considerese el programa Prolog dado por las siguientes clausulas:


a :- b, c.
a :- ....
b :- d, !, e.
b.
21

b :- ....
d.
d :- ....
e :- ....

La figura incluida a continuacion muestra el arbol de Resolucion SLD resultante al realizarse


la consulta ?-a. Las ramas tachadas son las que se deben ignorar debido al corte.



 




   

  

 

 

   

 

El efecto de la existencia de una regla de la forma a:-a1,..,ai,!,..,an se produce por


lo tanto cuando el sistema llega a la evaluacion del corte, y consiste en hacer que todas las
opciones tomadas desde el momento en el que aparece la clausula objetivo conteniendo un corte
(incluida la decision que lleva a la consideracion de esta clausula) hasta la evaluacion del corte
sean obligatorias, eliminandose cualquier alternativa. En concreto:
En el momento de evaluar el corte, el sistema ya ha encontrado soluciones para los objetivos a1,..,ai, y no se consideraran otras alternativas para ninguno de ellos (en el ejemplo
anterior, no se consideran nuevas alternativas para el objetivo d).
Tampoco se consideraran otras alternativas para el predicado responsable de la introduccion del corte (en el ejemplo anterior, el predicado b).
El predicado de corte tiene dos ventajas fundamentales:
Su utilidad basica, dado que reduce el espacio de b
usqueda de soluciones, es mejorar la
eficiencia de los programas, evitando la exploracion de partes del arbol de resolucion de
las que se sabe de antemano que no conduciran a ninguna nueva solucion.
22

Por otro lado, el corte tambien permite aumentar la expresividad del lenguaje: su uso, normalmente en combinacion con otros predicados predefinidos, aporta nuevas construcciones
de gran utilidad, como por ejemplo la negacion por fallo finito.
Sin embargo, el corte es un predicado muy controvertido. Al tratarse de una herramienta de
control (interviene en c
omo se debe resolver el problema), su uso entra en clara contradiccion
con los principios basicos de la programacion logica pura, que preconiza una separacion ntida
entre la logica del problema (responsabilidad del programador) y la forma de resolverlo (responsabilidad del mecanismo de demostracion automatica). As, el corte puede conducir a programas
logicos difciles de leer y de validar, y puede provocar muchos errores de programacion.
En definitiva, el predicado de corte de Prolog constituye una herramienta de caracter extralogico, muy potente pero que debe usarse con mucho cuidado y en casos muy concretos.
4.3.2.

Usos del corte. Ejemplos

Aunque el predicado de corte tiene usos muy variados (en general, en combinacion con otros
predicados predefinidos de Prolog) uno de los mas habituales es la simulacion de estructuras
condicionales de la forma:
si b1 entonces c1 ;
si no: si b2 , entonces c2 ;
....
si no: si bn , entonces cn ;
si no: c.
En Prolog, este tipo de estructuras, con condiciones mutuamente excluyentes, se representan
mediante un predicado definido por medio de n + 1 reglas, donde cada regla expresa una de
las posibles formas de calcular el predicado: la regla i-esima expresa que el predicado es cierto
si no se cumple ninguna de las condiciones b1 , ..., bi1 anteriores y, ademas, se cumplen las
condiciones bi y ci .
El corte permite simplificar la representacion anterior y conseguir un uso mas eficiente de este
tipo de estructuras. Su representacion utilizando el corte es la siguiente:
a :a :....
a :a :-

b1, !, c1.
b2, !, c2.
bn, !, cn.
c.

De esta forma se consigue que, en el momento en que se compruebe que se verifica una cierta
condicion bi, no se intente aplicar ninguna regla posterior.
A continuacion se describe el uso del corte mediante su aplicacion a varios ejemplos (todos ellos
contenidos en el fichero corte.pl).

23

Ejemplo 1: calculo de una funcion


Supongase que se necesita definir un predicado en Prolog que permita calcular la siguiente
funcion f un:

0,
1,
f un(x) =

2,

si x 10
si 10 < x 20
si x > 20

Una primera aproximacion para la resolucion del problema anterior es definir un predicado
f(X,Y), cierto si Y es igual a f un(X), mediante las tres siguientes reglas:
f(X,0) :- X =< 10.
f(X,1) :- X>10, X =< 20.
f(X,2) :- X > 20.
La representacion anterior calcula correctamente los valores de la funcion f un, pero tiene el
siguiente inconveniente. Supongase que se realiza la consulta ?- f(0,Z), Z>1.. La respuesta
de Prolog sera no, pero para llegar a dicha conclusion el sistema tiene que recorrer las 3
posibles ramas del arbol de Resolucion SLD correspondiente (dib
ujese como ejercicio dicho
arbol). Lo anterior es poco eficiente, puesto que, al ser las tres reglas que describen el predicado
f mutuamente excluyentes, una vez que se ha encontrado una solucion con una de ellas no
tiene sentido probar con el resto. En efecto, la funcion que se esta calculando tiene la siguiente
estructura condicional:
si X 10 entonces Y = 0;
si no: si X 20, entonces Y = 1;
si no: Y = 2.
Por lo tanto, una forma de remediar la ineficiencia anterior es utilizando el predicado de corte
como se ha indicado al principio de este apartado:
f(X,Y) :- X =< 10, !, Y=0.
f(X,Y) :- X =< 20, !, Y=1.
f(_X,2).
Con esta nueva version, la respuesta de Prolog a la consulta ?- f(0,Z), Z>1. sera tambien no, pero ahora, gracias a la introduccion del corte en la primera regla, el sistema solo
tendra que explorar la primera rama del arbol SLD.
Observese que una forma mas comoda para representar esta nueva version consistira en, al
igual que en la primera version, realizar la unificacion directamente en la cabeza de las reglas:
f(X,0) :- X =< 10, !.
f(X,1) :- X =< 20, !.
f(_X,2).

24

Sin embargo, hay que destacar que esta u


ltima version, a pesar de ser mas comoda de escribir,
tiene el inconveniente de que no siempre es correcta, porque no funciona adecuadamente para
ciertos usos del predicado: resuelve correctamente consultas de la forma ?- f(5,Z)., pero sin
embargo no siempre funciona con consultas en las que ambos argumentos estan instanciados:
por ejemplo, la respuesta del sistema ante la consulta ?- f(0,2). sera afirmativa, cuando
debera ser evidentemente negativa. Este problema no se da en las versiones anteriores.
Ejemplo 2: calculo del maximo de dos n
umeros
El procedimiento para calcular el maximo de dos n
umeros naturales se puede implementar en
Prolog mediante un predicado maximo(X,Y,Z), cierto si Z es el maximo de X e Y. Al igual que
en el ejemplo anterior, una primera version para dicho predicado podra ser la siguiente:
maximo(X,Y,X) :- X >= Y.
maximo(X,Y,Y) :- X < Y.

Dado que las dos opciones son mutuamente excluyentes, una forma mas comoda y eficiente de
expresar lo anterior es utilizando el corte:
maximo(X,Y,Z) :- X >= Y, !, Z=X.
maximo(_X,Y,Y).

Otra posibilidad, similar a lo que se comento en el ejemplo anterior, es modificar la version


anterior de forma que la unificacion se realice directamente en la cabeza de las clausulas:
maximo(X,Y,X) :- X >= Y, !.
maximo(_X,Y,Y).

Al igual que en el ejemplo anterior, resulta que esta u


ltima version no puede usarse de cualquier forma, porque con ciertas consultas puede dar lugar a resultados erroneos: por ejemplo,
la respuesta del sistema ante la consulta ?-maximo(3,0,0). es afirmativa, cuando debera
ser evidentemente negativa.
Ejemplo 3: pertenencia de un elemento a una lista
La forma mas inmediata para representar en Prolog la pertenencia de un elemento a una lista
es la siguiente:
pertenece(C, [C|_]).
pertenece(C, [_|R]) :- pertenece(C,R).
En la definicion anterior, las dos opciones no se consideran excluyentes, por lo que si un elemento
aparece varias veces en una lista, el predicado encontrara todas sus posibles ocurrencias. As,
25

el predicado anterior podra utilizarse no solo para averiguar si un elemento pertenece a una
lista determinada sino tambien para recorrer todos los elementos de una lista. Por ejemplo, la
respuesta del sistema ante la consulta pertenece(X,[a,b,c]). es la siguiente (compruebese
construyendo el arbol de resolucion SLD correspondiente).
?- pertenece(X,[a,b,c]).
X = a ? ;
X = b ? ;
X = c ? ;
no
Una version mas eficiente del predicado anterior se consigue introduciendo un corte en el cuerpo
de la primera regla, de forma que el predicado termine en el momento de encontrar la primera
ocurrencia de un cierto elemento:
pertenece(C, [C|_]) :- !.
pertenece(C, [_|R]) :- pertenece(C,R).
Con esto se consigue una version determinista y mas eficiente del predicado. Sin embargo,
la introduccion del corte y la consiguiente poda del arbol de Resolucion SLD hace que el
predicado ya no se pueda usar, como con la version anterior, para enumerar todos los elementos
de una lista. En efecto, ahora se tendra (compruebese construyendo el arbol de resolucion SLD
correspondiente):
?- pertenece(X,[a,b,c]).
X = a ? ;
no

26

También podría gustarte