Técnicas para la comunicación hombre

Anuncio
Técnicas para la comunicación hombremáquina y la programación
Tema
de
Programación no Procedural
Dr. Daniel Gálvez Lio
... 1
PROGRAMACIÓN LÓGICA
EL nombre PROLOG es derivado de la expresión “PROgramming in LOGIC”. Constituye una
implementación de los procesos y procedimientos involucrados en el cálculo de predicados de primer
orden. PROLOG no es exactamente la lógica de predicado en sí misma. Su forma, gramática o
sintaxis es de la lógica, pero su semántica o significado es diferente.
PROLOG es esencialmente un lenguaje declarativo puesto que la mayoría de los enunciados de un
programa PROLOG típico son aserciones o afirmaciones.
¿Cuándo surge el PROLOG?.
En 1970 Colmerauer y su grupo de la Universidad de Marsella (Francia), desarrollan un probador de
teoremas especializado, escrito en FORTRAN, el cual utilizaron para implementar sistemas de
procesamiento del lenguaje natural.
Un programa PROLOG consta de un conjunto de aserciones, los cuales se consideran que
constituyen los axiomas propios de una teoría junto con un conjunto de cláusulas objetivos, a los que
se consideran teoremas que hay que probar.
Beneficios:
Permite crear programas de la Inteligencia Artificial (lA) mucho más rápido y más fácil.
Es ideal para implementar sistemas expertos y procesamiento del lenguaje natural.
Los mecanismos de inferencias y los procedimientos son partes de él (built-in)
II.3 El lenguaje PROLOG
El lenguaje PROLOG (acronismo de PROgramación LÓGica) se creó en la década del 70 por
Alain Colmerouer y sus colaboradores de la Facultad de Ciencias en Marsella, Francia.
El objetivo original de los creadores fue integrar el principio de resolución de Robinson en un
lenguaje de programación. Este principio brinda una regla de inferencia para la prueba
mecánica de teoremas en lugar de las múltiples reglas que los lógicos proponían.
Esta idea en el diseño del lenguaje le da la capacidad de hacer que una computadora simule el
proceso del pensamiento haciendo deducciones a partir de información dada en forma lógica.
La idea inicial del diseño se basó en una teoría del lenguaje y la Lógica Matemática, pero la
estrecha relación con la lógica se convertía en algo pesado cuando se implementaba PROLOG
sobre una computadora, debido a esto se pusieron más restricciones prácticas y el resultado
final fue un lenguaje sin trabas, independiente de detalles que sólo se necesitan en lógica.
PROLOG utiliza árboles como su estructura básica. En un programa PROLOG cada árbol es un
hecho o un átomo de conocimiento y la naturaleza bidimensional de los árboles contribuye a la
potencia de expresión del lenguaje.
PROLOG es un lenguaje de Programación Lógica en el sentido que sus sentencias se
interpretan como sentencias lógicas.
Definición sintáctica simple
Un programa PROLOG es un conjunto de cláusulas que declaran, en forma lógica, el
conocimiento sobre un determinado problema. Estas cláusulas se definen como hechos
(elementos que se dan por verdaderos) y reglas que expresan las condiciones que se tienen
que cumplir para probar un determinado objetivo.
3
El lenguaje es especialmente útil para resolver problemas donde se trabaja con objetos y
relaciones entre ellos. Como ejemplo de lo que se está discutiendo se presenta en la figura II.1
un árbol de relación entre algunas de las personas que trabajan en la facultad de Matemática de
la UCLV. En esa figura se establecen relaciones de subordinación, el nivel 2 deja claro quienes
son los jefes de departamentos.
B ello
M a rily n
M a te o
Daniel
D ecano
M iria m
M e rce d e s
J ' D p to
H o r ta
P r o fe s o r e s
F i g u r a II.1 : E j e m p l o d e r e l a c i ó n d e s u b o r d i n a c i ó n .
Se pueden sacar varias relaciones del árbol presentado, por ejemplo el hecho, "Mateo está
subordinado a Marilyn" se expresa como:
subordinado(marilyn, mateo).
Los nombres se escriben en minúsculas por un problema sintáctico.
En este caso subordinado es el nombre (o functor) de la relación y marilyn y mateo son sus
argumentos.
Un programa PROLOG está compuesto por un conjunto de cláusulas. Entonces para establecer
las relaciones de subordinación escritas en el árbol, se escribirá el conjunto de cláusulas que
siguen, las cuales expresan las relaciones establecidas en el árbol precedente.
subordinado(bello, marilyn).
subordinado(bello, miriam).
subordinado(marilyn, mateo).
subordinado(marilyn, daniel).
subordinado(miriam, mercedes).
subordinado(miriam, horta).
Una vez escrito un programa como este pueden realizarse varias preguntas acerca de la
relación subordinado.
Tomando el signo de interrogación (?-) como el prompt del intérprete PROLOG, se puede
comenzar a interrogar al lenguaje.
1.- ¿Es Mateo subordinado de Marilyn ?
?-subordinado(marilyn,mateo).
yes
4
?En este caso la pregunta con la relación subordinado se hace con sus argumentos acotados
(tienen valores). El lenguaje hace una búsqueda en su memoria de trabajo y encuentra la
relación buscada, debe observarse que el orden en esta relación es totalmente aleatorio pero
una vez establecido se tiene que respetar, o sea la cláusula subordinado establece en este
caso que mateo es subordinado de marilyn y no lo contrario.
2.- ¿ Miriam tiene algún subordinado que se llame Antonio?
?-subordinado(miriam,antonio).
no
?Debido a que no existe nada en el programa que establezca una relación entre miriam y antonio
se recibe una respuesta negativa, en todos los casos se devuelve el prompt para avisar que
PROLOG esta listo para recibir una nueva pregunta.
3.- ¿ Marilyn es subordinado de Daniel?
?-subordinado(daniel,marilyn).
no
?
En este caso la respuesta vuelve a ser negativa ya que lo que se establece en el programa es
lo contrario.
4.- ¿Dígame alguien que sea subordinado de Marilyn?
?-subordinado(marilyn,X).
X <- mateo
?En este caso el primer argumento de subordinado va acotado por lo que la búsqueda se realiza
sobre aquellas cláusulas que tengan su primer argumento acotado con el valor bello, el
segundo argumento va sin acotar, entonces la variable X tomara valor de acuerdo a la cláusula
en que se realice la búsqueda, cuando esta sea posible (se analizaran los casos mas adelante).
5.- Si se deseara obtener todos los subordinados de Marilyn, se hará la misma pregunta
anterior, pero para cada respuesta se pedirá una solución alternativa utilizando el operador or
que se escribe con punto y coma(;).
?-subordinado(marilyn,X).
X <- mateo;
X <- daniel;
no
En este caso el usuario después de cada respuesta tecleo ";" entonces PROLOG interpreta esto
como "..búscame otra solución..", para resolver ese problema a la variable acotada X se le quita
el valor que tenía y se hace otra búsqueda pero ahora sin tomar en cuenta la cláusula utilizada
antes.
5
6.- Encontrar X y Y tal que X es el jefe de Y
?-subordinado(X,Y).
X <- bello
Y <- marilyn
7.- Si se desean todos los X y Y que satisfacen la relación anterior se puede hacer uso del or.
?-subordinado(X,Y).
X <- bello
Y <- marilyn;
X <- bello
Y <- miriam;
X <- marilyn
Y <- mateo;
X <- marilyn
<- daniel;
X <- miriam
Y <- mercedes;
X <- miriam
Y <- horta;
no
?Reglas en PROLOG
Si se desearan establecer más relaciones en un programa PROLOG, la solución no debe ser
escribir explícitamente cada una de estas relaciones porque esto haría al programa
extremadamente largo e ineficiente y no se explotaría la potencia real del lenguaje, por esta
razón el programa anterior no debe partir de la relación subordinado, sino de la relación más
básica o elemental que expresa donde trabaja cada persona, de esta forma se pueden
establecer otras relaciones que parten de la relación básica o de derivados de esa relación.
Esta forma de pensar es la que se debe tener en cuenta en el momento de escribir un programa
en PROLOG, aún en el caso que sólo se desee una determinada relación, esta manera de
diseñar el programa permite múltiples ampliaciones que no son posibles si se parte de hechos
específicos dados por necesidades momentáneas y que en general cuando se hace una
aplicación tiende a crecer según van surgiendo nuevas necesidades.
De esta forma el programa anterior se debe escribir de la manera siguiente:
trabaja(mateo,cibernetica).
trabaja(daniel,cibernetica).
trabaja(mercedes,matemática).
trabaja(horta,matemática).
jefe(marilyn,cibernetica).
jefe(miriam,matemática).
6
Estos hechos establecen las relaciones básicas. La discusión la dejaremos a nivel del
departamento, se deja al lector la ampliación del programa para establecer todas la relaciones
del árbol.
Ahora se debe formalizar una regla que establezca la relación de subordinación entre dos
personas, se puede pensar en la regla siguiente:
Para todo X y Y, existe Z tal que:
Y es subordinado de X si
Y trabaja en el departamento Z
y X es jefe del departamento Z.
La relación anterior se escribe en PROLOG como:
subordinado(X,Y):trabaja(Y,Z),
jefe(X,Z).
Las cláusulas PROLOG que se escriben de la forma anterior se denominan reglas. Debe
quedar claro que las cláusulas que formulamos inicialmente son hechos en el sentido que
siempre son ciertas, mientras cláusulas como la anteriormente escrita son reglas en el sentido
que para cumplirse tienen que darse determinadas premisas, si la regla anterior se escribe en
forma lógica, tenemos:
(x)(y)(z) tal que trabaja(Y,Z)^jefe(X,Z)  subordinado(X,Y)
Igual que la fórmula lógica anterior, una regla PROLOG tiene dos partes:
1- La cabeza, en este caso subordinado(X,Y), en ella se establece una conclusión, que se
cumplirá si se cumplen las premisas que están en el cuerpo de la cláusula.
2- Cuerpo, en este caso trabaja(Y,Z), jefe(X,Z), en ella se establecen las premisas
que se mencionaron en el punto anterior y tienen que cumplirse para que la regla se cumpla, en
caso contrario falla y no se puede concluir nada por esa regla.
El símbolo :- expresa la relación entre la cabeza y el cuerpo de la cláusula y puede leerse
como una implicación lógica ().
Un ejemplo muy común en todos los libros de programación lógica es la definición de las
relaciones familiares, en este programa se parte de la relación básica padre (en el sentido
genérico) y se forman las reglas que definen todas las relaciones familiares (abuelo, hijo, tío,
etc.).
Algunas relaciones derivadas de la relación básica padre escritas en forma de reglas pueden
ser:
abuelo(X,Z):padre(X,Y),
padre(Y,Z).
hermano(X,Y):7
padre(Z,X),
padre(Z,Y),
diferentes(X,Y).
Se puede seguir formando reglas que establezcan las restantes relaciones, no es necesario
agregar ningún nuevo hecho.
Observe en la última regla la relación diferentes (habrá que escribirla de alguna forma) que
establece: "para que dos personas X y Y sean hermanos no basta con tener un padre común,
debe cumplirse, además, que X y Y sean diferentes", si no se establece esa condición se tendrá
que una persona es hermano de ella misma. Se alerta al lector sobre problemas de este tipo.
Mecanismo de inferencia
Cualquier intérprete o compilador para el lenguaje PROLOG es, en última instancia, una
excelente máquina de inferencia que trabaja con razonamiento hacia atrás (ver Capítulo V). Con
esa premisa se analiza el programa siguiente:
p:-a,b.
b:-a,c.
a.
b:-h.
h.
Si se pregunta por el objetivo p comenzara un proceso de inferencia que parte de atrás hacia
adelante en el sentido que la búsqueda que realiza el lenguaje se hace por las conclusiones de
cada una de las cláusulas que componen el programa. De esta forma para probar p se
encuentra que aparece como conclusión en la primera cláusula, entonces para probar este
objetivo se tendrá que probar cada una de las condiciones de esta regla (si fuera un hecho no
habría nada que probar y se concluirá que es verdadero el objetivo). Analicemos entonces el
proceso paso a paso:
1.-
?-p.
Esta pregunta desenlaza el proceso de inferencia
2.- Se busca p como conclusión de alguna regla o como hecho, aparece en la cláusula 1 que es
una regla
p:-a,b.

3.- Esto provoca que se pase a probar el cuerpo de la regla para probar su primera condición
que es en este caso a:
p:-a,b.

4.- Se hace una nueva búsqueda pero ahora el objetivo es a y se encuentra que aparece en la
cláusula 3 como un hecho
8
a.

por lo que se da por probado. Como las condiciones están unidas por el operador and
(representado por una coma ",") se continua para probar el próximo objetivo
p:-a,b.

5.- Se realiza un nuevo proceso de búsqueda pero el objetivo es ahora b, que aparece como
conclusión en la cláusula 2 que es una regla:
b:-a,c.

Entonces para probar esta conclusión se tienen que probar las condiciones de la regla.
6.- El nuevo objetivo es ahora a:
b:-a,c.

Pero a se da como hecho en la cláusula 3:
a.

Entonces se tiene que continuar para probar la próxima condición de la regla ( si las
condiciones están unidas por or, representado por punto y coma " ;", basta con probar una de
ellas siguiendo las regla de la lógica).
7.- El objetivo ahora es c
b:-a,c.

8.- Tenemos una nueva búsqueda, el objetivo es c, pero no hay nada en el programa que
permita concluir algo con relación a c, entonces este objetivo falla y se produce un regreso atrás
(backtracking) para tratar de encontrar una solución alternativa al objetivo anterior, en este caso
a, pero a solo tiene una solución y por ese motivo a también falla, se sigue el regreso atrás pero
se llega al inicio de la regla sin poder encontrar una nueva solución para sus condiciones, por
ese motivo falla la regla formulada en la cláusula 2 y como se estaba buscando una solución
para b en esa regla, se produce un nuevo regreso atrás pero ahora buscando una nueva regla o
hecho que permita probar b.
9.- El objetivo es b nuevamente, se produce la búsqueda de b que excluye, por supuesto, la
búsqueda anterior y se encuentra b en la cláusula numero 4
b:-h.

9
Se pasa a probar las condiciones de esta regla.
10.- La primera condición es h, por lo que se convierte en el próximo objetivo a probar.
b:-h.

11.- Búsqueda de h y localización de h como un hecho en la cláusula 5.
h.

Como es un hecho se da por probado y como la regla 5 solo tiene una condición queda
probada.
12.- Al quedar probado b queda probada la segunda y última condición de la cláusula 1 que es
la regla que se esta probando para poder probar el objetivo inicial p, entonces p queda probado
y finaliza la inferencia con un resultado satisfactorio, por lo que PROLOG contestará
afirmativamente a la pregunta que se hizo en relación a p.
yes
?Ahora queda esperando por una nueva interrogante.
Se debe observar que el orden de las cláusulas influye en la velocidad de las respuestas, si se
hubieran intercambiado las cláusulas 2 y 4 de forma que el programa quede como:
p:-a,b.
b:-h.
a.
b:-a,c.
h.
En este caso la prueba de a es inmediata como el caso anterior, pero la prueba de b no provoca
ningún fallo y por ende no hay regreso atrás, todo lo que influye en que la prueba de p en esta
segunda versión del programa es más rápida.
Queda claro que el orden de las cláusulas en un programa influye directamente en la velocidad
de ejecución, pero no solo eso, el orden puede, a veces, influir en el correcto funcionamiento de
un programa y se alerta al lector en este sentido.
No existe una forma predeterminada o explícita para ordenar las cláusulas, solo la experiencia
en la programación en PROLOG y el conocimiento del problema que se está tratando puede
determinar esto.
II.4 Elementos sintácticos y semánticos del lenguaje
El lenguaje PROLOG específica a través de la sintaxis los diferentes datos que manipula, o sea,
no existe la declaración de datos, en general. Los datos pueden ser simples o estructurados.
10
II.4.1 Datos simples
- Átomos.
Un átomo es un elemento sintáctico que puede estar constituido por los siguientes elementos:
Letras, dígitos y caracteres especiales.
Los átomos pueden estar constituidos por cadenas de estos elementos que comienzan con letra
minúscula, por eso los nombres en las relaciones familiares y las de subordinación se
escribieron de esa forma. Un átomo puede ser, además, una cadena cualquiera encerrada entre
apóstrofe.
Ejemplos:
alina
pedro
esto_es_un_atomo
'Y este También, es el ejemplo numero 4'
- Números
Pueden ser enteros y reales, su longitud depende de la implementación con que se trabaje.
- Variables
Cadenas de letras, dígitos y el carácter subrayado que comienzan con Mayúscula.
Ejemplos:
X
Variable1
Variable_N2
Existe además la variable anónima underscore(_) que se utiliza cuando no se tiene interés en
conocer el valor de la variable en cuestión en una cláusula determinada.
II.4.2 Estructuras
Los objetos estructurados son objetos que tienen varios componentes, estos componentes
pueden ser a la vez nuevas estructuras.
Este concepto se puede comprender mejor con el uso de un ejemplo:
n a c i m i e n to
p e rs o n a
n o m b re
apellido
fe c h a
d ía
m es
año
Fi g u r a II.2 : E j e m p l o d e o b j e to s c o m p l e j o s .
El árbol mostrado en la figura II.2 se puede escribir como la estructura:
11
nacimiento(persona(Nombre,Apellido),fecha(Dia,Mes,A)).
La estructura escrita está compuesta por dos estructuras:
- persona, que describe en una variable el nombre y en otra el apellido de alguien.
- fecha, que hace uso de las variables Dia, Mes y A para especificar la fecha de nacimiento.
En PROLOG esta estructura se puede complicar todo lo que se desee, permitiendo hacer la
representación de cualquier árbol.
Si se desea que la estructura nacimiento se refiera a alguien en particular, se pueden acotar
(instanciar) las variables Nombre y Apellido de la estructura persona, con átomos que
especifiquen el nombre y el apellido de la persona.
Ejemplo:
nacimiento(persona(marien,lezcano),fecha(Dia,Mes,A)).
Igual sucede con la fecha:
nacimiento(persona(marien,lezcano,fecha(5,mayo,1973)).
Observe que el primer y último argumento de la estructura fecha se instancia con números
enteros, mientras que el segundo argumento se intancia con un átomo.
Sintácticamente todos los elementos manipulados por PROLOG son términos, por ejemplo
1973 y fecha(5,mayo,1973) son términos.
El mecanismo de operación más importante que se realiza sobre términos es el matching.
Veamos entonces cuando dos términos pueden hacer matching:
.Un átomo solo puede instanciar con otro átomo exactamente igual.
. Una variable libre (no acotada) instancia con cualquier término.
. Una estructura instancia solo con otra estructura que tenga el mismo nombre (denominado
functor) y la misma cantidad de argumentos (a esa cantidad se le denomina el arity de la
estructura).
Analicemos ahora, de nuevo, el funcionamiento de un programa PROLOG con los conceptos
que se han discutido hasta el momento, resulta útil utilizar el programa de las relaciones
familiares:
c1
c2
c3
c4
c5
padre(luis,carlos).
padre(luis,dalia).
padre(carlos,maria).
padre(dalia,martha).
abuelo(X,Y):padre(X,Z),
padre(Z,Y).
?-abuelo(luis,martha).
12

Se produce matching con la cláusula c5
X  luis
La variable libre X hace matching con el átomo luis, quedando X
intanciada con ese valor.
c5:
Y  martha
Sucede lo mismo con Y y martha
** padre(luis,Z)
Se pasa a probar la condición padre(X,Z), pero X está instanciada
con luis.
Se produce matching con c1
luis=luis
c1
X  carlos
El átomo luis hace matching con el átomo luis
La variable X hace matching y queda instanciada con el átomo carlos.
Se cumple la primera condición de la regla expresada en la cláusula 5 y
se pasa a probar la siguiente.
padre(carlos,martha)
No hay nada en el programa que permita llegar a esta conclusión, por lo que se
produce un regreso atrás hasta **, como en ese lugar se había instanciado Z,
pierde ahora su valor para buscar una solución alternativa para la llamada que
se produjo en ** exactamente igual a como se hizo en aquel momento pero
ahora sin tomar en cuenta la solución anterior.
padre(luis,Z)
luis=luis
c2
Z  dalia
Debemos encontrar una nueva solución para este subobjetivo.
Se puede instanciar ahora con c2
Con esta nueva solución se vuelve otra vez hacia delante, para buscar la
prueba de la segunda condición de la regla expresada en la cláusula 5.
padre(dalia,martha)
dalia=dalia
c4
martha=martha
Por c4 se puede afirmar la veracidad.
Como se cumple la segunda y última condición de la regla que se está tratando de probar, la
regla sucede y PROLOG responde.
yes
?En este ejemplo se puede observar un regreso atrás parcial o sea dentro de una misma regla,
se observa además como este regreso provoca que las variables acotadas en el paso previo
pierden su valor para permitir la búsqueda de una solución nueva a la condición anterior para de
esta forma volver hacia delante y tratar de buscar una solución, bajo las nuevas condiciones, a
la llamada que fallo.
13
II.4.3. Listas
Una estructura muy importante en un programa PROLOG es la lista.
Una lista es una secuencia de cualquier cantidad de elementos que en PROLOG se representa
de la forma siguiente:
(1) [daniel,marien,mercedes,michel,yakelin]
En este caso se tiene una lista de 6 elementos y cada elemento es un átomo que representa el
nombre de una persona. Algo que debe quedar claro en esta lista es que tiene un determinado
orden y esto se utiliza ampliamente en los programas PROLOG que trabajan sobre listas.
Una lista esta compuesta por:
- Una cabeza (su primer elemento).
- El resto de la lista denominado cola.
En el ejemplo que nos ocupa, daniel es la cabeza y la lista [marien, mercedes, michel,
yakelin] es el resto o cola de la lista.
La lista puede estar formada por cualquier cantidad de elementos de cualquier tipo permitido en
PROLOG (variables libres, átomos, etc.). Una lista (igual que todos los objetos estructurados en
PROLOG) es un árbol, que se escribe como una relación PROLOG. Si se toma como nombre
de esa relación el punto(.), se puede escribir la lista en forma general como:
.(cabeza, cola)
Retomando el ejemplo inicial podemos entonces escribir la lista como:
(2) .(daniel,.(marien,.(mercedes,.(michel,.(yakelin,[])))))
Observando esta representación queda claro que la lista que tiene como cabeza el átomo
daniel tiene como cola una lista con el resto de los elementos y esta lista cumple a su vez el
hecho de tener una cabeza y una cola, de esta forma se llega a la última lista que tiene como
cabeza yakelin y como resto la lista vacía:
(3) .(yakelin,[]).
La estructura arbórea de la lista representada de las formas indicadas en (1) y (2) se presenta
en la figura II.3, en esa representación se observa claramente la forma espacial de árbol que
tiene una lista.
14
daniel
m a rie n
m e rce d e s
m ichel
y aquelin
F i g u r a II.3 : Ár b o l p a r a l a l i s ta [d a n i e l , m a r i e n , m e r c e d e s , m i c h
En conclusión se puede decir que una lista PROLOG es una estructura especial que puede
estar vacía o puede estar constituida por dos partes Cabeza y Cola.
II.4.4 Patrones de listas
A veces resulta útil tratar la cabeza y el resto de la lista como objetos independientes y con este
fin se utiliza una notación especial que separa ambos elementos pudiendo entonces realizar
acciones de acuerdo a la parte de la lista tratada.
El concepto se analiza con la ayuda de un ejemplo:
(4) [c,d,e]
La lista (4) tiene como cabeza el átomo c y como resto la lista [d,e], si utilizamos la notación
de paréntesis se puede escribir como:
(5) (a,Cola)
Como la forma de paréntesis no resulta cómoda muchas implementaciones PROLOG utilizan el
símbolo | para representar la lista anterior de forma que quede claro cual es la cabeza y cual es
la cola o resto, de esta forma la lista anterior se puede representar como:
(6) [a|Cola]
De esta manera se representa en forma general una lista que tiene al menos un elemento ( la
cabeza) ya que la cola puede ser vacía, con esta convención se pueden escribir las listas
siguientes:
- [] La lista vacía.
- [A|R] La lista que tiene al menos un elemento (la cabeza), observe que ese elemento puede
ser cualquiera, incluso otra lista .
- [E1,E2,...,En] Una lista con n elementos ( no se puede escribir ... para representar esto
como seguramente tendrá claro el lector.
15
II.4.5 Operaciones sobre listas
Presentamos un programa que dada una lista cuenta sus elementos:
cuenta([],0).
cuenta([Cabeza|Resto],Resultado):cuenta(Resto,Contador),
Resultado is Contador + 1.
Llamada:
cuenta([a,[pedro,g],3,R)
R <- 3
yes
?Este simple programa expresa la potencia del lenguaje y el uso de la recursividad. El matching,
el regreso atrás, la recursividad y el acotamiento de las variables, son las armas fundamentales
del lenguaje.
El programa en cuestión esta constituido por dos cláusulas. La primera es un hecho que
expresa "..la lista vacía tiene 0 elementos" la segunda es una regla que hace uso de la
recursividad en una forma adecuada para lograr recorrer la lista antes de comenzar a
incrementar la variable que cuenta los elementos. Las llamadas cuenta(Resto,Contador)
que se realizan desde la segunda cláusula del programa no instancian nunca (excepto en la
ultima) con la primera cláusula (la lista en ninguna llamada esta vacía), pero la ultima llamada
constituye la excepción, ella toma la forma cuenta([],Contador) y esa llamada hace
matching con la cláusula 1, logrando entonces que la variable libre Contador haga matching
con 0. Ahora el lenguaje en su marcha hacia delante en la cláusula 2 hará todas las
operaciones de adición que quedaron pendientes, obteniendo de esa forma la cantidad de
elementos que forman la lista.
Una relación fácil de entender y que puede ser expresada con el uso de las listas es la relación
de pertenencia de un elemento dado a una lista.
El elemento X es miembro de una lista si:
- X es la cabeza de la lista o
- X es miembro del resto de la lista.
La definición recursiva "ser miembro de" en PROLOG nos facilita enormemente la escritura de
un predicado para definir la relación deseada:
miembro(X,[X|R]).
miembro(X,[_|R]):miembro(X,R).
Llamada:
?-miembro(3,[r,3,'si']).
yes
?-miembro(no,[si,a,12,r]).
16
no
?La primera cláusula expresa claramente la primera relación, mientras la segunda ya conoce que
el elemento no está en la cabeza, entonces hace que la cabeza de la lista instancie con la
variable anónima (ya no nos interesa) y llama con el elemento X y el resto R para averiguar si
esta ahora en la nueva cabeza.
II.5 Estructuras de control
Un programa PROLOG normalmente realiza regreso atrás cuando se hace necesario satisfacer
un objetivo que fallo, esta herramienta útil en la mayoría de los casos, a veces, resulta
indeseada, por esa razón deben existir estructuras que controlen el regreso atrás cuando el
usuario así lo decida .
II.5.1 Cortes
El corte es la forma más típica de controlar el regreso atrás y debe estar presente en cualquier
implementación PROLOG, este mecanismo se expresa sintácticamente como un signo de
admiración (!).
Dada la cláusula siguiente:
C:-C1,C2,...,Cn,!,...,Cm.
Se esta especificando que no se efectúe regreso atrás a partir de !, o sea si Cm falla provoca un
regreso atrás para buscar solución alternativa en la condición que le precede, si esto no es
posible se continua hacia atrás, pero cuando este retroceso llegue al corte, se le esta diciendo a
PROLOG "..no hagas más intentos hacia atrás" y en este caso el predicado C fallara.
II.5.2 Tijeras
Este mecanismo no es tan general como el anterior, pero si muy útil, y especifica que en el
regreso atrás no se tome en cuenta un determinado segmento de la definición de la cláusula.
Sintácticamente se expresa como [!segmento a saltar!]
C:-C1,C2,C3,[!C4,C5,C6!],C7.
En este caso si C7 falla el regreso atrás no tomara el segmento C4,C5,C6 en cuenta y por tanto
se efectúa un salto atrás hasta C3.
Definamos con la idea del corte una forma de escribir la relación diferentes que nos hizo falta
cuando se escribió la relación tío.
diferentes(X,X):!,
fail.
diferente(X,Y).
Esta regla expresa si X es X entonces falla (fail es un predicado PROLOG que fuerza a que
falle un objetivo) pero no busques solución alternativa, de forma que PROLOG responderá "no"
17
que es precisamente lo que se desea (el contenido de la variable X no puede ser diferente que
el contenido de ella misma). Por otra parte si la pregunta no hace matching con la primera
cláusula, entonces ira a la segunda que es un hecho y responderá que si, o sea que son
diferentes.
La llamada puede ser
?-diferente(2,3).
yes
?-diferente(2,2).
no
?El lector debe seguir la traza a mano de este programa para observar el efecto del corte.
II.6 Análisis critico sobre el lenguaje
PROLOG es un lenguaje que basa su potencia en un conjunto pequeño de mecanismos como
son: el pattern matching, el regreso atrás automático y la representación arbórea de los datos.
El lenguaje es particularmente útil para tratar problemas que traten sobre objetos estructurados
y las relaciones que se pueden establecer entre esos objetos.
Mientras los lenguajes tradicionales han sido orientados a procedimientos, PROLOG es un
lenguaje declarativo, lo cual rompe, en términos generales con la forma de pensar que tiene el
programador. En lenguajes como PROLOG el programador se ocupa de la parte declarativa del
problema y deja, en parte, al lenguaje responsabilizado con escoger los caminos que debe
seguir para resolver un determinado problema.
Uno de los problemas que se le señala al lenguaje es la longitud del código generado, aunque
existen en muchas implementaciones mecanismos que permiten controlar, hasta cierto punto,
este problema, el que es además fácilmente comprensible si se tiene en cuenta que un mismo
predicado ante llamadas diferentes puede dar respuestas también diferentes, sin que el
programador se haya preocupado mucho, a tal vez nada, en programar un caso diferente al que
le interesa. Queda claro que para hacer cosas como la mencionada es necesario generar el
código que las hace.
En la mayoría de las implementaciones las herramientas de puesta a punto no son las mas
adecuadas.
La forma de programar en PROLOG es, sin duda, muy útil para problemas de Inteligencia
Artificial, y el programador que alcance la pericia adecuada con el lenguaje hará aplicaciones en
forma rápida y relativamente cómoda en este novedoso campo.
Estas son sólo algunas consideraciones en relación al lenguaje que se ha presentado en una
forma muy general y sin tener en cuenta ninguna implementación en especial, las herramientas
que brinden cada una de las implementaciones contribuyen en lograr, por supuesto, productos
más o menos presentables y fáciles de hacer pero, en última instancia todo estará basado en el
núcleo básico que aquí se ha presentado y que los libros gustan nombrar como "PROLOG
puro".
18
BIBLIOGRAFÍA
1- Backus, J.
Can programming be liberated from the von Neumann Style? A functional style
and its algebra of programs,
Comm. of ACM, vol. 21, no. 8, 1978.
2- Bratcko, .
Prolog programming for artificial Intelligence.
19
Descargar