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