Está en la página 1de 260

Programacin Lgica o o

Programacin Lgica o o
I Lenguajes Formales: Conceptos Fundamentales 1 3 3 7

1 Gramticas y Lenguajes a 1.1 Gramticas . . . . . . . . . . . . . . . . . . . . . a 1.2 Lenguaje generado por una gramtica . . . . . . . a

2 Anlisis Sintctico a a 11 2.1 Tcnicas descendentes . . . . . . . . . . . . . . . 15 e 2.2 Tcnicas ascendentes . . . . . . . . . . . . . . . . 17 e 2.3 Eliminacin de ambig edades . . . . . . . . . . . 20 o u

II

Lgica: Conceptos Fundamentales o

23 25 27 28 29 30 33 35 36 37 41

3 Clculo de Proposiciones a 3.1 Evaluacin de proposiciones: tablas de verdad . . o 3.1.1 Evaluacin de proposiciones constantes . . o 3.1.2 Evaluacin de proposiciones en estados . . o 3.1.3 Evaluacin de proposiciones sin parntesis o e 3.1.4 Tautolog as . . . . . . . . . . . . . . . . . 3.2 Reglas de reescritura . . . . . . . . . . . . . . . . 3.2.1 Leyes de equivalencia . . . . . . . . . . . . 3.2.2 Reglas de sustitucin, resolucin y o o transitividad . . . . . . . . . . . . . . . . . 3.2.3 Axiomas y teoremas . . . . . . . . . . . .
i

ii

Programacin Lgica o o

4 Clculo de Predicados a 4.1 Extensin del concepto de estado . . . . . . o 4.2 Los operadores cand y cor . . . . . . . . . . 4.3 Cuanticadores . . . . . . . . . . . . . . . . 4.3.1 El cuanticador universal . . . . . . 4.3.2 El cuanticador existencial . . . . . . 4.3.3 El cuanticador numrico . . . . . . e 4.3.4 Equivalencias entre cuanticadores . 4.3.5 Cuanticacin sobre rangos innitos o 4.4 Identicadores libres y ligados . . . . . . . . 4.5 Sustitucin textual . . . . . . . . . . . . . . o 4.6 Sustitucin simultnea . . . . . . . . . . . . o a 5 Prolog y Clculo de Predicados a 5.1 Regla de resolucin . . . . . . . o 5.2 El proceso de resolucin . . . . o 5.2.1 Un ejemplo simple . . . 5.2.2 Un ejemplo completo . . III El Intrprete Lgico e o . . . . . . . . . . . . . . . . . . . . . . . . . . . .

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

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

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

43 44 46 48 48 49 50 51 53 54 56 59 61 61 63 64 68 79

6 Conceptos Fundamentales 81 6.1 Objetos en programacin lgica . . . . . . . . . . 81 o o 6.2 Programas lgicos, clusulas y preguntas . . . . . 83 o a 6.3 Concepto de unicacin: sustituciones e instancias 85 o 6.4 Un intrprete lgico simple . . . . . . . . . . . . . 89 e o 6.5 El concepto de retroceso . . . . . . . . . . . . . . 94 6.6 Signicado de un programa lgico . . . . . . . . . 100 o 6.6.1 El orden de tratamiento de los objetivos . 105 6.6.2 El orden de aplicacin de las clusulas . . 107 o a 7 Control en Prolog: el Corte 7.1 Semntica operacional . . . . . . . . . . . . . . a 7.2 Tipos de cortes . . . . . . . . . . . . . . . . . . 7.2.1 El corte verde . . . . . . . . . . . . . . . 111 . 111 . 122 . 123

Programacin Lgica o o

iii

7.3

7.2.2 El corte rojo . . . . . . . . . . . . . . . . . 123 Las variables annimas . . . . . . . . . . . . . . . 124 o

8 La Negacin o 127 8.1 El predicado fail . . . . . . . . . . . . . . . . . . 127 8.2 La negacin por fallo . . . . . . . . . . . . . . . . 130 o 8.3 Anomal de la negacin por fallo . . . . . . . . 132 as o 9 Control de la Evaluacin o 139 9.1 La primitiva freeze . . . . . . . . . . . . . . . . 139 9.2 La declaracin wait . . . . . . . . . . . . . . . . . 142 o IV Programacin Lgica o o Listas Denicin del tipo lista . . . . . . . . . o Operaciones fundamentales sobre listas Operaciones sobre conjuntos . . . . . . 10.3.1 El tipo conjunto . . . . . . . . . 10.3.2 La unin . . . . . . . . . . . . . o 10.3.3 La inclusin . . . . . . . . . . . o 10.3.4 La interseccin . . . . . . . . . o 10.3.5 El producto cartesiano . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 147 . 149 . 149 . 160 . 160 . 161 . 162 . 162 . 164 . . . . 165 165 171 172 178

10 Las 10.1 10.2 10.3

11 Tcnicas de Programacin e o 11.1 Los acumuladores . . . . . . . . . 11.2 Estructuras de datos incompletas 11.2.1 Diferencias de listas . . . . 11.2.2 Diferencias de estructuras 12 Predicados No Lgicos o 12.1 Predicados aritmticos . . . e 12.2 Entradas y salidas . . . . . 12.3 Predicados de memorizacin o 12.4 Predicados metalgicos . . . o 12.5 Comentarios . . . . . . . . . . . . . . . . . . . . . . . .

183 . 183 . 185 . 186 . 193 . 195

iv

Programacin Lgica o o

13 Los Operadores 13.1 Denicin de operadores . . . . o 13.1.1 Operadores binarios . . . 13.1.2 Operadores unarios . . . 13.2 Operadores y potencia expresiva 14 Lgica y Anlisis Sintctico o a a 14.1 Un acercamiento intuitivo . . 14.1.1 Una tcnica simple . . e 14.1.2 Una tcnica exible . . e 14.2 El problema de la recursividad

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

197 198 199 200 202

207 . . . . . . . . . . . 208 . . . . . . . . . . . 209 . . . . . . . . . . . 211 por la izquierda . 212 . . . . . . . . . . . . . . . . . . . . n mero u . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 224 225 227 229 231 236

15 Anlisis del Lenguaje Natural a 15.1 Anlisis sintctico . . . . . . . . . a a 15.1.1 Una tcnica simple . . . . e 15.1.2 Una tcnica exible . . . . e 15.2 Anlisis semntico . . . . . . . . a a 15.2.1 Concordancias de gnero y e 15.2.2 El signicado de las frases

Lista de Figuras
2.1 2.2 2.3 2.4 2.5 Arboles de derivacin para las expresiones o ambiguas con la cadena de entrada 2 + 3 4 . . Un ejemplo de anlisis descendente . . . . . . . a Una rama de profundidad innita . . . . . . . . Un ejemplo de anlisis ascendente . . . . . . . a Arboles de derivacin para las expresiones o ambiguas con la cadena de entrada 2 + 3 + 4 . aritmticas e . . . . . . . . . . . . . . . . . . . . . . . . . . . . aritmticas e . . . . . . . 14 16 17 18 21 67 77

5.1 Resolucin de :- mortal(Individuo). . . . . . . . . . . . o 5.2 Resolucin de :- invertir([1,2], Invertir). . . . . . . o

6.1 Representacin arborescente del trmino fecha(Ao, Mes, o e n Da). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 6.2 Arbol de resolucin o para la pregunta :numero natural(siguiente(siguiente(0))). . . . . . . . 93 6.3 Resolucin de :- numero natural(X). . . . . . . . . . . . 96 o 6.4 Resolucin de :- suma(0,siguiente(siguiente(0)),X). o 99 6.5 Resolucin de :- suma(X,Y,siguiente(siguiente(0))). 102 o 6.6 Resolucin de :- suma(X,Y,Z). . . . . . . . . . . . . . . . 103 o 7.1 7.2 7.3 7.4 7.5 Un programa Prolog genrico . . . . . . . . . . . . . . . . . e Resolucin de :- mult(siguiente(0),0,X)., sin corte . . o Resolucin de :- mult(siguiente(0),0,X)., con corte . . o Resolucin de :- numero de padres(Adan,X)., sin corte o Arboles con corte para :- numero de padres(Adan,X). y :- numero de padres(Adan,2). . . . . . . . . . . . . . 7.6 Resolucin de :- if then else(fail,fail,true)., con y o sin variables annimas . . . . . . . . . . . . . . . . . . . . . o 112 116 116 120 121 125

8.1 Resolucin de :- inferior(0,0)., sin corte . . . . . . . . 129 o 8.2 Resolucin de :- inferior(0,0)., con corte . . . . . . . . 129 o v

vi 8.3 8.4 8.5 8.6 8.7 Resolucin o Resolucin o Resolucin o Resolucin o Resolucin o de de de de de :::::-

Lista de Figuras not(true)., sin corte . . . . . not(true)., con corte . . . . . fea(X), igual(X,Teresa). fea(Teresa). . . . . . . . . igual(X,Teresa), fea(X). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 132 134 135 136

10.1 Representacin interna de la lista [a,[b],c,d] . . . . . . . 148 o 10.2 Resolucin de :- miembro(X,[1,2,3])., con corte . . . . . 152 o 10.3 Resolucin de :- miembro(X,Y)., sin corte . . . . . . . . . 153 o 11.1 Representacin grca de la relacin entre listas tradicionales o a o y diferencias de listas. . . . . . . . . . . . . . . . . . . . . . 11.2 Resolucin de :- aplanar([a,[b]],Resultado)., con o diferencias de listas. . . . . . . . . . . . . . . . . . . . . . . 11.3 Arboles para las expresiones (a+b)+(c+d) y ((a+b)+c)+d. . 11.4 Arbol sintctico asociativo por la derecha para a+b+c+d. . . a 11.5 Representacin grca de la relacin entre sumas o a o tradicionales y diferencias de sumas. . . . . . . . . . . . . . 173 176 179 180 181

12.1 Juego de las Torres de Hanoi para dos discos. . . . . . . . . 191 13.1 Un conjunto de guras para el problema de la analog . . . 202 a 14.1 Bosque sintctico para la cadena (), con innitos arboles . 213 a

Lista de Tablas
3.1 3.2 3.3 3.4 Tabla de operadores lgicos . . . . . . . . . . . . . . . . o Tablas de verdad para los operadores lgicos denidos . o Tabla de verdad para la expresin (((p) q) T ) . . . o Tabla de verdad para la proposicin (p q) = (p q) o . . . . . . . . 26 28 31 34 44 46 84

4.1 Algunos tipos usados comnmente . . . . . . . . . . . . . . u 4.2 Tablas de verdad para los operadores cand y cor . . . . . . 6.1 Notacin para la representacin de los nmeros naturales. . o o u

13.1 Tabla de nombres para el problema de la analog . . . . . 205 a

vii

Parte I

Lenguajes Formales: Conceptos Fundamentales

Cap tulo 1

Gramticas y Lenguajes a
El objetivo fundamental de este cap tulo es el de introducir los conceptos bsicos en el tratamiento e implementacin de a o los lenguajes formales de programacin, y ello por una razn o o fundamental que no es otra que la estrecha relacin existente o entre el desarrollo de intrpretes o compiladores lgicos por e o un lado, y la implementacin de analizadores sintcticos por o a otro [7, 10, 16, 20, 21, 27]. A este respecto, el conocimiento de las tcnicas clsicas de anlisis sintctico es fundamental e a a a para la comprensin efectiva de los problemas planteados en o programacin lgica, as como de las soluciones aportadas para o o subsanarlos.

1.1

Gramticas a

Todos los lenguajes, incluso los naturales utilizados en la comunicacin humana, poseen una representacin formal o o que viene dada por una estructura descriptiva denominada gramtica, la cual ja el conjunto de reglas sintcticas que a a orientan la construccin de textos en el lenguaje deseado. o Formalmente, una gramtica es una 4-upla G = (N, , P, S), a donde: N es un conjunto nito de s mbolos no terminales, tambin e
3

Gramticas y Lenguajes a

denominados variables. Cada uno de estos s mbolos es una categora sintctica de la gramtica. a a es un conjunto nito de s mbolos terminales, cada uno de los cuales representa una categora lxica de la gramtica. e a P es el conjunto de reglas o producciones de la gramtica. a S es el axioma de una gramtica o smbolo inicial de la a gramtica. a Ejemplo 1.1.1 Un ejemplo simple de gramtica puede ser a la que representa el lenguaje de las expresiones aritmticas. e Para simplicar en lo posible la notacin, reejaremos tan o solo la suma y la multiplicacin de nmeros1 . En ese caso, o u denominaremos a nuestra gramtica GA = (NA , A , PA , SA ) a donde: NA es el conjunto {S}. A es el conjunto {+, , (, ), nmero}. u PA es el conjunto de reglas expresadas por: S S S S S S S + S (S) n mero u

SA es en este caso el smbolo S. La primera de las producciones indica que una expresin o 2 aritmtica puede descomponerse en una multiplicacin de e o expresiones aritmticas. e La segunda regla representa la descomposicin en una suma de expresiones. La tercera, la o descomposicin en una expresin con parntesis y la ultima la o o e descomposicin en un nmero. Es importante observar que el o u smbolo n mero representa a toda una categora lxica, que no u e es otra que el conjunto de los nmeros. 2 u
1 la gramtica que se va a mostrar es vlida tanto para n meros enteros como reales a a u o complejos. 2 denotada aqu como S.

1.1. Gramticas a

En lo sucesivo, y para unicar criterios, utilizaremos la notacin que sigue, para representar el conjunto de s o mbolos de una gramtica: a V = N , el conjunto total de s mbolos. a, b, c, . . . , los s mbolos terminales. A, B, C, . . . N , los s mbolos no terminales. X, Y, Z, . . . V , s mbolos arbitrarios. u, v, w, . . . , cadenas de terminales. u1..n , una cadena u de longitud n. ui:j , la subcadena de u1..n que va del carcter en la a posicin i al carcter en la posicin j. o a o ui , el carcter de u en la posicin i. a o , , , . . . V , cadenas arbitrarias de s mbolos terminales y no terminales. , la cadena vaca. En este punto, estamos en condiciones de introducir el concepto de derivacin de un s o mbolo no terminal. Se trata, en denitiva, de expresar la nocin de descomposicin de una o o categor sintctica compleja en otras ms simples e incluso a a a en categor lxicas, aplicando el concepto de descomposicin as e o simple que de alg n modo representa la nocin de regla u o sintctica. Ello introduce el concepto de derivacin directa. a o Formalmente, decimos que deriva directamente si y slo si P , y utilizaremos la notacin . o o Extendiendo ahora el concepto de derivacin, consideramos o el de derivacin indirecta. As decimos que deriva o , indirectamente si y slo si verica uno de los dos casos o siguientes: 1 2 . . . n , que notaremos .
+

6
+

Gramticas y Lenguajes a

= o , y en este caso utilizaremos la notacin o . En caso de conocer el n mero exacto de u k derivaciones directas, tambin se usar la notacin e a o , donde k representa el n mero de dichas derivaciones. u Ejemplo 1.1.2 Partiendo de la gramtica de las expresiones a 5 aritmticas indicada en el ejemplo 1.1.1 tenemos que S e 2 3 + 4, puesto que: S S+S SS+S 2S+S 23+S 23+4 2 En la misma l nea, dado un lenguaje L(G) denimos forma sentencial recursivamente como: El axioma S de G es una forma sentencial. Si es una derivacin en G y es una forma o sentencial, entonces tambin lo es. e Intuitivamente, una forma sentencial no es otra cosa que un conjunto de s mbolos derivables a partir del axioma de la gramtica. Un tipo particular y especialmente interesante de a formas sentenciales lo forman las sentencias, que se denen como las formas sentenciales compuestas unicamente por s mbolos terminales. En concreto, estamos interesados en una clase particular de gramtica denominada de contexto libre que se caracteriza por la a forma peculiar de sus producciones. Las reglas de una gramtica a de contexto libre deben responder al patrn: o A donde A N , y es una secuencia nita de s mbolos terminales y no terminales, tal y como lo hac las reglas de la gramtica an a de las expresiones aritmticas del ejemplo 1.1.1. Distinguiremos e entre este conjunto de producciones, dos tipos de especial

1.2. Lenguaje generado por una gramtica a

inters. En primer lugar diremos que una regla es de transmisin e o simple si tiene la forma AB Intuitivamente este tipo de reglas no aumentan la longitud de la cadena derivada, tan solo expresa que los s mbolos derivables de B lo son tambin de A. En cualquier caso, es posible eliminar e este tipo de reglas de una gramtica de contexto libre [1]. Por a otra parte, denimos una regla como aquellas de la forma A que como en el caso anterior, siempre pueden eliminarse de la gramtica inicial obteniendo otra equivalente que genera el a mismo lenguaje. En el caso de que sea una sentencia del lenguaje, se admite la inclusin de la regla o S donde S es el axioma de la gramtica [1]. a En general, nos referiremos a las gramticas de contexto libre a 3 por sus siglas en ingls: CFGs . e

1.2

Lenguaje generado por una gramtica a

En este momento estamos ya en condiciones de introducir la nocin de lenguaje generado por una gramtica G = (N, , P, S) o a como el conjunto: L(G) = { , S } esto es, el conjunto de cadenas terminales que pueden ser derivadas a partir del axioma. Ms formalmente, el lenguaje a generado por una gramtica es el conjunto de sentencias para a dicha gramtica. a En este punto, es conveniente jar un orden de derivacin o con el n de eliminar diferencias irrelevantes en la generacin de o
3 por

Context-Free Grammars.

Gramticas y Lenguajes a

las cadenas que constituyen nuestro lenguaje. A este respecto, dada una gramtica G = (N, , P, S), y una derivacin indirecta a o A en G, diremos que se trata de una derivacin por o la derecha (resp. por la izquierda) si y slo si: o AP (resp. ) y utilizaremos la notacin A rm (resp. A lm o ) para representarla. Por defecto supondremos que toda derivacin es por la derecha, considerndola una derivacin o a o cannica. o Ejemplo 1.2.1 Siguiendo en la lnea del ejemplo 1.1.2 y considerando la gramtica de las expresiones aritmticas del a e ejemplo 1.1.1, tenemos: S lm (S) lm (S + S) lm (a + S) lm (a + a) S rm (S) rm (S + S) rm (S + a) rm (a + a) 2 Una vez hemos introducido formalmente el concepto de lenguaje generado por una gramtica, debemos establecer una a primera e importante diferenciacin en los lenguajes atendiendo o al n mero de derivaciones cannicas existentes para una cadena u o dada. En esencia, se trata de aproximarse de una forma simple al problema de la ambigedad sintctica en los lenguajes. As u a , desde un punto de vista formal diremos que G = (N, , P, S) es una gramtica ambigua si y slo si existe x L(G) para la a o cual hay al menos dos derivaciones cannicas S x. En la o misma l nea, decimos que el lenguaje L no es ambiguo si y slo o si existe una gramtica G = (N, , P, S) no ambigua, tal que a L = L(G). En contraposicin, diremos que L es un lenguaje o ambiguo cuando no existe una gramtica no ambigua que lo a genere.

1.2. Lenguaje generado por una gramtica a

Ejemplo 1.2.2 La gramtica de las expresiones aritmticas del a e ejemplo 1.1.1 es ambigua puesto que la cadena 2 + 3 4 puede derivarse de dos formas distintas:
S S S+S SS S+SS S4 S+S4 S+S4 S+34 S+34 2+34 2+34

Sin embargo, el lenguaje de las expresiones aritmticas no es e ambiguo puesto que es posible denir una gramtica no ambigua a que lo genere. Dicha gramtica puede ser la dada por las reglas a siguientes: EE + T T T F F (E) ET T F F nmero u

Estas nuevas reglas introducen implcitamente los conceptos de asociatividad a la izquierda y de prioridad del operador sobre el operador +. Con ello se evitan las ambigedades en expresiones u del tipo nmero1 op0 nmero2 op0 nmero3 u u u y nmero1 op1 nmero2 op2 nmero3 u u u respectivamente, donde opi {+, }, i {0, 1, 2} y op1 = op2 . 2 Finalmente, es interesante hacer notar que no todas las reglas ni s mbolos de una gramtica son forzosamente imprescindibles a para la generacin del lenguaje asociado. En efecto, en al menos o dos casos el razonamiento es trivial a partir de la denicin o misma de lenguaje: En el caso en el que un s mbolo A no pertenezca a ninguna forma sentencial, es evidente que toda regla de la forma A es irrelevante para la generacin del lenguaje. En este caso o decimos que A es un smbolo inaccesible.

10

Gramticas y Lenguajes a

Si un s mbolo A N es tal que, a n perteneciendo a una u forma sentencial del lenguaje, no existe ninguna regla del tipo A de forma que A es evidente que ser imposible generar sentencias del a lenguaje a partir de dichas formas sentenciales. En este caso decimos que A es un smbolo inutil. En todo caso es fcilmente demostrable que es posible eliminar a tanto s mbolos inaccesibles como in tiles de una gramtica, u a sin por ello afectar en absoluto a la integridad del lenguaje generado [1]. A una gramtica que no contiene ni s a mbolos inutiles, ni inaccesibles, ni reglas, ni reglas de transmisin o simple, se le denomina gramtica reducida. a

Cap tulo 2

Anlisis Sintctico a a
Una vez construida la gramtica de un lenguaje, es necesario a poner en marcha un mecanismo de reconocimiento tanto de las categorias lxicas como de las sintcticas, previo a la e a implementacin del mismo en un soporte f 1 . Al primero o sico se le suele llamar analizador lxico y de alg n modo constituye e u el diccionario de nuestro lenguaje. El segundo es el encargado de reconocer en la estructura de nuestro texto, las reglas de la gramtica y se le denomina analizador sintctico. Por debajo a a de este ultimo, suele considerarse la nocin de reconocedor o sintctico entendido como herramienta que verica la adecuacin a o de la estructura de la frase a la gramtica considerada, a mientras que el analizador sintctico construye adems una a a representacin del proceso de anlisis. Para facilitar la labor o a tanto de reconocimiento como de anlisis sintctico, se suelen a a considerar gramticas aumentadas. Formalmente, dada una a gramtica G = (N, , P, S), decimos que Ga = (Na , a , Pa , Sa ) a es su correspondiente gramtica aumentada si verica las a condiciones siguientes: Na = N a = P a = P S a = donde N . Ello quiere decir que en una gramtica a aumentada es fcilmente reconocible el nal de un proceso de a
1 esto

es, en un ordenador.

11

12

Anlisis Sintctico a a

anlisis sintctico. En efecto, basta con haber reconocido el no a a terminal , puesto que este slo aparece una vez y en una sola o produccin de la gramtica que genera el lenguaje. En esta o a seccin comentaremos algunos aspectos interesantes en relacin o o a los analizadores sintcticos. a En general, podemos distinguir dos grandes tipos de analizadores en relacin al modo en que abordan el o reconocimiento de las reglas de la gramtica: los ascendentes a 2 y los descendentes . Un algoritmo de anlisis descendente es, a por denicin, aquel que aplica sistemticamente el concepto de o a derivacin izquierda. Un anlisis ascendente, por el contrario, es o a aquel que aplica sistemticamente el concepto de derivacin por a o 3 la derecha . Esta, aparentemente, peque a diferencia se traduce n en comportamientos fuertemente diferenciados en cuanto al rendimiento del analizador sintctico, y ello desde dos puntos a de vista distintos: Por un lado, la eciencia a nivel de la complejidad tanto temporal como espacial, en lo que a la implementacin o prctica se reere. As los analizadores descendentes a , requieren en general menos memoria para su programacin. o En contraposicin, su rendimiento en cuanto a velocidad o de tratamiento de las estructuras sintcticas est muy por a a detrs de los algoritmos de anlisis ascendente. Se trata, a a en denitiva, del viejo enfrentamiento entre eciencia de tratamiento y minimizacin de la memoria necesaria para o la implementacin. o Por otra parte, el conjunto de gramticas capaces de ser a tratadas de forma efectiva por un algoritmo descendente es inferior, en general, al dominio representado por los analizadores ascendentes. De hecho, el segundo incluye en la prctica al primero. a Una vez aqu y puesto que este no es un curso de lenguajes , formales, intentaremos justicar nuestro razonamiento mediante
2 tambin e 3 existen

denominados predictivos. tambin algoritmos de anlisis sintctico que aplican tcnicas mixtas. e a a e

13

ejemplos simples. Para ello, partiremos de las gramticas a anteriormente consideradas para las expresiones aritmticas: e la ambigua del ejemplo 1.1.1 y la determinista introducida al nal del ejemplo 1.2.2. Es importante dejar bien claro que las diferencias que vamos a exponer en la discusin que sigue, en o cuanto a la aplicacin de un tipo u otro de analizador sintctico, o a no dependen del hecho de que una gramtica sea ambigua y la a otra no. El origen ser la forma de las reglas de la gramtica a a en cada caso. A este respecto, decimos que G = (N, , P, S) es una gramtica recursiva por la izquierda cuando es posible una a derivacin del tipo o + A A aplicando reglas en P . En el caso particular en el que existe en P una regla de la forma A A hablamos de recursividad izquierda directa. El concepto de recursividad por la izquierda es importante por dos razones: En la prctica todos los lenguajes tienden a representarse a de forma natural mediante gramticas recursivas por la a 4 izquierda . Los analizadores descendentes son incapaces de abordar simplemente el anlisis de gramticas recursivas por la a a izquierda. Antes de considerar algunos ejemplos ilustrativos, es necesario denir el concepto de arbol de derivacin. Formalmente, dada o una gramtica de contexto libre G = (N, , P, S), diremos que a un arbol T etiquetado y orientado, es un arbol de derivacin o para G si verica las dos propiedades siguientes:
4 el paso de una gramtica recursiva por la izquierda a otra no recursiva por la a izquierda y que genera el mismo lenguaje, es posible en todos los casos, pero el proceso conlleva una prdida importante de legibilidad de la gramtica por parte del diseador e a n del lenguaje. El mtodo se conoce como paso a la Forma Normal de Greibach y puede e ser consultado por el lector interesado en [1].

14

Anlisis Sintctico a a

La ra de T est etiquetada con el axioma S de la z a gramtica G. a Si T1 , T2 , . . . , Tn son subrboles descendientes directos de a la ra de T , y la ra de Ti , i {1, . . . , n}, est etiquetada z z a con Si , entonces: S S1 S2 . . . Sn es una produccin en P . o Cuando Si , entonces Si es un arbol de derivacin o para la gramtica Gi = (N, , P, Si ). a En este punto, es importante observar que el axioma de la gramtica es la categor sintctica a partir de la que se podrn a a a a derivar todos los textos analizables seg n la gramtica dada. De u a ah el nombre de s mbolo inicial de la gramtica. En ocasiones, a a los arboles de derivacin se les denomina simplemente arboles o sintcticos. a Ejemplo 2.0.3 Ejemplos simples de arboles de derivacin son o los mostrados en la gura 2.1 para la gramtica ambigua de las a expresiones aritmticas considerada en el ejemplo 1.1.1, cuando e la entrada viene dada por la cadena 2 + 3 4. 2
S S
2

S S S
3

S S
4

*
S
3

S
4

S
2

Figura 2.1: Arboles de derivacin para las expresiones aritmticas ambiguas o e con la cadena de entrada 2 + 3 4

A partir del concepto de arbol de derivacin, podemos o introducir la nocin de frontera de un arbol de derivacin T o o como la cadena obtenida al concatenar las hojas5 de dicho arbol de izquierda a derecha. Evidentemente, si el anlisis sintctico a a
5 esto

es, los nodos terminales.

2.1. Tcnicas descendentes e

15

ha tenido xito, la frontera del arbol de derivacin ha de coincidir e o con la cadena analizada.

2.1

Tcnicas descendentes e

Un analizador sintctico se denomina descendente cuando a construye los arboles de derivacin a partir del axioma de la o gramtica considerada, expandiendo el nodo correspondiente a mediante predicciones. Esto es, los analizadores descendentes exploran los arboles en profundidad. De este modo, las tcnicas e correspondientes son predictivas en cuanto que por construccin o deben predecir cules son las reglas de la gramtica a aplicar en a a la derivacin de un nodo del arbol sintctico, puesto que en o a ese estadio de la construccin del arbol podemos no conocer o todav la frontera del nodo en cuestin. Ms formalmente, a o a las reglas aplicadas en un anlisis predictivo se corresponden a con una derivacin de la cadena de caracteres que constituye la o entrada, de izquierda a derecha. Ejemplo 2.1.1 Como ejemplo simple, tomemos la gramtica de a las expresiones aritmticas no ambiguas previamente introducida e en el ejemplo 1.2.2. A partir de la misma, realizaremos un anlisis descendente muy simple de la cadena 2 + 3 4. a Comenzaremos por predecir cules son las posibles alternativas a para derivar el axioma E de dicha gramtica. En principio, a podemos considerar la primera produccin, lo cual nos dar o a como resultado un arbol cuyas primeras ramas son las mostradas en la parte superior izquierda de la gura 2.2. En este punto, es importante observar que la eleccin de esta regla de derivacin o o poda haber sido en principio la otra posible, esto es, E T . En este ultimo caso, slo detectaramos el error en la eleccin o o ante la imposibilidad de derivar el smbolo +. Una vez salvado el primer escollo, y siguiendo una exploracin en profundidad, el siguiente paso es predecir la regla o a aplicar para la derivacin de la variable E situada ms a la o a izquierda en el arbol que hemos comenzado a construir. En este

16

Anlisis Sintctico a a

punto, la eleccin no adecuada de la misma puede conducirnos o a una situacin sin salida para nuestro analizador sintctico. o a Ms exactamente, supongamos que sistemticamente intentamos a a aplicar las derivaciones posibles de una variable siguiendo el orden indicado por las reglas de la gramtica en cuestin. En ese a o caso, para derivar E aplicaramos siempre la regla E E + T en una exploracin en profundidad, pero ello nos llevara a la o construccin de arboles con ramas de profundidad innita como o la representada en la gura 2.3. La eleccin correcta de las o reglas, para el anlisis descendente de la cadena de entrada que a nos ocupa, es la indicada en la gura 2.2 siguiendo los dibujos de izquierda a derecha y de arriba hacia abajo. 2
E E E E

Figura 2.2: Un ejemplo de anlisis descendente a

El problema planteado en el ultimo ejemplo, acerca de la generacin de ramas de profundidad innita, es consecuencia o directa de la aplicacin de una construccin en profundidad o o del arbol sintctico cuando la gramtica que dene el lenguaje a a es recursiva por la izquierda. Ello representa una limitacin o fundamental para la aplicabilidad de los algoritmos de anlisis a descendente, por cuanto la prctica totalidad de los lenguajes a incluyen la misma de forma natural. En contraposicin, este tipo o

2.2. Tcnicas ascendentes e

17

de algoritmos permiten una implementacin extremadamente o simple, adems de poco costosa desde el punto de vista del a ordenador.
E E E E E

+
T

+
T

+
T

Figura 2.3: Una rama de profundidad innita

2.2

Tcnicas ascendentes e

En total contraposicin a los analizadores descendentes, en los o analizadores ascendentes la derivacin de la cadena de caracteres o que constituye en cada caso la entrada del analizador, se realiza de derecha a izquierda. Esto es, slo se considera una regla de la o gramtica cuando se est seguro de que la misma es idnea para a a o la construccin del arbol en construccin. Ms exactamente, o o a el analizador procede reconociendo subrboles que servirn a a posteriormente para construir otros mayores hasta completar el arbol sintctico resultante. Ello implica que el sistema debe a reconocer la estructura del arbol comenzando por sus niveles inferiores, en primer trmino por sus hojas. A partir de este e punto, el sistema busca las reglas que posibilitan la reduccin6 de o dichas hojas, para ms tarde continuar buscando producciones a capaces de reducir los nuevos s mbolos as obtenidos hasta la reduccin nal del s o mbolo inicial. Una consecuencia importante de la arquitectura aqu
6 cuando el tipo de anlisis considerado es ascendente, el trmino reduccin se aplica a e o para expresar que en una regla, la parte derecha de la misma ha sido totalmente reconocida. En ese momento, el no terminal que constituye la parte izquierda de la regla puede considerarse igualmente reconocido sintcticamente. a

18

Anlisis Sintctico a a

considerada para el analizador sintctico, es la independencia de a su aplicabilidad en relacin a la presencia o no de recursividad o por la izquierda en la gramtica que genera el lenguaje utilizado. a Ello implica que, en general, todo lenguaje analizable mediante un mtodo descendente puede ser reconocido tambin por un e e analizador ascendente. Esto es, el dominio de aplicacin de o estos algoritmos es notablemente superior al de los descendentes. La otra cara de la moneda es su mayor complejidad de implementacin sobre un soporte f o sico. Ejemplo 2.2.1 Para mostrar la tcnica general aplicada e en los analizadores ascendentes, y en particular su buen comportamiento frente al fenmeno de la recursividad por o la izquierda, trataremos el mismo problema planteado en el anterior ejemplo 2.1.1. As, una vez ledo el carcter 2 de la a cadena de entrada 2 + 3 4, el analizador reduce la regla F nmero u dando lugar al subrbol representado en la parte superior a izquierda de la gura 2.4. A su vez, una vez reconocido el smbolo
F T E E

+
T

+
T

T F

F F 3 2 T E F

2 E

2 E

2 E

+
T

+
T

+
T

*
4

+
T

F F 3 2

F F 3 2

F F 3 2

F F 3 2

Figura 2.4: Un ejemplo de anlisis ascendente a

no terminal F , el analizador puede aplicar la regla T F

2.2. Tcnicas ascendentes e

19

para reducir la variable T a partir de la parte del arbol sintctico a ya construido en el paso anterior. De este modo obtenemos el subrbol siguiente representado en la gura 2.4. Un proceso a similar se sigue para obtener el siguiente subrbol mediante la a aplicacin de la regla o ET Una vez llegados aqu, la unica posibilidad est en continuar a leyendo la cadena de entrada, cuyo siguiente carcter es +, a puesto que no podemos aplicar ms reducciones. De este a modo obtenemos un conjunto de dos subrboles: el primero a heredado del paso anterior y el segundo formado por la hoja +. En este punto, todava no podemos aplicar ninguna reduccin o y continuamos leyendo la cadena de entrada cuyo siguiente carcter es 3. Ahora podemos reducir sucesivamente las reglas a F nmero u T F

En principio seran ahora posibles dos alternativas: Considerar una reduccin mediante la aplicacin de la regla o o E T. Continuar leyendo en la cadena de entrada. Esto es, aplicar lo que se conoce como un desplazamiento en la cadena de entrada. Cuando este tipo de situaciones se da, se dice que existe un conicto de tipo desplazamiento/reduccin7 . Estos han de o resolverse mediante la aplicacin de alguna tcnica especca. o e Ello constituye justamente uno de los factores que suele establecer la diferencia entre los distintos tipos de analizadores ascendentes. En nuestro caso, decidirse por una de las dos posibilidades es muy sencillo, puesto que una reduccin mediante o E T no sera viable al no permitir ms tarde la lectura a del smbolo . Por tanto, la unica salida posible es la lectura
7 tambin es posible la aparicin de conictos de tipo reduccin/reduccin. e o o o Por otro lado, es evidente que es innecesario plantearse la existencia de conictos desplazamiento/desplazamiento.

20

Anlisis Sintctico a a

del carcter . En este estadio, tampoco es posible aplicar a nuevas reducciones y continuamos leyendo la cadena de entrada cuyo smbolo siguiente es 4. A partir de aqu, aplicamos sucesivamente las siguientes reducciones hasta llegar al nal del anlisis sintctico con la reduccin del axioma E: a a o T T F 2 E E+T

2.3

Eliminacin de ambig edades o u

Los anteriores ejemplos 1.1.1 y 1.2.2 sirven de presentacin para o el problema de las ambig edades en las gramticas de contexto u a libre, as como para la introduccin de algunas tcnicas clsicas o e a en el tratamiento de las mismas. El problema es, en general, complejo y no siempre fcil de abordar. Sin embargo, en casos a como los presentados su tratamiento es estndar y servir de a a justicacin a la metodolog aplicada en los lenguajes lgicos o a o de programacin para la introduccin de nuevos operadores. o o Ms exactamente, en una situacin como la presentada en el a o ejemplo 1.1.1, las ambig edades de la gramtica tienen dos u a or genes bien denidos: Por un lado, la asociatividad de los operadores no ha sido jada. Esto es, en el caso particular que nos ocupa, no sabemos si evaluar las expresiones de derecha a izquierda, o de izquierda a derecha. Concretamente, para la expresin o 2 + 3 + 4 tendr amos los dos posibles arboles sintcticos a mostrados en la gura 2.5, y ello independientemente de que el tipo de anlisis considerado sea ascendente o a descendente. Por otra parte, las reglas de la gramtica no inducen a ning n tipo de prioridad en la evaluacin de las distintas u o subexpresiones. Este es el problema planteado en el anlisis a de 2 + 3 4, tal y como se mostraba en la gura 2.1.

2.3. Eliminacin de ambigedades o u


S S + S S
+

21
S S
+

Figura 2.5: Arboles de derivacin para las expresiones aritmticas ambiguas o e con la cadena de entrada 2 + 3 + 4

En cualquiera de los dos casos considerados, la cuestin inicial o es la denicin incompleta del mecanismo de evaluacin de los o o operadores. Situaciones de este tipo son muy corrientes en la denicin de los lenguajes de programacin, y desde luego sern o o a factores a considerar en cualquier protocolo de introduccin o dinmica de operadores en lenguajes de programacin. La a o solucin al problema planteado pasa por la aplicacin de una o o de las dos tcnicas siguientes: e La introduccin expl o cita tanto del tipo de asociatividad considerada para cada operador, como de su prioridad en relacin a los dems. La principal ventaja de esta o a aproximacin es que no requiere una alteracin previa de o o la gramtica original. Ello permite fcilmente un uso a a dinmico de la tcnica. Por el contrario, es importante a e constatar que el origen del problema no se ha abordado en absoluto. En efecto, las producciones de la gramtica no a han sido modicadas. La introduccin impl o cita de la asociatividad y de las prioridades entre los operadores, aprovechando el formalismo descriptivo del lenguaje. Este es el acercamiento que permiti eliminar las ambig edades en o u el ejemplo 1.2.2, donde la posicin de los operadores en la o nueva gramtica se diferencia claramente en lo que se reere a

22

Anlisis Sintctico a a

a su accesibilidad desde el axioma. As la multiplicacin , o aparece representada por un operador situado a mayor profundidad en la estructura de la gramtica con respecto a a la suma. Ello garantiza para la multiplicacin una prioridad o de evaluacin ms elevada que para la adicin. o a o En relacin a la introduccin de asociatividades para los o o operadores, la recursividad izquierda en las reglas de la gramtica propuesta garantiza una asociatividad por la a izquierda. Esto es, la evaluacin se realizar de izquierda a o a derecha. Con respecto a la solucin propuesta anteriormente, esta o ultima es sin duda ms elegante y completa. En efecto, a hemos abordado el origen mismo del problema, la forma inapropiada de las producciones. Sin embargo, una solucin o de este tipo no puede ser considerada como dinmica por a cuanto su aplicacin conlleva un redise o completo de la o n gramtica que sirve de sustento a nuestro lenguaje. a

Parte II

Lgica: Conceptos o Fundamentales

23

Cap tulo 3

Clculo de Proposiciones a
Este cap tulo constituye una introduccin a los conceptos o fundamentales del clculo de proposiciones. El poder expresivo a de las lgicas basadas en la nocin de proposicin es o o o limitado debido sobre todo a la ausencia del concepto genrico e 1 de variable , pero su conocimiento es imprescindible para comprender posteriormente otras lgicas ms avanzadas, como o a las basadas en el concepto de predicado. Las lgicas basadas en proposiciones surgen como un intento o de formalizar el conocimiento que se posee del mundo, a travs de un lenguaje formal cuyas sentencias sean fcilmentes e a manipulables mediante la aplicacin de unas reglas sencillas. Los o elementos individuales de las sentencias son identicadores que expresan hechos ciertos o falsos acerca del mundo. Por ejemplo, casa roja es un identicador, cuyo valor puede ser T (verdadero) o F (falso). Todos los identicadores son de tipo booleano. Este es precisamente el origen de las limitaciones en su uso. Inicialmente los identicadores pueden construirse tomando enunciados del mundo real que representan conceptos atmicos o en el sentido de que no se expresan a partir de una relacin o entre otros conceptos ms simples. De este modo podemos a representar el concepto la casa es roja mediante la expresin o casa roja T .
1 en

lgica de proposiciones slo existe el concepto de variable boolena. o o

25

26

Clculo de Proposiciones a

Para poder expresar un mayor conocimiento acerca del mundo que nos rodea es necesario poder combinar los identicadores para formar expresiones complejas. Los operadores lgicos son los encargados de realizar esta tarea. o En la tabla 3.1 se muestran los cinco operadores lgicos o fundamentales: la negacin, la conjuncin, la disyuncin, la o o o implicacin y la igualdad. Los cuatro ultimos son binarios, o mientras que la negacin es unaria. o

Operador =

Nombre conjuncin o disyuncin o implicacin o equivalencia negacin o

Resultado T si los dos operandos son T . T si alguno de los dos operandos es T . T si el segundo operando es una consecuencia del primero. T si los dos operandos tienen el mismo valor. T si el operando es F .

Tabla 3.1: Tabla de operadores lgicos o

Estos operadores no slo combinan identicadores para o formar sentencias, sino que pueden ser aplicados a las propias sentencias. De este modo, es posible construir sentencias complejas mediante la combinacin de otras ms simples. Como o a en todo lenguaje, existe una gramtica que expresa la forma en a que se deben combinar los distintos elementos para construir frases o sentencias sintcticamente correctas. A continuacin a o se muestra una gramtica de contexto libre para la lgica de a o

3.1. Evaluacin de proposiciones: tablas de verdad o

27

proposiciones: P roposicin o | | | | | | | T F (Identif icador) (P roposicin P roposicin) o o (P roposicin P roposicin) o o (P roposicin P roposicin) o o (P roposicin = P roposicin) o o (P roposicin) o

La gramtica utilizada es muy limitada en el sentido de a que las precedencias de evaluacin entre operadores, as como o sus asociatividades, deben ser indicadas expl citamente por el programador mediante el uso de parntesis. Ello hace de esta e gramtica un procedimiento engorroso de descripcin, aunque a o desde un punto de vista meramente orientativo sea vlida. a

3.1

Evaluacin de proposiciones: tablas de o verdad

Con la escritura de la gramtica ha surgido una cuestin a o importante: la de la evaluacin de proposiciones. Ya hemos o visto que las proposiciones complejas surgen de la combinacin o de proposiciones ms simples, las cuales pueden tomar valor a T o F . El modo de obtener el valor de la proposicin o resultante consistir en realizar una evaluacin ascendente a o de las proposiciones a partir de sus elementos ms simples. a Los resultados de las evaluaciones de estos se reejan para cada operador en una tabla denominada tabla de verdad. En la tabla 3.2 aparecen representadas las tablas de verdad correspondientes a los cinco operadores lgicos introducidos o anteriormente.

28

Clculo de Proposiciones a

p T T F F

q T F T F

(p) F F T T

(p q) (p q) (p q) (p = q) T T T T F T F F F T T F F F T T

Tabla 3.2: Tablas de verdad para los operadores lgicos denidos o

3.1.1

Evaluacin de proposiciones constantes o

Por proposicin constante se entiende aquella que no posee o identicadores, es decir, que est construida mediante la a aplicacin de los operadores directamente sobre los valores T o y F . Ejemplos de proposiciones constantes son: (T ), (T F ), ((F T ) T ). La evaluacin de este tipo de proposiones es sencilla, ya o que tan slo hay que ir sustituyendo, desde los parntesis o e interiores hacia los exteriores, la aplicacin de un operador por o su resultado, que se obtiene directamente de la tabla de verdad. Ejemplo 3.1.1 Tomemos la proposicin o (((T (T )) F ) T ) que se transforma en (((T F ) F ) T ) al sustituir (T ) por su resultado segn la tabla de verdad, que u es F . Al sustituir la primera disyuncin obtenemos o ((T F ) T ) Ahora, sustituyendo la conjuncin, llegamos a o (F T ) para obtener nalmente T .2

3.1. Evaluacin de proposiciones: tablas de verdad o

29

3.1.2

Evaluacin de proposiciones en estados o

Cuando las proposiciones no son constantes, hay que tener en cuenta el valor de las variables en el momento en que se eval a u la proposicin. Por ejemplo, la proposicin o o (casa roja puerta verde) se eval a a T si es cierto que nos hallamos ante una casa roja u con una puerta verde. Pero este no tiene porqu ser el caso en e todo momento. El conjunto de los valores de todas las variables denidas constituye el estado en el que se eval an las proposiciones. Ms u a formalmente, diremos que un estado S es una funcin que lleva o un conjunto de identicadores en el conjunto {T , F }: S : {identif icadores} {T , F } Sin embargo, no siempre es posible evaluar una proposicin o en un estado, simplemente porque es posible que no todos los identicadores implicados en la misma estn denidos. Es por e ello necesario introducir el concepto de proposicin bien denida. o As decimos que una proposicin est bien denida en un estado , o a si cada identicador de la proposicin est asociado bien a T o o a bien a F en dicho estado. Ejemplo 3.1.2 Sea el estado S igual a {(p, F ), (q, T )}, entonces las siguientes proposiciones estn bien denidas: a (p q) (q) (p ((p q) (p))) mientras que las siguientes no lo estn: a (a) ((p q) a) (p ((p b) (p))) porque las variables a y b no estn denidas en el estado S. 2 a

30

Clculo de Proposiciones a

El concepto de estado es muy importante en lenguajes de programacin, ya que durante la ejecucin de un programa o o los valores de las variables van cambiando, provocando la modicacin del estado de la mquina. Ello implica que al o a evaluar una misma expresin en varios lugares de un programa o se pueden obtener valores diferentes, ya que el estado de la mquina diere de un lugar a otro. As dado un estado S y a , una proposicin e bien denida en ese estado, suele notarse por o S(e) el valor obtenido al reemplazar todas las ocurrencias de los identicadores2 en el estado por sus valores correspondientes y evaluar las proposiciones constantes resultantes. En este caso, se dice que S(e) es el resultado de evaluar e en S. Ejemplo 3.1.3 El resultado de evaluar la proposicin o (((p) q) T ) en el estado S = {(p, T ), (q, F )} es el siguiente: S (((p) q) T ) = S (((T ) F ) T ) = F Este proceso se puede representar mediante la utilizacin de una o tabla de verdad en la que las columnas representan cada una de las subexpresiones que se van evaluando en cada paso. En este ejemplo, dicha tabla tendra el aspecto mostrado en la tabla 3.3. 2 3.1.3 Evaluacin de proposiciones sin parntesis o e

En las expresiones totalmente parentizadas, como son todas las mostradas hasta el momento, los parntesis se utilizan para e denir expresamente el orden de evaluacin de las distintas o subexpresiones contenidas en una proposicin. Dado que se o trata de un mecanismo relativamente incmodo, parece natural o
2 esto

es, variables booleanas.

3.1. Evaluacin de proposiciones: tablas de verdad o

31

p T T F F

q T F T F

(p) F F T T

((p) q) (((p) q) T ) T T F F T T T T

Tabla 3.3: Tabla de verdad para la expresin (((p) q) T ) o

restringir su utilizacin mediante la denicin de precedencias o o por defecto, tal y como ocurre en los lenguajes de programacin. o De este modo, el uso de parntesis quedar reducido a aquellos e a casos en los que se desee evaluar las subexpresiones en un orden distinto al establecido por defecto. Las reglas que se van a considerar en el proceso de establecimiento de las precedencias por defecto son las siguientes: 1. Las subexpresiones formadas por la aplicacin consecutiva o del mismo operador son evaluadas de izquierda a derecha. De este modo, la expresin p q r es equivalente a o ((pq)r). Esto es, estamos suponiendo una asociatividad por la izquierda, por defecto, para los operadores lgicos. o 2. En las expresiones formadas por la aplicacin de distintos o operadores, las subexpresiones se eval an atendiendo a la u prioridad de los operadores. La siguiente lista ordenada dene dichas prioridades: =, donde es el operador con mayor prioridad y = el de menor prioridad. En este momento, una vez establecidas expl citamente las prioridades y asociatividades de los operadores lgicos, podemos o eliminar los parntesis de la gramtica inicialmente considerada, e a

32

Clculo de Proposiciones a

para pasar a la siguiente : P roposicin o | | | | | | | | T F Identif icador P roposicin P roposicin o o P roposicin P roposicin o o P roposicin P roposicin o o P roposicin = P roposicin o o P roposicin o (P roposicin) o

donde la ultima regla permite el cambio expl cito de prioridades mediante el uso de parntesis. e Otra forma de eliminar la obligatoriedad en el uso de parntesis es la introduccin impl e o cita de asociatividades y prioridades en la gramtica utilizada para describir el lenguaje a de las proposiciones. Esto es, podemos escribir una nueva gramtica que contemple las prioridades y asociatividades a por defecto. Ello har que esta sea determinista en el a sentido de que slo sea factible un camino para analizar cada o proposicin, justamente la causa que nos oblig en un principio o o a incluir sistemticamente el uso de los parntesis. Una posible a e alternativa es la que se muestra a continuacin : o P roposicin o | Imp exp | Exp | T ermino | F actor | | | | Imp exp P roposicin = Imp exp o Exp Imp exp Exp T ermino Exp T ermino F actor T ermino F actor F actor (P roposicin) o T F Identif icador

3.1. Evaluacin de proposiciones: tablas de verdad o

33

En este punto, es importante observar que la precedencia entre operadores queda establecida por el nivel de profundidad en el que aparecen en la gramtica. As cuanto mayor es esta, mayor a , es la prioridad. De la misma forma, la asociatividad por la izquierda se introduce impl citamente en la recursividad por la izquierda de las reglas consideradas. Al igual que en el caso de la gramtica inicial con parntesis, a e es posible dar una denicin de la evaluacin de proposiciones o o dirigida por la sintaxis de la nueva gramtica y de carcter a a recursivo, tal como se muestra a continuacin: o
S(< P roposicin >) = S(< Imp exp >) o S(< P roposicin >) = (S(< P roposicin >) = S(< Imp exp >)) o o . . . S(< F actor >) = S(< Identif icador >)

Evidentemente, cuando se llega al nivel de las expresiones constantes, se utilizarn las tablas de verdad para proceder a a su evaluacin. o 3.1.4 Tautolog as

Hemos visto que el resultado de la evaluacin de una proposicin o o depende del estado en el cual se realiza dicha evaluacin. o Sin embargo, hay ciertas expresiones que siempre producen el mismo resultado independientemente del estado en el que se eval en. Este tipo de proposiciones es particularmente u importante por cuanto se corresponden con el concepto intuitivo de frmula lgica. Desde un punto de vista prctico, estas son o o a las proposiciones en las que estamos interesados: aquellas que expresan relaciones ciertas entre objetos, cualesquiera que sean los valores manipulados. Ejemplo 3.1.4 Vamos a evaluar la proposicin (p q) = o (p q) para todos los posibles valores de sus operandos. Esto es equivalente a evaluar la proposicin en todos los posibles estados o en los que est bien denida. Para ello basta con construir su e tabla de verdad, tal y como se muestra en la tabla 3.4. A partir

34

Clculo de Proposiciones a

de sta, es fcilmente vericable la verdad de la proposicin, e a o cualquiera que sea el estado en el que sea evaluada, siempre y cuando nuestra proposicin est bien denida. 2 o e

p T T F F

q T F T F

p F F T T

p q T F T T

pq T F T T

(p q) = (p q) T T T T

Tabla 3.4: Tabla de verdad para la proposicin (p q) = (p q) o

A una proposicin que, como en el caso del anterior o ejemplo 3.1.4, posee un valor constante T cualquiera que sea el estado en el que est bien denida se le denomina tautologa. e Dado que stas constituyen las frmulas vlidas para el clculo e o a a de proposiciones es necesario plantearse una metodolog con el a objeto de vericar el carcter tautolgico de las proposiciones. a o En relacin a este problema, podemos distinguir dos losof o as bien diferenciadas en razn del objetivo que se persiga y teniendo o presentes las herramientas introducidas hasta el momento: Para demostrar el carcter tautolgico tendremos que a o probar que para todos los casos posibles la evaluacin de o la proposicin da como resultado T . Esto conlleva la o construccin y vericacin expl o o cita de las tablas de verdad, lo que con toda probabilidad constituir un proceso muy a costoso desde el punto de vista computacional. Si lo que pretendemos es descalicar la conjetura tautolgica, el proceso es en principio mucho ms sencillo, o a puesto que es suciente con encontrar un solo caso de estado en el que la proposicin est bien denida y se eval e a F , o e u para probar que no es una tautolog El proceso resulta a. computacionalmente menos costoso que en el caso anterior,

3.2. Reglas de reescritura

35

al menos cuando seamos capaces de proponer alg n sistema u efectivo de b squeda de este tipo de estados. u En cualquier caso, parece claro que el formalismo de las tablas de verdad, si bien extremadamente simple e intuitivo, no es el ms conveniente para la puesta en prctica del clculo de a a a proposiciones. En este punto se hace necesaria la introduccin o de un entorno de clculo ms manejable y que no exija un retorno a a continuo a la evaluacin al ms bajo nivel, representado por las o a tablas de verdad.

3.2

Reglas de reescritura

Hasta ahora hemos visto un estilo de razonamiento con proposiciones consistente en la utilizacin de tablas de verdad o y en la evaluacin exhaustiva. Este tipo de razonamiento o tiene un carcter de procesamiento aritmtico/lgico, ya que a e o trata de llegar a expresiones constantes que son resueltas aplicando las tablas de verdad para cada operador. Existe un modo de razonamiento basado en proposiciones que utiliza una manipulacin de ms alto nivel en las mismas, consistente en la o a derivacin de expresiones equivalentes. o La idea general consiste en transformar una proposicin o compleja en otra ms simple que sea equivalente a la anterior, es a decir, que el resultado de evaluar ambas en cualquier estado en el que estn bien denidas sea el mismo. Formalmente, diremos e que dos proposiciones P y Q son equivalentes si y slo si P = Q o es una tautolog a. En tal caso, se dice que P = Q es una equivalencia lgica. o Ejemplo 3.2.1 La expresin p q p es equivalente a p. o Obsrvese que esta ultima es ms simple, ms fcil de manejar. e a a a 2

36

Clculo de Proposiciones a

3.2.1

Leyes de equivalencia

No ganar amos nada con una posible simplicacin si para o transformar una proposicin en otra equivalente tuvisemos o e que vericar mediante tablas de verdad la validez de tal transformacin. o Afortunadamente, existe un conjunto de equivalencias, fcilmente comprobables, que se utilizan a habitualmente como base para realizar las transformaciones de equivalencia. A continuacin se enumeran estas o equivalencias, que tradicionalmente reciben el nombre de Leyes de Equivalencia: 1. Leyes conmutativas: (E1 E2 ) = (E2 E1 ) (E1 E2 ) = (E2 E1 ) (E1 = E2 ) = (E2 = E1 ) 2. Leyes asociativas: E1 (E2 E3 ) = (E1 E2 ) E3 E1 (E2 E3 ) = (E1 E2 ) E3 3. Leyes distributivas: E1 (E2 E3 ) = (E1 E2 ) (E1 E3 ) E1 (E2 E3 ) = (E1 E2 ) (E1 E3 ) 4. Leyes de De Morgan: (E1 E2 ) = E1 E2 (E1 E2 ) = E1 E2 5. Ley de la negacin: o (E) = E 6. Ley del medio excluido: E E = T 7. Ley de la contradiccin: o E E = F

3.2. Reglas de reescritura

37

8. Ley de la implicacin: o E1 E2 = E1 E2 9. Ley de la igualdad: (E1 = E2 ) = (E1 E2 ) (E2 E1 ) 10. Leyes de la simplicacin del : o E E =E E T =T E F =E E1 (E1 E2 ) = E1 11. Leyes de la simplicacin del : o E E =E E T =E E F =F E1 (E1 E2 ) = E1 12. Ley de la identidad: E=E Como hemos comentado con anterioridad, se puede comprobar fcilmente la veracidad de cada una de las a equivalencias en relacin a la lgica introducida en la discusin o o o precedente, construyendo la correspondiente tabla de verdad. Sin embargo, es importante se alar que el conjunto de leyes n enumeradas tambin podr ser considerado como el conjunto e a de axiomas a partir del cual denimos nuestra nueva lgica y o que en principio no tendr porqu coincidir con la denida por a e las tablas de verdad. Por otro lado, es necesario ahora completar este n cleo de leyes con un conjunto de reglas capaces de inferir u nuevas tautolog a partir de los conocimientos disponibles, esto as es, de permitirnos avanzar en nuestro conocimiento. 3.2.2 Reglas de sustitucin, resolucin y transitividad o o

Para poder razonar con proposiciones mediante la aplicacin o de las leyes de equivalencia vamos a introducir tres reglas de

38

Clculo de Proposiciones a

inferencia: la regla de sustitucin, la de resolucin, y la de o o transitividad. Ellas nos permitirn ensanchar el horizonte de a nuestras posibilidades en lo que al clculo de proposiciones se a reere y dejarn el camino abierto para el clculo de predicados. a a Regla de sustitucin o Formalmente, la regla de sustitucin establece que si E1 y o E2 son proposiciones equivalentes, y E(p) es una proposicin o 3 escrita como funcin de uno de sus identicadores p, entonces o se cumple que E(E1 ) = E(E2 ) y E(E2 ) = E(E1 ), es decir, que E(E1 ) y E(E2 ) son equivalentes. Utilizando la notacin habitual o en las reglas de inferencia, podemos escribir la de sustitucin en o la forma E1 = E 2 E(E1 ) = E(E2 ), E(E2 ) = E(E1 ) Ejemplo 3.2.2 Tomemos la equivalencia (a b) = (a b) y la proposicin E(p) = c p. Entonces, aplicando la regla de o sustitucin y tomando: o E1 = a b E2 = a b se cumple que c (a b) = c (a b) es una equivalencia. 2 Regla de resolucin o La regla de resolucin ser una pieza clave en la construccin o a o de demostradores de teoremas, o lo que es lo mismo, en la construccin de intrpretes lgicos. Formalmente, la regla de o e o inferencia en cuestin es la siguiente: o (a b) (a c) bc
que una proposicin esta escrita como funcin de un identicador si ese o o identicador aparece en la proposicin en la forma de un operando. o
3 diremos

3.2. Reglas de reescritura

39

Para demostrar la veracidad de esta regla, tendremos que probar que si las premisas son ciertas, entonces tambin lo es la e conclusin. En principio, dos casos son posibles: o 1o caso: Si a = F , entonces puesto que estamos suponiendo que la premisa es cierta, tendremos que b = T . En consecuencia la conclusin es tambin cierta. o e 2o caso: Si a = F , entonces puesto que estamos suponiendo que la premisa es cierta, tendremos que c = T . Por tanto, bc=T. por lo que en cualquier caso la conclusin es cierta. o Regla de transitividad Esta regla nos permite encadenar sucesivas aplicaciones de las leyes de equivalencia y de las reglas de inferencia para pasar de una proposicin inicial a otra ms simplicada, o incluso a T o a en el caso de que se trate de una tautolog Formalmente, la a. regla de transitividad establece que si E1 = E2 y E2 = E3 son equivalencias, entonces E1 = E3 es una equivalencia. Claramente, esto indica que si de E1 podemos pasar, mediante la aplicacin de las reglas de equivalencia y/o o sustitucin a E2 , y de esta ultima por el mismo procedimiento o somos capaces de pasar a E3 , entonces el paso de E1 a E3 es vlido, esto es, E1 y E3 son equivalentes. Esto es, tenemos que: a E1 = E 2 , E2 = E 3 E1 = E 3 Ejemplo 3.2.3 Se trata de demostrar la equivalencia (b c) = (c b). Para ello se van aplicando sucesivamente diferentes reglas de equivalencia: b c = b c (Implicacin) o = c b (Conmutatividad) = c b (Implicacin) o

40

Clculo de Proposiciones a

En cada paso se ha explicitado, a modo de aclaracin, la regla de o equivalencia aplicada. La utilizacin de signos = entre todas o las proposiciones indica que se puede aplicar la transitividad desde la primera de ellas hasta la ultima. 2 Ejemplo 3.2.4 Demostrar la ley de la contradiccin. Es o suciente probar que (e e) = T . Para ello partimos de (e e) y vamos buscando proposiciones equivalentes hasta llegar a T : (e e) = e e = e e = e e =T 2 Transformacin de implicaciones o Un caso particular muy importante, en relacin con la ley de o la transitividad, es el de la transformacin de implicaciones. o Supongamos que tenemos una proposicin del tipo o E1 E 2 . . . E n E y que queremos demostrar que se trata de una tautolog a. Evidentemente, la solucin consiste en aplicar las leyes de o equivalencia hasta llegar a la proposicin constante T . Sin o embargo, dicha tarea puede simplicarse notablemente si aplicamos tales leyes en un cierto orden: primero la ley de la implicacin y seguidamente la ley de De Morgan. El proceso o ser el siguiente: a E1 E 2 . . . E n E = (E1 E2 . . . En ) E = (E1 E2 . . . En ) E (Implicacin) o = E1 E2 . . . En E (De M organ) La proposicin nal es cierta si al menos una de las proposiciones o E1 , E2 , . . ., En , E lo es. Estas ultimas sern ms simples a a (De M organ) (N egacin) o (Conmutatividad) (M edio excluido)

3.2. Reglas de reescritura

41

que la original, por lo que el proceso de comprobacin de o la tautolog ser computacionalmente menos costoso. Esta a a tcnica ser aplicada, con profusin, en el motor de los e a o intrpretes lgicos. e o Ejemplo 3.2.5 Probar que ((b c) (b (c d))) (c d) es una tautologa. Para ello se realizan los siguientes pasos:
((b c) (b (c d))) (c d) = (b c) (b (c d)) (c d) (Implicacin y De M organ) o = (b c) (b (c d)) (c d) (N egacin) o = b c b c d c d (Implicacin y De M organ) o = b c b d (Simplif icacin del ) o =T cd (M edio excluido) =T (Simplif icacin del ) o

2 3.2.3 Axiomas y teoremas

En la discusin precedente hemos hablado en alg n momento o u de axiomas para referirnos a las leyes de equivalencia que hemos introducido como alternativa para denir nuestra lgica. o Nuestro objetivo ahora es el de formalizar el concepto. As , denominaremos axioma al resultado de sustituir proposiciones en las expresiones de las leyes de equivalencia. Esto es, a aquellas proposiciones cuya veracidad es consecuencia inmediata de la aplicacin de una o varias sustituciones en las leyes de o equivalencia. En la misma l nea, denominaremos teorema al resultado de aplicar una o varias veces las reglas de sustitucin o y transitividad sobre un axioma o sobre un teorema. En este sentido, se dice que dichas reglas sirven para inferir teoremas.

42

Clculo de Proposiciones a

Cap tulo 4

Clculo de Predicados a
Hemos visto en el cap tulo anterior que la lgica denida para las o proposiciones permit expresar conocimiento sobre los hechos a del mundo a la vez que proporcionaba un medio de manipular dicho conocimiento para inferir nuevos hechos. Sin embargo, el poder expresivo de las proposiciones est limitado por su a incapacidad de generalizacin. Se pueden indicar los hechos o de cada elemento individual del mundo, pero no se puede utilizar una unica expresin que abarque a todos los elementos. o Tomando un ejemplo clsico, la lgica de proposiciones a o permite expresar que Manolo, Miguel y Alberto son hombres y son mortales mediante las proposiciones hombre Manolo, hombre Miguel, hombre Alberto, mortal Manolo, mortal Miguel y mortal Alberto, pero no permite expresar que todos los hombres son mortales por el hecho de ser hombres. Para obtener la capacidad de generalizacin debemos abandonar o el mundo de las proposiciones y penetrar en un nivel ms a avanzado de la lgica, la lgica de predicados de primer orden. o o Adicionalmente, el uso de predicados nos permitir utilizar a expresiones booleanas1 en todos aquellos lugares en donde puedan aparecer identicadores en la lgica proposicional. o
es, expresiones de cualquier tipo con una unica caracter stica en comn: el u resultado de su evaluacin debe ser un valor booleano. o
1 esto

43

44

Clculo de Predicados a

4.1

Extensin del concepto de estado o

El clculo de predicados constituye una ampliacin del de a o proposiciones, dotndolo de mayor potencia y capacidad a expresiva. Estas mejoras provocan la necesidad de completar conceptos ya denidos en relacin al clculo de proposiciones. o a Uno de ellos es la nocin de estado. As consideraremos que un o , estado es una funcin que va de un conjunto de identicadores o a un conjunto de valores, eventualmente innito, que incluye T y F. S : {identif icadores} {T , F , . . .} Intuitivamente, un estado representa el contexto en el cual se eval a un predicado. En tal contexto, cada identicador se u encuentra ligado a un tipo al que pertenece. Un tipo dene un conjunto de elementos. El valor de un identicador en un estado deber estar comprendido en el conjunto de los valores denidos a por su tipo. Algunos de los tipos ms utilizados se muestran en a la tabla 4.1. Tipo Booleano Natural Entero . . . Conjunto de valores {T , F } {0,1,2, . . .} {. . ., -2, -1, 0, 1, 2, . . .} . . .

Tabla 4.1: Algunos tipos usados comnmente u

Adems es necesario poder extender el conjunto de a expresiones manejadas por nuestra lgica, hasta ahora o estrictamente limitado a las booleanas. En este sentido denominaremos expresin atmica a aquella que no se puede o o descomponer en otras ms simples seg n la gramtica de a u a proposiciones, pero a la que se puede asociar el valor T o F . Intuitivamente, este tipo de expresiones nos permite ampliar el clculo proposicional con toda una variedad de frmulas a o

4.1. Extensin del concepto de estado o

45

no exclusivamente lgicas. De este modo la limitacin antes o o expuesta puede ser fcilmente superada. a Ejemplo 4.1.1 La subexpresin x < y en la expresin (x < o o y) (x > y), donde x e y son identicadores que estn denidos a en el estado en el cual se evala esta ultima, es una expresin u o atmica. 2 o Una vez llegados a este punto, ya no queda ms que a incluir de forma efectiva el concepto de expresin atmica en o o nuestra lgica. Con este n, deniremos un predicado como o una expresin resultante de sustituir en una proposicin, los o o identicadores por expresiones booleanas o atmicas. o Ejemplo 4.1.2 A partir de la proposicin a b se puede o construir el predicado (x < y) b, resultado de sustituir a por x < y. 2 Como consecuencia de la inclusin del concepto de expresin o o atmica, tambin ser necesario redenir la nocin de o e a o evaluacin, con el objeto de extenderla al caso de los predicados. o As diremos que la evaluacin del predicado e en el estado S, , o denotada por S(e), es el valor obtenido al sustituir todos los identicadores por su valor en dicho estado. Evidentemente, los identicadores no tienen porqu ser ahora obligatoriamente e booleanos como en el caso ms restrictivo de las proposiciones. a Adems en este caso no estamos exigiendo que e est bien a e denido en S. Ejemplo 4.1.3 Sea P el predicado (x yy < z)(x+y < z) y S el estado denido por los siguientes pares identicador/valor: {(x, 1), (y, 3), (z, 5)}. Entonces el resultado de evaluar P en S es el siguiente: S((x y y < z) (x + y < z)) = S((T T ) T ) = T 2

46

Clculo de Predicados a

4.2

Los operadores cand y cor

En la denicin de la evaluacin de predicados, no se exig que o o a cada predicado estuviese bien denido en el estado en que se realizaba dicha evaluacin. Por consiguiente, en principio, se o puede evaluar un predicado en un estado en el cual no todos los identicadores involucrados estn denidos. Con el objeto de a formalizar este tipo de situaciones se hace necesario introducir un nuevo valor atmico, que denominaremos U , por indenido2 , o que acompa e a T y F como posible resultado de la evaluacin n o de una expresin booleana. o Como expresin de la utilidad prctica de la posibilidad de o a evaluacin con variables no ligadas a ning n valor, se introducen o u dos nuevas operaciones denominadas conjuncin condicional y o disyuncin condicional, y que denotaremos cand y cor. En o denitiva, se trata de variantes del y respectivamente, que realizan la conjuncin y la disyuncin sobre la lgica trivaluada o o o resultante. Las tablas de verdad correspondientes a ambos operadores lgicos se muestran en la tabla 4.2. Las operaciones o a T T T F F F U U U b T F U T F U T F U a cand b T F U F F F U U U a cor b T T T T F U U U U

Tabla 4.2: Tablas de verdad para los operadores cand y cor

cand y cor estn implementadas en la mayor de los lenguajes a a


2 undened

en ingls. e

4.2. Los operadores cand y cor

47

de programacin. Se suelen utilizar preferentemente en la o condicin de las instrucciones de control tales como if o while, o en las cuales se busca determinar lo antes posible el valor de dichas expresiones. Estos operadores verican una serie de interesantes propiedades que de alg n modo representan un claro paralelismo u en relacin a algunas de las leyes de equivalencia ya o introducidas. Antes de enumerarlas, es conveniente realizar algunas puntualizaciones acerca de la nocin de equivalencia o entre predicados cuando el valor U est presente. As decimos a , que: a b, si a = b en los estados en los que a y b estn bien a denidos. a b, si a = b en todos los estados, aun cuando aparezcan valores U en las expresiones. A continuacin se da una lista de las propiedades de cand y cor: o 1. Leyes asociativas: E1 cand (E2 cand E3 ) (E1 cand E2 ) cand E3 E1 cor(E2 cor E3 ) (E1 cor E2 ) cor E3 2. Leyes distributivas: E1 cand (E2 cor E3 ) (E1 cand E2 ) cor (E1 cand E3 ) E1 cor (E2 cand E3 ) (E1 cor E2 ) cand (E1 cor E3 ) 3. Leyes de De Morgan: (E1 cand E2 ) E1 cor E2 (E1 cor E2 ) E1 cand E2 4. Ley del medio excluido: E1 cor E1 E1 cand E1 T

5. Ley de la contradiccin: o F

48

Clculo de Predicados a

6. Leyes de la simplicacin del cor: o E1 cor E1 E1 E1 cor T T E1 cor F E1 E1 cor (E1 cand E2 ) E1 7. Leyes de la simplicacin del cand: o E1 cand E1 E1 E1 cand T E1 E1 cand F F E1 cand (E1 cor E2 ) E1

4.3

Cuanticadores

Una de las caracter sticas de los predicados, y que les conere mayor fuerza expresiva, es la posibilidad de cuanticar los identicadores. Ello permite expresar propiedades que se reeren a ms de un elemento sin tener que referenciar a expl citamente dicha propiedad para cada individuo involucrado. Los dos cuanticadores bsicos son el cuanticador universal y a el cuanticador existencial. A estos a adiremos un tercero, el n cuanticador numrico que generaliza los dos anteriores. e 4.3.1 El cuanticador universal

El cuanticador universal se utiliza para expresar una propiedad que se verica para todos los elementos de un conjunto. Formalmente aplicaremos la denicin que sigue. o Denicin 4.3.1 Sean m, n Z, con m < n. Entonces o Em Em+1 . . . En1 , i [m, n) Ei puede expresarse mediante el uso del cuanticador universal en la forma : (i : m i < n : Ei )

4.3. Cuanticadores

49

donde el conjunto [m, n) constituye el rango del cuanticador i. Esta notacin es equivalente a: o
n1 i=m Ei

2 Tambin podemos dar una denicin recursiva del cuanticador e o universal en la forma: 1. (i : m i < m : Ei ) = T 2. (i : m i < k + 1 : Ei ) = (i : m i < k : Ei ) Ek , con k m Ejemplo 4.3.1 Sea el conjunto A = {3, 6, 9, 12, 15}. Para expresar la propiedad de que todos los elementos de A son divisibles por 3, se utiliza el siguiente predicado: (i : 1 i < 6 : (Ai mod 3) = 0) donde Ai representa al elemento que ocupa la posicin i en el o conjunto A. Tambin se suele escribir e 5 (Ai mod 3) = 0 i=1 2 4.3.2 El cuanticador existencial

El cuanticador existencial permite expresar la existencia de al menos un elemento en un conjunto, que cumple un predicado. Formalmente la denicin es la que sigue. o Denicin 4.3.2 Sean m, n Z, con m < n. Entonces o Ei , i [m, n) Em Em1 . . . En1 puede expresarse mediante la utilizacin del cuanticador o existencial en la forma : (i : m i < n : Ei )

50

Clculo de Predicados a

que tambin podemos denotar en la forma siguiente: e


n1 i=m Ei

2 A imagen de la denicin recursiva considerada para el o cuanticador universal, en este caso podemos considerar la que sigue: 1. (i : m i < m : Ei ) = F 2. (i : m i < k + 1 : Ei ) = (i : m i < k : Ei ) Ek , con k m Tanto el cuanticador universal como el existencial se utilizan profusamente en el clculo de predicados y en la aplicacin a o de este a la programacin lgica, tal y como veremos en la o o continuacin de este texto. No es ese el caso, en general, del o cuanticador numrico que introducimos a continuacin. e o 4.3.3 El cuanticador numrico e

Un cuanticador menos conocido que los anteriores es el cuanticador numrico, que se utiliza en aquellos casos en los e que se desea explicitar el n mero de elementos dentro de un u rango que cumplen un determinado predicado. La notacin es o (N i : m i < n : Ei ) donde m, n Z, con m < n. Ejemplo 4.3.2 Supongamos que se desea expresar que k es el ms peque o de los nmeros naturales tales que Ek = T . a n u Se puede expresar de la siguiente forma, haciendo uso del cuanticador universal: ({i, k} N ) (i : 0 i < k : Ei ) Ek

4.3. Cuanticadores

51

pero tambin lo podemos hacer considerando el cuanticador e numrico en la forma e ({i, k} N ) ((N i : 0 i < k : Ei ) = 0) Ek Con esta ultima expresin se indica que el nmero de valores o u que cumplen Ei es 0 en el rango que va de 0 a k 1 y que Ek se cumple. 2 Ejemplo 4.3.3 Supongamos que deseamos expresar el hecho de que k es el segundo nmero natural ms peque o tal que u a n Ek = T . Utilizando el cuanticador universal, el predicado resultante sera: ({i, j, k} N ) (i : 0 i < j : Ei ) Ej (i : j + 1 i < k : Ei ) Ek Mediante el uso del cuanticador numrico el predicado e resultante es ms reducido y comprensible: a ({i, k} N ) ((N i : 0 i < k : Ei ) = 1) Ek ya que se expresa explcitamente que hay un solo nmero i u tal que Ei se cumple en el rango [0, k), y que Ek se verica igualmente. 2 En este momento es importante se alar que, como han mostrado n los ejemplos 4.3.2 y 4.3.3, el cuanticador numrico no es e ms que una facilidad notacional para abreviar situaciones que a se pueden perfectamente expresar mediante los cuanticadores universal y existencial. 4.3.4 Equivalencias entre cuanticadores

Los distintos cuanticadores se encuentran relacionados unos con otros. De entre todas estas relaciones, una de las ms a importantes es la equivalencia de cuanticadores que se establece en la siguiente discusin: o

52

Clculo de Predicados a

Lema 4.3.1 Sean m, n Z. Entonces se cumple que: (i : m i < n : Ei ) = (i : m i < n : Ei ) Demostracin: o Bastar aplicar las deniciones de los cuanticadores y las leyes a de equivalencia. As tenemos que: , (i : m i < n : Ei ) = Em Em+1 . . . En1 = (Em Em+1 . . . En1 ) (N egacin) o = (Em Em+1 . . . En1 ) (De M organ) = (i : m i < n : Ei ) 2 En relacin al cuanticador numrico, este se encuentra o e estrechamente ligado a los cuanticadores existencial y universal, tal y como se hab apuntado con anterioridad en los a ejemplos 4.3.2 y 4.3.3. En realidad, estos dos ultimos pueden ser sustituidos por el cuanticador numrico, ya que se verican e las siguientes igualdades: (i : m i < n : Ei ) = ((N i : m i < n : Ei ) 1) (i : m i < n : Ei ) = ((N i : m i < n : Ei ) = n m) Por otro lado, las expresiones que incluyen cuanticadores pueden ser simplicadas con frecuencia, cuando estos son del mismo tipo. Este es el caso de los rangos consecutivos, tal y como se muestra a continuacin: o (i : m i < n : Ei ) (i : n i < p : Ei ) = (i : m i < p : Ei ) (i : m i < n : Ei ) (i : n i < p : Ei ) = (i : m i < p : Ei ) (N i : m i < n : Ei ) + (N i : n i < p : Ei ) = (N i : m i < p : Ei )

4.3. Cuanticadores

53

4.3.5

Cuanticacin sobre rangos innitos o

Hasta ahora se han considerado unicamente rangos nitos en los cuanticadores, lo que limita la expresividad de los predicados. Se trata, por tanto, de introducir el concepto de rango innito, teniendo en cuenta que tales predicados no pueden, en ocasiones, ser calculados mediante programas reales en un tiempo nito. Como primer paso, se generalizan los cuanticadores existencial y universal en la forma: (i : R : E) (i : R : E) donde i es un identicador, y R y E son predicados. Declarativamente leer amos, respectivamente: Existe un i que verica R tal que E es T . Para todo i que verica R, E es T . Al predicado R se le denomina el rango del cuanticador. Ejemplo 4.3.4 Dados los siguientes conceptos atmicos y o predicados asociados: Conceptos atmicos o p es hombre x es mortal Predicados hombre(p) mortal(x)

entonces, el enunciado todo hombre es mortal puede expresarse mediante el predicado (p : hombre(p) : mortal(p)) 2 Ejemplo 4.3.5 Podemos establecer que el mximo de un a nmero real y su opuesto es el valor absoluto de ese nmero u u real, en la forma: (n : real(n) : abs(n) = max(n, n)) donde real(n) es cierto si n es un nmero real. 2 u

54

Clculo de Predicados a

En general, el tipo del identicador cuanticado viene dado expl citamente por su rango, como en el caso del ejemplo anterior con real(n). Sin embargo, en los casos en que dicho test es obvio, se suele omitir. As la expresin del ejemplo anterior se podr , o a escribir: (n : abs(n) = max(n, n)) Continuando con el mismo ejemplo, resulta evidente que abs(n) = max(n, n) para cualquier real n. Esto signica que nos encontramos ante una tautolog puesto que es T en cualquier estado en el que a, est bien denida. Esto es lo que se expresa con e (n : real(n) : abs(n) = max(n, n)) En general, una tautolog E(i1 , i2 , . . . , in ), donde los ij a son los identicadores contenidos en E, puede considerarse como una abreviatura de un predicado en el cual todos los identicadores se encuentren cuanticados universalmente. Ms a concretamente: E = (i1 , i2 , . . . , in : E)

4.4

Identicadores libres y ligados

En el clculo de predicados, hay dos clases diferentes de a identicadores que se distinguen por su visibilidad: Los identicadores libres son aquellos cuyo ambito abarca todos los predicados. Los identicadores ligados o acotados son aquellos cuyo valor slo es visible dentro de la parte acotada por un o cuanticador. Para aclarar ms los conceptos, tomamos como ejemplo el a predicado: (i : m i < n : x + i = 0)

4.4. Identicadores libres y ligados

55

En este caso, el identicador i est acotado por el cuanticador a universal y slo sirve para indicar elementos individuales dentro o de su rango, por lo que su utilizacin fuera del ambito del o cuanticador no tiene sentido. Podr decirse que i slo est a o a denido en el contexto local del cuanticador. En cambio, x es un identicador libre cuyo valor forma parte del contexto global y puede ser utilizado sin problemas en cualquier otro predicado. A continuacin se describe formalmente cundo un identicador o a es libre en una expresin: o 1. i es libre en la expresin i. o 2. i es libre en la expresin (E), si es libre en E. o 3. i es libre en op E, donde op es un operador unario, si es libre en E. 4. i es libre en E1 op E2 , donde op es un operador binario, si es libre en E1 o en E2 . 5. i es libre en (j : m j < n : E), (j : m j < n : E) y (N j : m j < n : E) si lo es en m, en n o en E, siempre que i = j. Igualmente, a continuacin se describe formalmente cundo un o a identicador est acotado en una expresin: a o 1. i est acotado en (E) si lo est en E. a a 2. i est acotado en op E, donde op es un operador unario, si a lo est en E. a 3. i est acotado en E1 op E2 si lo est en E1 o en E2 . a a 4. i est acotado en (i : m i < n : E), (i : m i < n : E) a y (N i : m i < n : E). En este caso, los predicados precedentes delimitan la visibilidad del identicador i. 5. i est acotado en (j : m j < n : E), (j : m j < n : a E) y (N j : m j < n : E) si lo est en m, n o E. a

56

Clculo de Predicados a

Con el objeto de evitar problemas en la identicacin de las o variables, se establece la regla de que un identicador no puede estar acotado simultneamente por dos cuanticadores. Esto a quiere decir que no se puede dar el siguiente caso: (i : m i < n : i 3 = 6) (i : s i < t : i > 0) ya que i est acotado tanto por el cuanticador universal como a por el existencial. Este caso se puede evitar reescribiendo la expresin anterior para obtener otra en la cual la variable o acotada por uno de los cuanticadores ha sido renombrada: (i : m i < n : i 3 = 6) (j : s j < t : j > 0) con lo cual podemos asegurar que nuestro convenio no supone en ning n momento una prdida de generalidad en la potencia u e expresiva de los predicados.

4.5

Sustitucin textual o

Una operacin fundamental en la transformacin de predicados o o es la sustitucin de un identicador por una expresin, o o o sustitucin textual. o Ello nos permitir particularizar una a tautolog adaptndola al problema concreto a tratar en cada a, a caso. Formalmente: Denicin 4.5.1 Sean E y e expresiones y x un identicador. o x Entonces, la notacin Ee representa la expresin obtenida al o o sustituir en E todas las ocurrencias libres de x por e. 2 Ejemplo 4.5.1 Se desea sustituir la variable x por la expresin o z en (x + y). El resultado es el siguiente: (x + y)x = (z + y) z 2 Como advertencia, debemos hacer notar que en general es aconsejable utilizar parntesis en la expresin que va a sustituir e o

4.5. Sustitucin textual o

57

al identicador, puesto que en ciertos casos su ausencia puede hacer que la expresin resultante agrupe operaciones de forma o no prevista ni deseada. Ejemplo 4.5.2 Se desea sustituir el identicador y en la expresin (x y) por la expresin a + b. Si no se utilizan o o parntesis rodeando a esta ultima expresin, el resultado sera: e o (x y)y = (x a + b) a+b La mayor prioridad del frente al + hace que la operacin del o producto se realice primero. Por el contrario, con parntesis se e obtendra: (x y)y (a+b) = (x (a + b)) En este caso, los parntesis salvaguardan el orden de las e operaciones a realizar, y con ello la semntica de la expresin. a o 2 Evidentemente, si no hay ninguna ocurrencia libre del identicador que va a ser reemplazado, la expresin resultante o ser igual a la original, pues tal y como qued establecido en la a o denicin 4.5.1, tan slo pueden ser reemplazadas ocurrencias o o libres de identicadores. Ejemplo 4.5.3 Sea E = x < y (i : 0 i < n : b[i] < y). i Entonces Ek = E, puesto que i no es libre en E. 2 Enlazando la presente discusin con la relativa al clculo de o a proposiciones, podr observarse que las sustituciones textuales a ya hab sido utilizadas previamente, aunque con otra notacin, an o cuando se hab introducido la regla de sustitucin. En efecto, si a o x E es una expresin en funcin de x, se cumple que Ez = E(z). o o En esta l nea, de la misma forma que en el caso de las proposiciones se pod aplicar la regla de sustitucin de forma a o consecutiva, en el caso que ahora nos ocupa se pueden encadenar m ltiples sustituciones textuales. Esto signica que se pueden u sustituir identicadores en una expresin resultado de una o sustitucin previa. Los parntesis identican el orden en que o e

58

Clculo de Predicados a

se realizan tales sustituciones: primero se sustituyen los niveles ms internos de parntesis. a e Ejemplo 4.5.4 Sea E la expresin x < y (i : 0 i < n : o b[i] < y). Entonces:
y E(wz) z (a+u)

= (x < (w z) (i : 0 i < n : b[i] < (w z)))z (a+u) 2 Una observacin importante es que al realizar sustituciones o debemos tener en cuenta que la expresin resultante sea o sintcticamente correcta. As con la expresin E del anterior a , o b ejemplo 4.5.4 no se podr hacer Ec+1 puesto que dar lugar a a a la aparicin de expresiones del tipo c + 1[i] que son incorrectas. o Un problema adicional que surge al aplicar sustituciones est a relacionado con los posibles conictos que puedan surgir con los identicadores acotados por cuanticadores. Como ilustracin, o supongamos que en el ejemplo anterior deseamos expresar que x y los elementos del vector b son menores que y i, donde i es un identicador libre. En principio, expresar amos la situacin o mediante:
y E(yi) = x < (y i) (i : 0 i < n : b[i] < (y i))

lo cual no se corresponde con la idea original. En denitiva, se debe de tener cuidado con que los identicadores que aparezcan en la expresin por la que se sustituye no estn ligados en la o e expresin original. Una forma sencilla de evitar este problema o consiste en renombrar los identicadores de forma automtica, a considerando unicamente las sustituciones a variables libres. x Todo ello nos lleva a matizar la denicin de la notacin Ee . o o
x Denicin 4.5.2 Ee denota el predicado creado por el o reemplazamiento de toda ocurrencia libre de la variable x en la expresin e. Adems, para ser vlida, debe ser sintcticamente o a a a correcta. Finalmente, si la sustitucin provocase la acotacin o o

4.6. Sustitucin simultnea o a

59

de alguna variable en e, los identicadores de las expresiones cuanticadas en E debern ser reemplazadas de forma a conveniente. 2 Ejemplo 4.5.5 Sea E la expresin x < y (i : 0 i < n : o b[i] < y). El resultado de sustituir en E el identicador y por y i es el siguiente:
y E(yi) = x < (y i) (k : 0 k < n : b[k] < (y i))

donde se ha cambiado el nombre del antiguo identicador ligado i por el de k, para evitar que el nuevo i estuviese ligado.2

4.6

Sustitucin simultnea o a

Sin embargo, el concepto de sustitucin textual no ser suciente o a para la continuacin de nuestro trabajo, por cuanto su accin o o se limita a una sola variable. Ello representa una seria barrera para la expresividad de lo que sern nuestros programas a lgicos, en los que la translacin de informacin entre sus o o o diferentes componentes probablemente exija la manipulacin o simultnea de un conjunto de sustituciones. Es por tanto a necesario introducir un concepto ms potente, el de sustitucin a o simultnea. a Denicin 4.6.1 Sean x = {xi , i = 1, . . . , n} y e = o {ei , i = 1, . . . , n} dos vectores de distintos identicadores x y de expresiones e, respectivamente. Ambos vectores tienen la x x ,x ,...,x misma longitud. Entonces denimos Ee , o Ee11,e22,...,enn , como la sustitucin simultnea de todas las ocurrencias libres de xi o a por su correspondiente ei en la expresin E. 2 o Ejemplo 4.6.1 A continuacin se muestran varios ejemplos de o sustituciones simultneas: a (x + x + y)x,y = a + b + a + b + c a+b,c (x + x + y)x,y = x + y + x + y + z x+y,z

60

Clculo de Predicados a

(i : 0 i < n : b(i) c(i + 1))n,b n+i,d = (k : 0 k < n + i : d(k) c(k + 1)) 2 Debemos observar que, en general, una sustitucin o simultnea no es quivalente a la realizacin de sucesivas a o x,y x sustituciones simples, esto es, Eu,v no es quivalente a (Eu )y . v Por ejemplo: (x + x + y)x,y = x + y + x + y + z x+y,z mientras que (x + x + y)x x+y
y z

= (x + y + x + y + y)y = x + z + x + z + z z

Cap tulo 5

Prolog y Clculo de a Predicados


En este cap tulo se aborda la relacin existente entre el clculo o a de predicados y el lenguaje de programacin Prolog, aplicando o la teor explicada en los cap a tulos anteriores. Ms exactamente, a construiremos un demostrador de teoremas cuyo funcionamiento se corresponder casi exactamente con el presentado por el a lenguaje citado. A la vez, aprovecharemos dicho proceso para introducir la terminolog propia de Prolog, as como sus a conceptos bsicos. a

5.1

Regla de resolucin o

Recordemos ahora la regla de resolucin del clculo de o a proposiciones: (a b) (a c) bc Veamos el modo en que se puede aplicar dicha regla al clculo a de predicados. Para ello ser suciente, en general, con tener en a cuenta las siguientes reglas de inferencia: Regla de particularizacin: o
61

( i : R : Ei ) Ei

(5.1)

62

Prolog y Clculo de Predicados a

Regla de generalizacin: o

E1 , E2 , . . . , En E1 E 2 . . . E n

(5.2)

La primera de ellas recibe el nombre de regla de sustitucin en o numerosos textos, no as en el presente en el que se ha reservado esa denominacin para una regla fundamental del clculo de o a proposiciones. Debemos observar, sin embargo, que la regla de resolucin, tal y como ha sido enunciada, no permite su o aplicacin a casos como el dado por las expresiones: o ( X, Z : a(X) b(Z)) y ( W, Y : a(W ) c(Y )) puesto que no se trata de proposiciones, sino claramente de predicados. Sin embargo, dicha aplicacin es posible si antes o hemos considerado la adecuada aplicacin de la ecuacin 5.1, o o 1 dada en este caso por la sustitucin que asigna W a X, y que o notaremos: {X W } con lo que a(X) b(Z) a(W ) b(Z) de donde tendremos que tanto a(W ) b(Z) como a(W ) c(Y ) son tautolog En este caso, diremos que los trminos a(X) y as. e a(W ) unican mediante la sustitucin . Veamos ahora cmo o o podemos aplicar la regla de resolucin. Teniendo en cuenta que o el conjunto de valores posibles para las variables Y , Z y W es
trmino sustitucin constituye aqu un abuso del lenguaje, puesto que realmente e o se trata de un simple renombramiento de variables.
1 el

5.2. El proceso de resolucin o

63

en la prctica nito2 , podemos aplicar a cada triple de posibles a valores la ecuacin 5.2 y tendremos que o a(W ) b(Z), a(W ) c(Y ) (a(W ) b(Z)) (a(W ) c(Y )) y por tanto ( W, Z : a(W ) b(Z)), ( W, Y : a(W ) c(Y )) ( W, Z : a(W ) b(Z)) ( W, Y : a(W ) c(Y )) lo cual, teniendo en cuenta la concatenacin de rangos en los o cuanticadores, es lo mismo que escribir ( W, Z : a(W ) b(Z)), ( W, Y : a(W ) c(Y )) ( W, Y, Z : a(W ) b(Z), a(W ) c(Y )) Ahora s podemos aplicar la regla de resolucin en el interior o del cuanticador para cada valor de W , Y y Z, con lo que tendremos: ( W, Y, Z : a(W ) b(Z)), ( W, Y : a(W ) c(Y )) ( Y, Z : b(Z) c(Y )) que notacionalmente es lo mismo que escribir a(W ) b(Z), a(W ) c(Y ) b(Z) c(Y ) con lo que resumiendo el proceso aplicado, tendremos que: a(X) b(Z), a(W ) c(Y ) b(Z) c(Y ) lo que signica que hemos extendido la aplicacin de la regla de o resolucin de las proposiciones al caso de los predicados. o

5.2

El proceso de resolucin o

Con el objeto de no sobrecargar al lector con ms deniciones a formales, utilizaremos un sencillo ejemplo para ilustrar y guiar la discusin en cada caso. o
hay que olvidar que en la prctica los recursos de un ordenador son nitos, y por a tanto el rango tambin. e
2 no

64

Prolog y Clculo de Predicados a

5.2.1

Un ejemplo simple

En primer lugar consideraremos las dos expresiones: hombre( Adan ) T mortal(P ersona) hombre(P ersona) que denominaremos clusulas y que constituirn nuestro a a programa lgico o lo que es lo mismo, la base de datos que o representa nuestro conocimiento del mundo. En cuanto al signicado declarativo del programa, podemos entender estas dos clusulas en la forma: a Adn es un hombre. a Todo hombre es mortal. En un futuro, utilizaremos la notacin o hombre( Adan ). mortal(Persona) : hombre(Persona). para abreviar y facilitar el manejo de las expresiones. De hecho, esta ser la representacin Prolog del programa considerado, a o donde los s mbolos T a la derecha de las implicaciones son obviados y donde adems el s a mbolo de la implicacin o lgica ha sido cambiado por :-. Tambin consideraremos el o e predicado dado por la expresin: o F mortal(Individuo) que representaremos en forma abreviada como : mortal(Individuo). y que constituye la pregunta que el usuario realiza al programa. Ms exactamente, el signicado declarativo de esta pregunta a ser a: Existe algn individuo mortal ? u

5.2. El proceso de resolucin o

65

Formalmente la inclusin de esta ultima clusula en nuestra base o a de datos signica que estamos suponiendo que ( Individuo : mortal(Individuo)) = T o lo que es lo mismo, estamos suponiendo que no existe ning n u valor de Individuo para el que mortal(Individuo) = T Esto implica que nuestra estrategia de demostracin es por o reduccin al absurdo. Ms exactamente, se trata de demostrar o a que ( Individuo : mortal(Individuo)) = F con lo que ( Individuo : mortal(Individuo)) = T lo cual se corresponde con el signicado declarativo que hab amos dado a nuestra pregunta. Podemos considerar ahora el conjunto de clusulas en juego, junto con su interpretacin en a o lgica de predicados: o 1. hombre(Adan). T : hombre( Adan ) 2. mortal(Persona) :- hombre(Persona). ( P ersona : T : mortal(P ersona) hombre(P ersona)) = ( P ersona : mortal(P ersona) hombre(P ersona)) 3. :- mortal(Individuo). ( Individuo : T : mortal(Individuo)) = ( Individuo : mortal(Individuo)) = ( Individuo : mortal(Individuo)) donde la primera clusula recibe el nombre de hecho por cuanto a expresa una verdad sin condiciones. A partir de aqu podemos realmente comenzar el proceso , de resolucin, o lo que es lo mismo, el proceso de o

66

Prolog y Clculo de Predicados a

demostracin de nuestro candidato a teorema3 . As el trmino o , e mortal(Individuo) de la pregunta :- mortal(Individuo). unica con la cabeza de la clusula4 a mortal(Persona) :- hombre(Persona). mediante la sustitucin o 1 {Individuo Persona} Aplicando ahora la regla de resolucin obtendremos o mortal(P ersona), mortal(P ersona) hombre(P ersona) hombre(P ersona) a cuya conclusin podemos aplicarle de nuevo el mismo o razonamiento, unicando de nuevo con la cabeza de la primera clusula mediante la sustitucin a o 2 {Persona Adan} Ahora, aplicando la regla de resolucin de forma anloga al caso o a 5 de las proposiciones , obtenemos hombre( Adan ), hombre( Adan ) F lo cual es una inconsistencia lgica, puesto que F es un valor o que nunca puede ser cierto. Ello representa un absurdo, que es consecuencia directa de haber supuesto que ( Individuo : mortal(Individuo)) = T por tanto, podemos concluir que ( Individuo : mortal(Individuo)) = T
que a su vez equivale a encontrar una respuesta vlida para la pregunta inicial. a es, la parte izquierda de la clusula. a 5 ya no hay variables sin instanciar en los trminos. e
4 esto 3 lo

5.2. El proceso de resolucin o

67

y este Individuo viene dado por la sustitucin o Individuo Persona Adan lo que constituye la respuesta6 a nuestra pregunta, tal como pretend amos. El proceso comentado suele representarse abreviadamente en forma arborescente, en lo que habitualmente se denomina arbol de resolucin. En l se indican las sustituciones utilizadas en o e las unicaciones que nos han conducido a la obtencin de la o respuesta nal, as como el conjunto de expresiones a las que han sido aplicadas. En este contexto, cada una de las expresiones que constituyen los nodos del arbol se denominan objetivos y desde un punto de vista intuitivo representan el conjunto de cuestiones en las que hemos descompuesto el problema representado por la pregunta inicial para su resolucin. Cuando no queda ning n o u objetivo por resolver es que hemos conseguido demostrar nuestro teorema, o lo que es lo mismo responder a la pregunta inicial. En nuestro caso, el arbol de resolucin es el representado en la o gura 5.1. A cada nodo del arbol de resolucin se le denomina o resolvente y representa el conjunto de objetivos a resolver en el momento de la construccin de dicho nodo. o {mortal(Individuo)} | 1 {hombre(P ersona)} | 2 {}
Figura 5.1: Resolucin de :- mortal(Individuo). o

veces tambin se le denomina contraejemplo, puesto que efectivamente constituye e un contraejemplo a nuestra falsa suposicin inicial. o

6a

68

Prolog y Clculo de Predicados a

5.2.2

Un ejemplo completo

Una vez introducida, al menos informalmente, la tcnica de e resolucin que representa el motor de Prolog, el siguiente paso o consistir en mostrar un ejemplo ms completo. El problema a a elegido es el de la denicin del tipo lista, tal y como se o considera en los lenguajes clsicos de programacin. En este a o caso, consideraremos que una lista puede representarse de dos formas distintas: Mediante la simple explicitacin de todos sus elementos o separados por comas y encerrados entre corchetes. As por , ejemplo la lista cuyos elementos son 1 y 2 se representar a en la forma [1, 2] Mediante la diferenciacin entre los primeros elementos de o la lista y el resto de los elementos. En este caso la lista [1, 2] tambin se representar en la forma e a [1 | [2]] o tambin e [1, 2 | [ ]] donde | es el operador que separa los n primeros elementos de la lista, del resto. Ejemplo 5.2.1 La denicin del tipo lista en programacin o o lgica se corresponde con las dos clusulas que siguen: o a lista([ ]). lista ([Car|Cdr]) :- lista(Cdr). que declarativamente pueden ser ledas en la forma: La lista vac es una lista. a Una estructura cuyos elementos estn expresados a entre corchetes es una lista si contiene un primer elemento Car y lo que queda dene tambin una lista. e

5.2. El proceso de resolucin o

69

Si ahora interrogamos al programa con la pregunta :- lista([1,2]). formalmente estamos armando que lista([1, 2]) = T Veremos que esta suposicin nos lleva a un absurdo, con lo que o podremos concluir que lista([1, 2]) = T El proceso de resolucin sera el siguiente: o 1. El objetivo lista([1, 2]) unica con la cabeza de la segunda clusula mediante la sustitucin a o 1 {Car1 1, Cdr1 [2]} 2. Aplicando ahora la regla de resolucin, obtendremos o lista([1, 2]), lista([1 | [2]]) lista([2]) lista([2]) 3. De nuevo, unicaremos el objetivo lista([2]) con la cabeza de la segunda clusula mediante la sustitucin a o 2 {Car2 2, Cdr2 [ ]} con lo que podemos aplicar de nuevo la regla de resolucin: o lista([2]), lista([2 | [ ]) lista([ ]) lista([ ]) 4. Ahora unicamos con la primera clusula y aplicando de a nuevo la regla de resolucin, tendremos o lista([ ]), lista([ ]) F

70

Prolog y Clculo de Predicados a

con lo que hemos llegado a una inconsistencia lgica, cuyo o origen no es otro que el de haber supuesto lista([1, 2]) = T por lo tanto tendremos que lista([1, 2]) = T siendo en este caso T la respuesta obtenida a nuestra pregunta. 2 El ejemplo siguiente muestra la complejidad del proceso de resolucin a la vez que la monoton de la tcnica aplicada en su o a e puesta en prctica. Ambos factores justican el inters de una a e implementacin informtica para el mismo. o a Ejemplo 5.2.2 El problema abordado ahora es el de la inversin, al primer nivel, de estructuras de tipo lista, tal como o han sido denidas con anterioridad. La idea es simple, dada una lista [1, 2] el resultado de la inversin ser o a [2, 1] En el caso de listas con ms de un nivel de profundidad, tales a como [1, [2, 3], 4] el efecto de la inversin slo se reejar en el primero de ellos, o o a de modo que obtendramos [4, [2, 3], 1] Un posible conjunto de clusulas capaz de implementar esta a funcionalidad viene dado por

5.2. El proceso de resolucin o

71

concatenar([], Lista, Lista). concatenar([Car|Cdr], Lista, [Car|Resultado]) :concatenar(Cdr, Lista, Resultado). invertir([ ], [ ]). invertir([Car|Cdr], Invertir) :invertir(Cdr, Invertir_Cdr), concatenar(Invertir_Cdr,[Car],Invertir).

donde el predicado concatenar representa la implementacin o del concepto de concatenacin de listas y el predicado invertir o el de la inversin propiamente dicha. o Ms exactamente a consideraremos que concatenar(Lista 1, Lista 2, Resultado) es cierto si Resultado es el resultado de concatenar las listas Lista 1 y Lista 2. De forma anloga, supondremos que a invertir(Lista, Invertir) es cierto si Invertir es el resultado de la inversin, al primer o nivel, de la lista Lista. Declarativamente, el signicado de nuestro programa sera el siguiente, interpretando clusula a a clusula: a Si concatenamos la lista vac con otra lista, esta a ultima es el resultado. El resultado de concatenar una lista, cuyo primer elemento viene dado por Car y el resto de los elementos por Cdr, con otra lista Lista es igual a concatenar Cdr con Lista y al resultado as obtenido anteponerle Car. El resultado de invertir la lista vac es ella misma. a El resultado de invertir una lista de primer elemento Car es igual a invertir el resto de sus elementos Cdr, y al resultado as obtenido concatenarle la lista formada por el primer elemento Car de la lista original.

72

Prolog y Clculo de Predicados a

Supongamos ahora que planteamos la pregunta :- invertir([1,2], Invertir). Esto es, estamos interrogando al programa sobre el resultado del proceso de inversin de la lista [1, 2]. Primero comenzaremos o por traducir el conjunto de clusulas a su expresin exacta como a o predicados. As, tenemos que:
invertir([ ],[ ]). = T invertir([Car|Cdr],Invertir) :invertir(Cdr, Invertir Cdr), concatenar(Invertir Cdr, [Car], Invertir). = (Car, Cdr, Invertir, Invertir Cdr : invertir(Cdr, Invertir Cdr) concatenar(Invertir Cdr, [Car], Invertir) invertir([Car | Cdr], Invertir)) :- invertir([1,2],Invertir). = (Invertir : invertir([1, 2], Invertir)) = (Invertir : invertir([1, 2], Invertir))

De forma totalmente anloga podramos traducir las clusulas a a del predicado concatenar. Se trata pues de demostrar que (Invertir : invertir([1, 2], Invertir)) = F lo que es equivalente a probar que (Invertir : invertir([1, 2], Invertir)) = T Si consideramos la sustitucin7 o 1 { Car 1, Cdr [2], Invertir Invertir1 , Invertir Cdr Invertir Cdr1 } y aplicndola sobre la segunda clusula, tendremos que por a a aplicacin de la regla de particularizacin: o o
7 aqu Invertir Cdr es el resultado de renombrar el Invertir Cdr en la segunda 1 clusula del predicado invertir e Invertir1 es el resultado de renombrar el Invertir de a la pregunta.

5.2. El proceso de resolucin o

73

(Car, Cdr, Invertir, Invertir Cdr : invertir([Car | Cdr], Invertir) invertir(Cdr, Invertir Cdr) concatenar(Invertir Cdr, [Car], Invertir)) (Invertir1 , Invertir Cdr1 : invertir([1 | [2]], Invertir1 ) invertir([2], Invertir Cdr1 ) concatenar(Invertir Cdr1 , [1], Invertir1 ))

Ahora, aplicando la regla de generalizacin, obtenemos: o


(Invertir1 , Invertir Cdr1 : invertir([1 | [2]], Invertir1 ) invertir([2], Invertir Cdr1 ) concatenar(Invertir Cdr1 , [1], Invertir1 )), (Invertir1 : invertir([1 | [2]], Invertir1 )) (Invertir1 , Invertir Cdr1 : invertir([1 | [2]], Invertir1 ) invertir([2], Invertir Cdr1 ) concatenar(Invertir Cdr1 , [1], Invertir1 )) (Invertir1 : invertir([1 | [2]], Invertir1 ))

Concatenando los rangos de los cuanticadores:


(Invertir1 , Invertir Cdr1 : invertir([1 | [2]], Invertir1 ) invertir([2], Invertir Cdr1 ) concatenar(Invertir Cdr1 , [1], Invertir1 ) invertir([1 | [2]], Invertir1 ))

y aplicando la regla de resolucin a nivel de los predicados o simples, tendremos que nalmente
(Invertir1 , Invertir Cdr1 : invertir([1 | [2]], Invertir1 ) invertir([2], Invertir Cdr1 ) concatenar(Invertir Cdr1 , [1], Invertir1 )), (Invertir1 : invertir([1 | [2]], Invertir1 )) (Invertir1 , Invertir Cdr1 : (invertir([2], Invertir Cdr1 ) concatenar(Invertir Cdr1 , [1], Invertir1 )))

74

Prolog y Clculo de Predicados a

Esto es, la nueva resolvente es:


(Invertir1 , Invertir Cdr1 : invertir([2], Invertir Cdr1 ) concatenar(Invertir Cdr1 , [1], Invertir1 ))

donde, considerando la sustitucin8 o 2 { Car 2, Cdr [ ], Invertir Invertir Cdr1 , Invertir Cdr Invertir Cdr2 } y aplicndola a la segunda clusula, tendremos que por a a aplicacin de la regla de particularizacin o o
(Car, Cdr, Invertir, Invertir Cdr : invertir([Car | Cdr], Invertir) invertir(Cdr, Invertir Cdr) concatenar(Invertir Cdr, [Car], Invertir)) 2 (Invertir Cdr1 , Invertir Cdr2 : invertir([2 | [ ]], Invertir Cdr1 ) invertir([ ], Invertir Cdr2 ) concatenar(Invertir Cdr2 , [2], Invertir Cdr1 ))

Aplicando de nuevo la regla de particularizacin tendremos que: o


(Invertir Cdr1 , Invertir Cdr2 : invertir([2 | [ ]], Invertir Cdr1 ) invertir([ ], Invertir Cdr2 ) concatenar(Invertir Cdr2 , [2], Invertir Cdr1 )), (Invertir1 , Invertir Cdr1 : (invertir([2 | [ ]], Invertir Cdr1 ) concatenar(Invertir Cdr1 , [1], Invertir1 ))) (Invertir Cdr1 , Invertir1 , Invertir Cdr2 : (invertir([ ], Invertir Cdr2 ) concatenar(Invertir Cdr2 , [2], Invertir Cdr1 )) concatenar(Invertir Cdr1 , [1], Invertir1 ))

Invertir Cdr2 es el resultado de renombrar el Invertir Cdr en la segunda clusula del predicado invertir. a

8 aqu

5.2. El proceso de resolucin o

75

Lo que es equivalente a
(Invertir Cdr1 , Invertir1 , Invertir Cdr2 : invertir([ ], Invertir Cdr2 ) concatenar(Invertir Cdr2 , [2], Invertir Cdr1 ) concatenar(Invertir Cdr1 , [1], Invertir1 ))

que es la nueva resolvente. Si aplicamos ahora a la conclusin o obtenida la sustitucin o 3 {Invertir Cdr2 [ ]} y aplicando la regla de particularizacin tendremos que o
(Invertir Cdr1 , Invertir1 , Invertir Cdr2 : invertir([ ], Invertir Cdr2 ) concatenar(Invertir Cdr2 , [2], Invertir Cdr1 ) concatenar(Invertir Cdr1 , [1], Invertir1 )) 3 (Invertir Cdr1 , Invertir1 : invertir([ ], [ ]) concatenar([ ], [2], Invertir Cdr1 ) concatenar(Invertir Cdr1 , [1], Invertir1 ))

Al considerar la aplicacin de la regla de generalizacin a o o dicha conclusin en la primera clusula del predicado invertir, o a tendremos:
(Invertir Cdr1 , Invertir1 : invertir([ ], [ ]) concatenar([ ], [2], Invertir Cdr1 ) concatenar(Invertir Cdr1 , [1], Invertir1 )), invertir([ ], [ ]) (Invertir Cdr1 , Invertir1 : invertir([ ], [ ]) concatenar([ ], [2], Invertir Cdr1 ) concatenar(Invertir Cdr1 , [1], Invertir1 )) invertir([ ], [ ])

y al concatenar dominios
(Invertir Cdr1 , Invertir1 : (invertir([ ], [ ]) concatenar([ ], [2], Invertir Cdr1 ) concatenar(Invertir Cdr1 , [1], Invertir1 )) invertir([ ], [ ]))

76

Prolog y Clculo de Predicados a

Teniendo ahora en cuenta la regla de resolucin en el interior o del cuanticador universal, tendremos que nalmente:
(Invertir Cdr1 , Invertir1 , Invertir Cdr2 : invertir([ ], Invertir Cdr2 ) concatenar(Invertir Cdr2 , [2], Invertir Cdr1 ) concatenar(Invertir Cdr1 , [1], Invertir1 )) (Invertir Cdr1 , Invertir1 : concatenar([ ], [2], Invertir Cdr1 ) concatenar(Invertir Cdr1 , [1], Invertir1 ))

El proceso contina ahora de forma similar para concatenar, u siendo los valores obtenidos para las variables en juego Invertir Cdr1 [2] y Invertir1 [2, 1] con lo que nuestra respuesta nal ser a Invertir [2, 1] Evidentemente podemos generar el arbol de resolucin o correspondiente, que es el indicado en la gura 5.2, donde = {Invertir Cdr1 [2], Invertir1 [2, 1]} 2

5.2. El proceso de resolucin o

77

{invertir([1, 2], Invertir1 } | 1 { invertir([2], Invertir Cdr1 ); concatenar(Invertir Cdr1 , [1], Invertir1 )} | 2 { invertir([ ], Invertir Cdr1 ); concatenar(Invertir Cdr2 , [2], Invertir Cdr1 ); concatenar(Invertir Cdr1 , [1], Invertir1 )} | 3 { concatenar([ ], [2], Invertir Cdr1 ); concatenar(Invertir Cdr1 , [1], Invertir1 )} | . . . | {}

Figura 5.2: Resolucin de :- invertir([1,2], Invertir). o

78

Prolog y Clculo de Predicados a

Parte III

El Intrprete Lgico e o

79

Cap tulo 6

Conceptos Fundamentales
6.1 Objetos en programacin lgica o o

La clase ms general de objeto manejado en programacin lgica a o o es el trmino. La jerarqu de datos a partir de dicha estructura e a viene indicada por el siguiente diagrama:

Variable

N mero u

Simple

Trmino e

a Constante Carcter

Cadena de caracteres

Compuesto

Las variables suelen indicarse mediante un identicador cuyo primer carcter es una letra may scula. a u Los trminos e compuestos son los objetos estructurados del lenguaje. Se componen de un funtor1 y una secuencia de uno o ms a trminos llamados argumentos. Un funtor se caracteriza por e su nombre, que es un atomo, y su aridad o n mero de u argumentos. Grcamente, el objeto puede representarse en a
1 llamado

el funtor principal del trmino. e

81

82

Conceptos Fundamentales

este caso mediante un arbol en el que la ra est etiquetada con z a el nombre del funtor y los hijos con los argumentos del mismo. Cuando el trmino compuesto no expresa ning n tipo de relacin e u o lgica2 , suele drsele el nombre de funcin. Una constante lgica o a o o es una funcin de aridad cero. o Ejemplo 6.1.1 Podemos considerar el caso de un objeto estructurado fecha con tres argumentos: A~o, Mes y Da. Su n representacin ser la siguiente: o a fecha(A o, Mes, Da) n En este caso, el funtor puede caracterizarse usando la notacin o fecha/3 en referencia a su nombre y a la aridad considerada. Dicha representacin se suele conocer como la rma del funtor. o La representacin en forma de arbol sera la indicada en la o gura 6.1. 2

fecha

Ano

Mes

Dia

Figura 6.1: Representacin arborescente del trmino fecha(Ao, Mes, Da). o e n

Intuitivamente, el lector puede pensar en los trminos e compuestos de la programacin lgica como si de un tipo registro o o en los lenguajes clsicos de programacin se tratara. De hecho, el a o principio es el mismo con la salvedad de que aqu la recuperacin o y asignacin de lo que ser los campos del registro no se realiza o an mediante funciones de acceso, sino utilizando el concepto de unicacin que introduciremos ms adelante. o a
2 ello

depender tan solo del contexto expresado por el programa lgico. a o

6.2. Programas lgicos, clusulas y preguntas o a

83

6.2

Programas lgicos, clusulas y preguntas o a

La unidad fundamental de un programa lgico es el atomo, el o cual es un tipo especial de trmino compuesto, distinguido slo e o por el contexto en el cual aparece en el programa3 . Su estructura es en principio la misma que la de un trmino compuesto, pero e en este caso el funtor principal recibe el nombre de predicado. Su equivalente en la programacin clsica ser el de una llamada o a a a un proceso. A partir del concepto de atomo, denimos el de literal, que no es otra cosa que un atomo o su negacin. o En este punto, podemos ya denir la nocin de clusula como o a un conjunto de literales ligados por conectores y cuanticadores lgicos. En nuestro caso, nos limitaremos a un tipo especial de o clusulas denominadas de Horn. Una clusula de Horn es una a a estructura compuesta por una cabeza y un cuerpo. La cabeza consiste o bien de un simple atomo, o bien est vac El cuerpo a a. est formado por una secuencia de cero o ms atomos. Cuando a a la cabeza est vac se dice que la clusula es una pregunta. La a a a cabeza y el cuerpo de una misma clusula estn separados por a a un s mbolo de implicacin lgica cuya representacin notacional o o o puede variar seg n el autor considerado. En cuanto a los atomos u del cuerpo, estos se separan por operadores lgicos conjuntivos4 , o soliendo indicarse el nal del cuerpo mediante un punto. Esto es, en general representaremos una clusula en la forma : a P : Q 1 , Q2 , . . . , Qn . que podemos leer bien declarativamente: P es cierto si Q1 es cierto, Q2 es cierto, ..., y Qn es cierto. bien operacionalmente: Para satisfacer P , es necesario satisfacer los atomos Q1 , Q2 , ..., y Qn .
3 esto 4y

es, expresa una relacin lgica. o o en determinados casos disyuntivos.

84

Conceptos Fundamentales

En este contexto, un programa lgico se dene simplemente como o una secuencia de clusulas. a Ejemplo 6.2.1 El siguiente programa dene recursivamente el conjunto de los nmeros naturales: u
numero_natural(0). numero_natural(siguiente(Numero)) :- numero_natural(Numero).

Se puede observar que hemos utilizado una funcin, de nombre o siguiente, que no expresa ningn tipo de relacin lgica. De u o o hecho su utilidad es meramente notacional, en contra de lo que ocurre con el predicado numero natural. Adems el argumento a de la regla recursiva es una variable, puesto que se trata de una regla que debe expresar de forma general la naturaleza de un nmero natural. Declarativamente, podemos leer ambas u clusulas en la forma: a El cero es un n mero natural. u El n mero siguiente(Numero) es natural, si Numero u tambin lo es. e Evidentemente, la notacin considerada en este caso para los o nmeros naturales no es la habitual, sino la dada por la tabla 6.1. u 2 Natural 0 1 2 . . . n Notacin o 0 siguiente(0) siguiente(siguiente(0)) . . . siguiente(. n . (siguiente(0)) . . .) .

Tabla 6.1: Notacin para la representacin de los nmeros naturales. o o u

6.3. Concepto de unicacin: sustituciones e instancias o

85

6.3

Concepto de unicacin: sustituciones e o instancias

Dos conceptos, sustitucin e instanciacin son, junto con el de o o resolucin, nociones bsicas del motor de un intrprete lgico o a e o y determinan inequ vocamente el estilo de programacin propio o de los lenguajes de este tipo. Denicin 6.3.1 Una sustitucin es una lista de pares o o (variable, trmino). Utilizaremos la notacin e o {X1 T1 , . . . , Xn Tn } para representar la sustitucin que asocia las variables X i a o los trminos e Ti , i {1, 2, . . . , n} La aplicacin de una sustitucin a un trmino lgico T ser o o e o a denotada T y se dir que es una instancia del trmino T . 2 a e Ahora podemos considerar una denicin formal recursiva o de la semntica declarativa de las clusulas, que sirve para a a indicarnos aquellos objetivos que pueden ser considerados ciertos en relacin a un programa lgico: o o Un objetivo es cierto si es una instancia de la cabeza de alguna de las clusulas del programa lgico a o considerado y cada uno de los objetivos que forman el cuerpo de la clusula instanciada son a su vez ciertos. a En este punto, es importante advertir que la semntica a declarativa no hace referencia al orden expl cito de los objetivos dentro del cuerpo de una clusula, ni al orden de las clusulas a a dentro de lo que ser el programa lgico. Este orden es, sin a o embargo, fundamental para la semntica operacional de Prolog. a Ello es la causa fundamental de las divergencias entre ambas semnticas en dicho lenguaje y fuente de numerosos errores de a programacin, que adems no siempre son fciles de detectar. o a a

86

Conceptos Fundamentales

Las sustituciones son utilizadas en programacin lgica o o para, mediante su aplicacin a las variables contenidas en una o clusula, obtener la expresin de la veracidad de una relacin a o o lgica particular a partir de la veracidad de una relacin lgica o o o ms general incluida en el programa. Ms formalmente, dicho a a concepto se conoce con el nombre de unicacin, que pasamos o a denir inmediatamente. Denicin 6.3.2 Un unicador de dos trminos lgicos T1 y o e o T2 es una sustitucin , tal que T1 = T2 . Cuando al menos o existe un unicador para dos trminos lgicos T1 y T2 , existe un e o unicador particular llamado el unicador ms general (mgu)5 a de T1 y T2 , tal que para cualquier otro unicador , existe una sustitucin tal que = . 2 o Intuitivamente, el mgu(T1 , T2 ) representa el n mero m u nimo de restricciones a considerar sobre dos trminos para hacerlos e iguales. Ejemplo 6.3.1 Dados los trminos lgicos: e o T1 = p(A, 3, f (Y )) T2 = p(B, C, f (g(Z))) un conjunto de posibles unicadores es el siguiente: 1 {A 5, B 5, C 3, Y g(Z)} 2 {B A, C 3, Y g(0), Z 0} 3 {A B, C 3, Y g(Z)} donde el mgu(T1 , T2 ) es 3 . 2 Desde un punto de vista prctico, el mgu nos permitir a a efectuar nuestro razonamiento lgico conservando la mayor o generalidad posible en nuestras conclusiones. Es por ello que el mgu es el unicador utilizado en el proceso de demostracin o que constituye un intrprete lgico. Para su obtencin, la e o o mayor de los dialectos Prolog actuales consideran el algoritmo a de Robinson [22], que pasamos a describir inmediatamente.
5 de

most general unicator.

6.3. Concepto de unicacin: sustituciones e instancias o

87

Algoritmo 6.3.1 El siguiente seudocdigo describe el mtodo o e de unicacin de Robinson. o Entrada: Dos trminos lgicos T1 y T2 . e o Salida: El mgu(T1 , T2 ), si existe; en otro caso fail. Algoritmo: inicio := ; push (T1 = T2 , Pila) ; mientras Pila = hacer (X = Y ) := pop(Pila) ; caso XY : sustituir (X, Y ); a~adir (, X Y ) n Y X : sustituir (Y, X); a~adir (, Y X) n (X Y ) : nada (X f (X1 , . . . , Xn )) y (Y f (Y1 , . . . , Yn )) : para i := n hasta 1 paso -1 hacer push(Xi = Yi , Pila) n para sino : devolver fail n caso n mientras ; devolver n donde la funcin push(T1 = T2 , Pila) introduce la ecuacin o o lgica T1 = T2 y la funcin pop(Pila) extrae la ecuacin o o o lgica X = Y de la estrucura LIFO6 Pila. La funcin o o sustituir(X, Y ) sustituye la variable X por Y en la pila y en la sustitucin . Finalmente, la funcin a~adir(, ) a ade al o o n n unicador la sustitucin . 2 o
6 Last

Input First Output.

88

Conceptos Fundamentales

Ejemplo 6.3.2 El siguiente ejemplo describe la unicacin de o los trminos: e T1 = f (X, g(X, h(Y ))) T2 = f (Z, g(Z, Z)) Como aplicacin directa del algoritmo 6.3.1 tenemos la siguiente o secuencia de conguraciones de la pila usada para la unicacin: o
{} | T1 = T 2 {} X=Z g(Z, Z) = g(X, h(Y )) {X Z} | g(Z, Z) = g(Z, h(Y )) Z=Z Z = h(Y ) | Z = h(Y ) |

{X Z} |

{X Z}

Esto es, el resultado nal es el dado por la sustitucin o {X Z h(Y ), Z h(Y )} 2 Un aspecto importante a se alar en relacin al algoritmo n o de unicacin es el com nmente llamado test de ciclicidad y o u que en el algoritmo 6.3.1 se representa mediante las expresiones X Y y Y X. En efecto, en la prctica y dado el elevado a costo que representar la aplicacin de este test, la mayor a o a de los intrpretes Prolog lo eliminan. Como consecuencia, el e programador puede incurrir en errores de dif localizacin, tal cil o y como demuestra el siguiente ejemplo. Ejemplo 6.3.3 Consideremos el siguiente programa lgico, que o implementa el concepto de igualdad entre dos trminos: e igual(X,X). cuya semntica declarativa viene dada por a Dos trminos son iguales si unican. e

6.4. Un intrprete lgico simple e o

89

Interrogamos ahora a nuestro programa con la pregunta :- igual(Y,f(Y)). Veremos que nuestro algoritmo de unicacin, sin test de o ciclicidad, entra en un ciclo sin n. En efecto, la secuencia de conguraciones en la pila que sirve de sustento al algoritmo, es la que sigue:
{} | igual(X, X) = igual(Y, f (Y )) {} X =Y X = f (Y ) | Y = f (Y ) {X Y }

Observemos que en la ultima de las conguraciones Y aparece en f(Y). Si continuamos con el proceso ocurrir a que sustituiremos toda ocurrencia de Y por f(Y), y como consecuencia obtendremos: X Y f (Y ) f (f (Y )) f (f (f (Y ))) f (f (f (f (Y )))) . . . Esto es, la unicacin ha entrado en un ciclo. 2 o

6.4

Un intrprete lgico simple e o

La mayor de los intrpretes Prolog actuales estn basados en a e a un mtodo de resolucin lgica denominado SLD7 [8] y que e o o pasamos a describir ahora. Algoritmo 6.4.1 El siguiente seudocdigo describe el mtodo o e de resolucin SLD. o Entrada: Un programa lgico P y una pregunta Q. o Salida: Q, si es una instancia de Q deducible a partir de P ; en otro caso fail.
Selecting a literal, using a Linear strategy and searching the space of possible deductions Depth-rst.
7 por

90

Conceptos Fundamentales

Algoritmo: inicio Resolvente := {Q} ; mientras Resolvente = hacer A Resolvente ; si P : Q1 , . . . , Qn tal que = mgu(A, P ) entonces borrar (Resolvente, A) ; a~adir (Resolvente, Q1 , . . . , Qn ) ; n aplicar (, Resolvente) sino devolver fail n si n mientras ; devolver n donde la funcin borrar(Resolvente, A) borra el objetivo A o de Resolvente, mientras que la funcin a~adir(Resolvente, o n Q1 , . . . , Q2 ) a ade los objetivos indicados a Resolvente. n La funcin aplicar(, Resolvente) aplica sobre el conjunto o de objetivos de Resolvente la restriccin representada por la o sustitucin . En general consideraremos que una resolvente o contiene en cada instante el conjunto de objetivos a resolver. 2 De hecho, existe un formalismo arborescente para representar las derivaciones efectuadas por nuestro algoritmo 6.4.1. En dicho arbol, la existencia de una rama cuya ultima hoja es la clusula vac se traduce en la existencia de una instancia que a a es consecuencia lgica del programa, esto es, de una respuesta. o En otro caso, no existe ninguna instancia que sea consecuencia lgica del programa. o El arbol en cuestin se denomina arbol de resolucin. En o o l, cada uno de los nodos representa el estado actual de la e resolvente, mientras que las ramas estn etiquetadas con los a valores de las sustituciones aplicadas en el algoritmo 6.4.1.

6.4. Un intrprete lgico simple e o

91

Denicin 6.4.1 Sean P un programa lgico y Q una pregunta o o para el mismo, entonces el arbol de resolucin para el programa o P , dada la pregunta Q, se construye en la forma siguiente: 1. La raz del arbol est constituida por la pregunta Q, que es a el primer valor de la resolvente. 2. Una vez seleccionado un atomo A en la resolvente, que llamaremos el objetivo a resolver, la construccin del arbol o en cada nodo contina como sigue: u (a) Si el atomo seleccionado A se puede unicar con la cabeza de cada una de las clusulas a P1 : Q1 , . . . , Qm1 . 1 1 P2 : Q1 , . . . , Qm2 . 2 2 . . . Pn : Q1 , . . . , Qmn . n n mediante las sustituciones {i , i=1,2,. . . ,n}, entonces construimos n ramas para el nodo considerado. En cada una de esas ramas escribimos la nueva resolvente derivada de la clusula Ci y de la sustitucin i , a o renombrando8 automticamente las variables de los a nuevos objetivos incorporados a la resolvente. Los atomos de la cola de la clusula unicada se a aden a n a la resolvente, mientras que el objetivo a resolver es eliminado de la misma. (b) Si el atomo seleccionado no se puede unicar con la cabeza de ninguna de las clusulas de P , se paraliza a la construccin de la rama del arbol considerada y se o devuelve fail como respuesta. (c) Si la resolvente resultante est vaca es porque no queda a ningn objetivo por resolver. En este caso, tambin se u e
8 dicho renombramiento puede efectuarse simplemente mediante la incorporacin de o un sub ndice a los nombres de las variables. Es importante indicar que esta tcnica es e necesaria para indicar qu variables de igual nombre en clusulas distintas son diferentes, e a evitando de este modo confusiones en las futuras sustituciones.

92

Conceptos Fundamentales

paraliza la construccin de dicha rama y se devuelve o true, adems del resultado de la composicin de las a o 1 2 . . . l que han sido consideradas sustituciones desde la raz hasta el nodo en cuestin. Ello constituye o la respuesta a la pregunta Q. 2 En este punto, es importante se alar que en la prctica la n a construccin del arbol de resolucin en un intrprete Prolog o o e impone un orden jo en la eleccin tanto del objetivo a resolver o dentro de la resolvente en un momento dado, como de la clusula a que ser aplicada en primer lugar. Ello nos obliga a redenir el a concepto de arbol de resolucin, tal y como es considerado en la o prctica por los intrpretes Prolog. Esta carcter a e a stica marca la diferencia fundamental entre lo que entendemos por intrprete e lgico basado en la resolucin SLD e intrprete Prolog. o o e Denicin 6.4.2 Sean P un programa lgico y Q una pregunta o o para el mismo, entonces el arbol de resolucin Prolog para el o programa P , dada la pregunta Q, se construye de la misma forma que en la anterior denicin 6.4.1, salvo que: o 1. El objetivo a resolver es siempre el primer atomo A de la resolvente Q, si consideramos esta como una lista ordenada de izquierda a derecha. 2. En el proceso de unicacin del objetivo a resolver, con las o cabezas de las clusulas del programa, se impondr un orden a a de exploracin de estas que ser de arriba hacia abajo. o a 3. Al a adir a la resolvente los atomos de la cola de la clusula n a unicada con el objetivo a resolver, estos sustituyen la posicin que tena en la resolvente el objetivo resuelto, a o la vez que conservan el orden local que mantenan en la cola de la clusula. a 2

6.4. Un intrprete lgico simple e o

93

Los dos conceptos introducidos en las deniciones 6.4.1 y 6.4.2 estn muy prximos. Sin embargo, los detalles que a o las distinguen tendrn una importancia fundamental en el a establecimiento de tcnicas prcticas de programacin lgica, e a o o as como en el alejamiento de esta de la declaratividad que en principio justic su introduccin. o o Ejemplo 6.4.1 Veamos el programa que dene recursivamente el tipo nmero natural, que viene dado por las clusulas: u a
numero_natural(0). numero_natural(siguiente(Numero)) :- numero_natural(Numero).

Consideremos la pregunta :- numero natural(siguiente(siguiente(0))). Entonces, la aplicacin directa de la denicin 6.4.2 puede o o representarse grcamente en forma de arbol de resolucin, cuyo a o valor exacto para este caso es el indicado en la gura 6.2.
{ numero_natural(siguiente(siguiente(0))) } Numero
1

siguiente(0)

{ numero_natural(siguiente(0)) } Numero { numero_natural(0) } 0

{ } true

Figura 6.2: Arbol de resolucin para o numero natural(siguiente(siguiente(0))).

la

pregunta

:-

94

Conceptos Fundamentales

Es absolutamente necesario detenerse en algunas reexiones acerca del trabajo expuesto hasta el momento. En efecto, el ejemplo 6.4.1 muestra un caso muy simple de resolucin desde o todo punto de vista: La pregunta realizada9 no contiene variables y por tanto la respuesta no se expresa en funcin de las sustituciones o aplicadas. El arbol de resolucin es determinista, en el sentido en que o cada nodo del mismo slo posee un hijo en su descendencia. o Ello equivale a decir que slo existe una posible respuesta. o Finalmente, el orden de lectura considerado para las clusulas y objetivos de la resolvente no ha perturbado en a forma alguna el proceso de resolucin. o Ello no es, ni mucho menos, lo habitual, como vamos a demostrar en la discusin que sigue. o

6.5

El concepto de retroceso

Como hemos comentado anteriormente, el recorrido del arbol de resolucin Prolog se efect a en profundidad. Este mtodo o u e consiste en un descenso directo a la rama ms a la izquierda a en el arbol de resolucin. En este punto, es necesario llamar la o atencin sobre tres posibles casos: o 1. Si nos encontramos con una resolvente vac al extremo de a la nueva rama, hemos encontrado una de las respuestas. Entonces, dependiendo de las implementaciones, Prolog se detiene y espera nuestras instrucciones o contin a buscando u otras respuestas. 2. Si caemos en una rama innita no podemos hacer otra cosa ms que tratar de eliminar nuestro proceso desde el sistema a
9 :-

numero natural(siguiente(siguiente(0))).

6.5. El concepto de retroceso

95

operativo o esperar a que la pila de ejecucin del intrprete o e se sature. 3. Si nos encontramos con un fail al extremo de la rama, entonces Prolog automticamente contin a con la a u exploracin de la rama inexplorada del arbol de resolucin o o que est ms prxima por la derecha. e a o En los casos 1 y 3, la exploracin de una nueva rama del o arbol implica el retroceder paso a paso por la rama acabada de construir. En cada nodo revisitado, se pueden plantear dos casos: Si existe una rama no explorada por la derecha, esto es, queda alguna clusula aplicable como alternativa a la a anteriormente escogida para resolver el primer objetivo de la resolvente de ese nodo, entonces esa nueva posibilidad es explorada. En otro caso, remontamos un nodo ms en nuestra rama a y recomenzamos el proceso para el mismo, hasta haber agotado todas las posibilidades. Si esto ultimo ocurre devolvemos fail como respuesta. El retroceso, tal como ha sido descrito, no slo se desencadena de o forma automtica por el intrprete Prolog cuando se encuentra a e con fail en el extremo de la rama del arbol de resolucin que se o explora en ese momento, sino que el usuario puede a voluntad forzar el retroceso en una rama en la que se ha obtenido una respuesta con xito. La utilidad en este caso se reserva para la e obtencin de varias respuestas para una misma pregunta. Para o forzar el retroceso una vez obtenida una respuesta, la mayor a de los intrpretes lgicos preveen la instruccin ; tecleada e o o directamente sobre el intrprete. e Ejemplo 6.5.1 Volviendo al programa del ejemplo 6.4.1, consideremos una pregunta que incluya variables en su estructura: :- numero natural(X).

96

Conceptos Fundamentales

Declarativamente, el signicado de la pregunta es el siguiente: Cules son los valores Val de la variable X para los que a el atomo numero natural(Val) es deducible a partir del programa. Esto es, los valores para los cuales X es un n mero natural. u Una cosa es, en principio, evidente: El conjunto de posibles soluciones es innito. Veremos cmo se enfrenta nuestro o intrprete a un problema de tal magnitud. En este caso, teniendo e en cuenta que el arbol de resolucin es el representado en la o gura 6.3, concluimos que la profundidad del mismo es innita y que a cada nodo de su estructura le corresponden dos hijos: 1. El situado ms a la izquierda es el resultado de la a unicacin nal con la primera de las clusulas del o a programa. Es slo en estas ramas en las que el proceso o de resolucin devolver una respuesta. o a
{ numero_natural(X) } X 0 X siguiente(Numero 1)

{ } { numero_natural(Numero 1) } true Numero 1 0 Numero 1 siguiente(Numero 2)

{ } { numero_natural(Numero 2) } true Numero 2 0

Numero 2

siguiente(Numero 3)

{ } { numero_natural(Numero 3) } true

Figura 6.3: Resolucin de :- numero natural(X). o

6.5. El concepto de retroceso

97

2. El hijo restante es el resultado de la aplicacin de la relacin o o recursiva representada por la segunda de las clusulas del a programa. Para recuperar las soluciones, bastar con aplicar las a sustituciones aplicadas sobre cada una de las ramas terminales. As, obtendremos:
X X X 0 siguiente(Numero1 ) siguiente(0) siguiente(Numero1 ) siguiente(siguiente(Numero2 )) siguiente(siguiente(0)) siguiente(Numero1 ) siguiente(siguiente(Numero2 )) siguiente(siguiente(siguiente(Numero3 ))) siguiente(siguiente(siguiente(0)))

. . .

Entre resultado y resultado, el usuario deber forzar el retroceso a en el intrprete Prolog. En relacin a la cuestin de cundo e o o a nalizar el clculo, la respuesta es tan contundente como a a simple: Cuando la memoria reservada por el ordenador para uso de nuestro intrprete se agote. 2 e Ejemplo 6.5.2 Se trata ahora de implementar el concepto de nmero natural par. Para ello bastar, en principio, con u a considerar la funcin siguiente del ejemplo 6.4.1. El esqueleto o del nuevo programa podra venir dado por las dos reglas que siguen:
par(0). par(siguiente(siguiente(Numero))) :- par(Numero).

De hecho la semntica declarativa es la correcta, puesto que: a El cero es un n mero natural par. u El siguiente al siguiente de un n mero natural Numero u es par, si Numero lo es.

98

Conceptos Fundamentales

Este programa se comporta conforme a lo esperado ante preguntas como :- par(X). que nos devuelve todos los posibles valores para los nmeros u naturales pares. La respuesta para preguntas con argumentos que no incluyan variables es igualmente satisfactoria, como sera el caso de: :- par(siguiente(siguiente(0))). que produce una respuesta armativa. 2 Ejemplo 6.5.3 De forma anloga, podemos implementar el a concepto de nmero natural impar. Siguiendo la misma tcnica u e que la del anterior ejemplo, nuestro programa podra ser el siguiente:
impar(siguiente(0)). impar(siguiente(siguiente(Numero))) :- impar(Numero).

cuya semntica declarativa es la dada por: a El uno es un n mero natural impar. u El siguiente al n mero natural siguiente(Numero) u es impar, si Numero lo es. Este programa se comporta conforme a lo esperado ante preguntas como :- impar(X). que nos devuelve todos los posibles valores para los nmeros u naturales impares. Como en el caso del ejemplo 6.5.2 la respuesta es igualmente satisfactoria para preguntas cuyos argumentos no incluyen variables. 2 Ejemplo 6.5.4 Como muestra ms completa de programa a lgico vamos a extender el programa del ejemplo 6.4.1 con o el objeto de implementar el concepto de suma de nmeros u naturales. Para ello basta considerar el programa lgico o siguiente:

6.5. El concepto de retroceso

99

numero_natural(0). numero_natural(siguiente(Numero)) :- numero_natural(Numero). suma(0,Numero,Numero) :- numero_natural(Numero). suma(siguiente(Numero_1),Numero_2,siguiente(Numero_3)) :suma(Numero_1,Numero_2,Numero_3).

o donde suma(Sumando 1,Sumando 2,Resultado) es la notacin de usuario que determina la semntica declarativa del predicado a suma, cuyo signicado ser: a El resultado de la suma de Sumando 1 y Sumando 2 es Resultado. y a partir de la cual hemos construido las dos clusulas del a predicado suma en la forma: La suma del cero y de un n mero cualquiera, es dicho u n mero si este es natural. u La suma del siguiente al n mero Numero 1 y un u u n mero arbitrario Numero 2, es el siguiente al n mero u Numero 3, si Numero 3 es el resultado de sumar Numero 1 y Numero 2.

{ suma(0,siguiente(siguiente(0)),X) }

Numero 1 Numero
1

siguiente(siguiente(0)) X

{ natural(siguiente(siguiente(0)) }

{ } true

Figura 6.4: Resolucin de :- suma(0,siguiente(siguiente(0)),X). o

Una vez el programa denido, consideremos la pregunta: :- suma(0,siguiente(siguiente(0)),X ).

100

Conceptos Fundamentales

Esto es, estamos preguntando por el valor de la suma de 0 y 2. El proceso de resolucin es en este caso el representado en la o gura 6.4, cuya unica solucin es: o X Numero1 siguiente(siguiente(0)) 2

6.6

Signicado de un programa lgico o

Es fundamental resaltar dos cuestiones importantes que afectarn a la congruencia declarativo/operacional de Prolog. a En efecto, desde un punto de vista meramente operacional: 1. La eleccin de los objetivos de la resolvente que en cada caso o debern ser resueltos, se realizar en un orden determinado. a a Ello tendr como consecuencia que el funcionamiento de a los programas Prolog sea directamente dependiente de dicho orden, cuando desde un punto de vista meramente declarativo ello es irrelevante. 2. Lo mismo se puede decir sobre el orden de b squeda de las u clusulas cuya cabeza unicar con el objetivo a resolver. a a Esta situacin se traduce formalmente en una posible diferencia o entre el signicado10 de un programa lgico P que notaremos o 11 por S(P ), y su signicado deseado D(P ). Concretamente, denimos los conceptos de correccin y completud de un o programa lgico. o Denicin 6.6.1 Sea P un programa lgico, entonces decimos o o que P es correcto respecto a una signicacin deseada D(P ) si o S(P ) D(P ). Decimos que P es completo respecto a D(P ) si D(P ) S(P ).
es, el conjunto de objetivos deducibles aplicando el algoritmo de resolucin. o decir, el conjunto de objetivos que el programador desear que fuesen deducibles a a partir del programa.
11 es 10 esto

6.6. Signicado de un programa lgico o

101

Intuitivamente, un programa es correcto cuando todas las soluciones calculadas entran dentro del conjunto de las previstas por el programador, mientras que es completo cuando todas las soluciones previstas por el programador pueden ser efectivamente calculadas por el programa. 2 Lejos de constituir casos aislados, las incongruencias declarativo/operacionales son, en la prctica, el taln de aquiles a o de la programacin lgica. La unica solucin prctica hoy o o o a por hoy es la consideracin de la semntica declarativa de o a las clusulas como una primera aproximacin a la semntica a o a operacional del programa, que en denitiva es la que cuenta12 . Eso si, ya hemos perdido parte de la magia de un lenguaje lgico o puro. Con el n de presentar un caso t pico de incongruencia declarativo/operacional, vamos a intentar aplicar toda la potencia de la semntica declarativa a nuestro programa del a ejemplo 6.5.4. Ejemplo 6.6.1 Continuando con el programa del ejemplo 6.5.4, consideraremos ahora la pregunta :- suma(X,Y,siguiente(siguiente(0))). Ello equivale a intentar resolver la ecuacin o X +Y =2 Obtenemos el arbol de resolucin representado en la gura 6.5, o
12 en este punto, es muy importante dejar claro que los distintos mtodos de resolucin e o considerados en programacin lgica son siempre correctos y completos. Es en el o o momento de su implementacin cuando, atendiendo a razones de econom de recursos o a y de eciencia general del proceso, el diseador puede optar por limitar la completud del n algoritmo. En todo caso, la correccin debe estar siempre asegurada. o

102

Conceptos Fundamentales

y por tanto las respuestas son en este caso las dadas por:
X 0 Y Numero 11 siguiente(siguiente(0)) X siguiente(Numero 11 ) siguiente(0) Y Numero 21 siguiente(0)) X siguiente(Numero 11 ) siguiente(siguiente(Numero 12 )) siguiente(siguiente(0)) Numero 21 Numero 22 0

{ suma(X,Y,siguiente(siguiente(0))) } X Y Numero 1 0 Numero 1 siguiente(siguiente(0)) { numero_natural(siguiente(siguiente(0))) } Numero_1 1 Numero_2 { } true

X Y Numero_3

siguiente(Numero_1 ) 1 Numero_2 1 siguiente(0)

{ suma(Numero_1 1,Numero_2 1,siguiente(0)) } Numero_1 1 0 Numero_2 1 siguiente(0) Numero_3 2

siguiente(Numero_1 2) Numero_2 2 0

{ numero_natural(siguiente(0)) } { suma(Numero_1 2, Numero_2 2,0) } Numero_1 2 Numero_2 { } true { numero_natural(0) } 0 0

{ } true

Figura 6.5: Resolucin de :- suma(X,Y,siguiente(siguiente(0))). o

Est claro que en el caso de la pregunta considerada en el a ejemplo 6.6.1 el programa no presenta mayores problemas, y en principio todo parece funcionar como estaba previsto en la semntica declarativa. Vamos a ver que desgraciadamente a ello es tan solo un simple espejismo. Comenzamos con las incongruencias. Para ello, y antes de pasar al ejemplo concreto, debemos subrayar el hecho de que con el signicado declarativo considerado, nuestro programa deber en principio ser capaz de a resolver cualquier ecuacin de n meros naturales de la forma o u X +Y =Z

6.6. Signicado de un programa lgico o

103

cuando veremos que desde un punto de vista operacional ello no es ni remotamente posible. Ejemplo 6.6.2 Supongamos que al programa considerado en el ejemplo 6.5.4 se le interroga con la pregunta :- suma(X,Y,Z) Esto es, nos interesamos por las soluciones de la ecuacin o X +Y =Z Desde un punto de vista exclusivamente declarativo, nuestro programa debera ser capaz de responder; sin embargo dicho empe o slo podr ser posible en parte, como muestra la n o a gura 6.6 que representa el correspondiente arbol de resolucin. o
{ suma(X,Y,Z) } 0 Numero 1 Numero
1

X Y Z

{ numero_natural(Numero 1) } Numero 1 0 Numero 1 siguiente(Numero 2)

{ } { numero_natural(Numero 2) } true Numero 2 0

Numero 2

siguiente(Numero 3)

{ } { numero_natural(Numero 3) } true

Figura 6.6: Resolucin de :- suma(X,Y,Z). o

En efecto, ante la pregunta considerada, el programa jams a llega a proporcionar ni una sola de las respuestas vlidas de a la ecuacin. En sntesis, el problema consiste en que debido o

104

Conceptos Fundamentales

al mtodo particular aplicado para la exploracin del arbol e o de resolucin, en profundidad, el algoritmo de resolucin es o o incapaz de salirse del proceso que implica la determinacin de o la naturaleza del primero de los sumandos X, como nmero u natural. 2 En denitiva, podemos concluir que en s mismo, la implementacin del algoritmo SLD considerado en la prctica o a por Prolog, no es completo. De hecho la completud se sacrica en aras tanto de la eciencia del sistema como de la econom de recursos. El problema as planteado es endmico a e en programacin lgica, y su resolucin todav est abierta. o o o a a En este sentido, los esfuezos se concentran en el dise o n de nuevos esquemas de resolucin [15, 26], para los que la o exigencia de completud en los clculos no se traduzca en una a explotacin masiva de recursos, a la vez que se asegura un buen o comportamiento temporal del sistema. Profundizando ahora en las razones de la incompletud operacional de la mayor de los dialectos Prolog, diremos que a el paradigma declarativo en el que se basa la programacin o lgica slo establece relaciones entre los objetos manejados en o o un programa, pero en ning n caso un orden en el tratamiento de u estas. En este sentido, es necesario hacer hincapi en el hecho de e que ni el mtodo de unicacin de Robinson del algoritmo 6.3.1, e o ni el intrprete lgico del algoritmo 6.4.1 establecen ning n e o u tipo de orden en el tratamiento de los objetos y relaciones del programa lgico. El aspecto expuesto es determinante para la o comprensin de los problemas planteados en la prctica por la o a programacin lgica y nuestro objetivo ser ahora el de ilustrar o o a mediante ejemplos simples las situaciones provocadas por este alejamiento del paradigma declarativo. Como primer factor causante de tales incongruencias nos referiremos al orden de tratamiento de los objetivos durante el proceso de resolucin o establecido por el algoritmo 6.4.1 y que fue jado en la denicin 6.4.2 como el signicado en la prctica del concepto o a de arbol de resolucin. Como segundo factor, nos referiremos o

6.6. Signicado de un programa lgico o

105

al orden de exploracin del conjunto de clusulas que forman o a nuestro programa y que recordamos tambin fue jado en la e denicin 6.4.2. o A pesar de las limitaciones expuestas en el ejemplo 6.6.2 con respecto al funcionamiento de la denicin lgica propuesta o o para la suma, esta puede servir de base para la creacin de una o peque a biblioteca matemtica que considere las operaciones n a numricas fundamentales, tal y como se mostrar en los e a cap tulos siguientes. 6.6.1 El orden de tratamiento de los objetivos

Para ilustrar la inuencia de este factor en la incompletud operacional de Prolog plantearemos un problema sencillo, el de la denicin del concepto de persona. Nuestra semntica o a declarativa ser la siguiente: a Alguien es una persona si tiene una madre y esta es una persona. Claramente, la denicin considerada es vlida y el orden de o a las condiciones establecidas es irrelevante. Esto es, el orden de tratamiento de los conceptos: Tener una madre. La madre es una persona. no altera la relacin establecida en nuestra denicin del o o concepto. Sin embargo, veremos que este orden s inuye en el tratamiento que en la prctica realiza Prolog. As una posible a , implementacin es la dada por la regla o
persona(Persona) :- persona(Madre), madre(Persona, Madre).

donde estamos suponiendo que persona(Persona) es cierto si Persona es un individuo humano. Evidentemente, es necesario completar nuestra base de datos con el n de establecer las relaciones madre(Persona, Madre) pertinentes. Un primer acercamiento podr ser el programa: a

106

Conceptos Fundamentales

persona(Persona) :- persona(Madre), madre(Persona, Madre). madre(Javier, Rosa). madre(Juan, Maria). madre(Eva, Nuria). persona(Rosa). persona(Maria). persona(Nuria).

para el cual, considerando el orden de tratamiento de los objetivos de la denicin 6.4.2, el usuario no obtendr respuesta o a para la pregunta :- persona(Juan). por agotamiento de los recursos de memoria. La razn es simple o y estriba en que para responder a la misma, el intrprete aplica e la siguiente semntica operacional: a El individuo Persona es una persona si se puede demostrar que el individuo Madre es una persona y que adems es la madre de Persona. a El problema radica en que para responder al objetivo persona(Madre) el intrprete volver a aplicar la primera de e a las clusulas, entrando en un bucle innito. Sin embargo, a la situacin var simplemente con cambiar el orden de los o a trminos de la primera clusula. En efecto, consideremos ahora e a el conjunto de clusulas siguiente: a
persona(Persona) :- madre(Persona, Madre), persona(Madre). madre(Javier, Rosa). madre(Juan, Maria). madre(Eva, Nuria). persona(Rosa). persona(Maria). persona(Nuria).

La semntica declarativa es la misma del programa anterior, a pero la operacional ha cambiado sustancialmente debido a la

6.6. Signicado de un programa lgico o

107

alteracin en el orden de tratamiento de los objetivos a tratar o durante el proceso de resolucin. Ahora la semntica operacional o a es: El individuo Persona es una persona si se puede demostrar que tiene una madre Madre y esta es una persona. Ms exactamente, la diferencia consiste en que cuando ahora a planteamos la pregunta :- persona(Juan). en primer lugar buscamos la identidad de su madre, en caso de existir, y que en este caso es Maria. Cuando ahora intentamos resolver el objetivo persona(Madre), la variable Madre ha sido instanciada al valor Maria y su resolucin es inmediata y o armativa. Esto es, la respuesta a nuestra pregunta inicial es ahora true. 6.6.2 El orden de aplicacin de las clusulas o a

Con el n de discutir la inuencia de este nuevo aspecto utilizaremos el mismo ejemplo usado para ilustrar la inuencia del orden de tratamiento de los objetivos en el proceso de resolucin: la denicin del concepto de persona. En efecto, aun o o sin cambiar el orden de los trminos en las clusulas, podemos e a reconstruir nuestro programa de forma que podamos obtener una respuesta congruente para la pregunta :- persona(Juan). El razonamiento es muy simple: se trata de conseguir que cuando se realice la resolucin del objetivo persona(Madre), o ello no conlleve la aplicacin de la clusula recursiva, que era o a la responsable de la entrada en un bucle innito. Una vez jado el orden de aplicacin de las clusulas del programa por o a la denicin 6.4.2, consideremos el nuevo programa: o

108 persona(Rosa). persona(Maria). persona(Nuria).

Conceptos Fundamentales

persona(Persona) :- persona(Madre), madre(Persona, Madre). madre(Javier, Rosa). madre(Juan, Maria). madre(Eva, Nuria).

cuya semntica declarativa es idntica a la del original. La a e respuesta a nuestra pregunta es ahora true, aun cuando la estructura interna de las clusulas no ha variado en absoluto. a En este punto es conveniente claricar qu es lo que realmente e puede esperar el programador de un lenguaje como Prolog y cules son sus ventajas en relacin a los lenguajes clsicos. As a o a , por un lado es evidente que el atractivo fundamental estriba en la declaratividad que podemos imprimir a nuestro estilo de programacin. Ello es fcilmente vericable en la prctica, en o a a la que unas cuantas clusulas Prolog suelen ser equivalentes a a pginas completas de cdigo escrito en otros lenguajes clsicos a o a de probada ecacia. Sin embargo, y a la vista de los resultados presentados en esta seccin, el programador deber considerar este o a aspecto declarativo slo como una potente facilidad orientativa o en su trabajo. En ning n caso deber olvidar que u a el lenguaje tiene una componente operacional importante, inducida principalmente por los dos factores comentados anteriormente. En este sentido, es importante se alar n tambin que estas dos limitaciones al paradigma declarativo e son generalmente superables, desarrollndose un estilo de a programacin caracter o stico que consiste en tener en cuenta el orden de los trminos y de las clusulas del programa en relacin e a o al algoritmo de resolucin del intrprete lgico. En resumen, dos o e o reglas son sucientes en la mayor parte de los casos para resolver esta situacin: o

6.6. Signicado de un programa lgico o

109

1. Dado que los objetivos se resuelven de izquierda a derecha seg n el orden preestablecido en Prolog por la u denicin 6.4.2, el programador deber asegurarse de que o a ello asegura la instanciacin del mayor n mero posible de o u variables en los objetivos inmediatos a resolver. 2. En la misma l nea, el programador deber asegurarse de a que la exploracin de la base de datos constituida por o las clusulas, de arriba hacia abajo, asegura que los casos a particulares sean tratados con la mayor brevedad posible, evitando en lo posible la ca en ciclos innitos durante la da construccin del arbol de resolucin. o o Aparte de los factores ya se alados, existen otros que n inuyen tambin de forma denitiva en el alejamiento, cuando e programamos en Prolog, de la programacin lgica con respecto o o al paradigma declarativo. Se trata fundamentalmente de la introduccin en el lenguaje del concepto de predicado no o lgico. o Esto es, de predicados con un signicado lgico o irrelevante, que no expresan ning n tipo de relacin sino tan u o slo comportamientos operacionales. Este es t o picamente el caso de las estructuras de control o de la gestin de las entradas y o salidas.

110

Conceptos Fundamentales

Cap tulo 7

Control en Prolog: el Corte


Hemos visto la importancia de entender, en la prctica, el a orden en el que Prolog resuelve las cuestiones planteadas. En particular, hemos intuido lo interesante de la posibilidad de controlar de alg n modo dicho orden. En este sentido, el corte u es el mtodo ms utilizado para establecer un control de la e a resolucin en un programa Prolog. Pero no nos enga emos, su o n utilizacin abrir a su vez nuevos interrogantes. o a

7.1

Semntica operacional a

Bsicamente, el corte es un predicado cuya utilizacin provoca a o un efecto colateral sobre la estructura del arbol de resolucin, o forzando a que ciertas ramas que en principio podr an ser exploradas en caso de retroceso, no lo sean en la prctica. Esto a es, se trata de una forma muy simple de determinizar nuestra b squeda de soluciones. u Denicin 7.1.1 El corte es un predicado sin argumentos, o que se verica siempre y que suele representarse mediante la notacin !. Se ejecuta en el momento en el que es llamado, esto o es, en el momento en que se encuentra como primer objetivo
111

112

Control en Prolog: el Corte

a la izquierda de nuestra resolvente. Como efecto colateral, suprime en el nodo actual de nuestro arbol de resolucin todas las o alternativas que puedan quedar por explorar para los predicados que se encuentren entre la cabeza de la clusula en la que a aparece, y el lugar en el que el corte se ha ejecutado. 2

a : b1 , . . . , bi1 , !, bi , . . . , br . b1 : c1 , c1 , . . . , c1 1,1 . 1,1 1,2 1,m . . . b1 : cl1 , cl1 , . . . , cl1 1,l . 1,m 1 1,1 1,2 . . . b1 : cn1 , cn1 , . . . , cn1 1,n . 1,m 1,1 1,2
1

1 1 bi1 : c1 i1,1 , ci1,2 , . . . , ci1,mi1,1 . . . .


i1 i1 i1 bi1 : ci1,1 , ci1,2 , . . . , ci1,mi1,l . i1 . . . i1 i1 i1 bi1 : ci1,1 , ci1,2 , . . . , ci1,mi1,n . i1 1 1 1 bi : ci,1 , ci,2 , . . . , ci,mi,1 . . . .

b2 : c1 , c1 , . . . , c1 2,1 . 2,1 2,2 2,m . . . b2 : cl2 , cl2 , . . . , cl2 2,l . 2,1 2,2 2,m 2 . . . b2 : cn2 , cn2 , . . . , cn2 2,n . 2,1 2,2 2,m 2 . . .

bi : cni , cni , . . . , cni i,n . i,1 i,2 i,m i . . . br : c1 , c1 , . . . , c1 r,1 . r,1 r,2 r,m . . . br : cnr , cnr , . . . cnr r,nr . r,m r,1 r,2

Figura 7.1: Un programa Prolog genrico e

El concepto de corte es tan importante como dif de asimilar, cil es por ello que ser objeto de especial atencin a lo largo a o del presente texto. Para comenzar, ilustraremos su utilizacin o en el entorno de un programa abstracto. Ms exactamente, a consideremos un programa lgico incluyendo el conjunto de o clusulas representado en la gura 7.1. y supongamos que en a un momento dado nuestra resolvente es de la forma {a, . . .}

7.1. Semntica operacional a

113

vericndose adems todos los objetivos a a b1 , b2 , . . . bi1 y siendo las correspondientes primeras clusulas para las a que dichos objetivos se verican1 aquellas indicadas con los super ndices l1 , l2 , . . . li1 respectivamente. Entonces, una vez el corte se ha ejecutado, todas las alternativas de las clusulas cuya cabeza se encuentra a en el conjunto b1 , b2 , . . . bi1 y que todav no han sido exploradas, se cortan para la a resolucin del objetivo a. Esto es, en caso de un retroceso o sobre las ramas construidas entre el nodo del arbol de resolucin o indicado por {a, . . .} y aquel en el que el corte es el primer objetivo, ninguna de las alternativas indicadas por las clusulas a
i1 bj1 , bj2 , . . . , bi1 , tal que j1 > l1 , j2 > l2 , . . . , ji1 > li1 2 1

se tendrn en cuenta en el proceso de resolucin. Informalmente, a o la inclusin de un corte en una clusula es una forma de decir: o a Si hemos llegado hasta aqu, es que estamos en el buen camino y por tanto es intil intentar otras u alternativas en el camino ya recorrido. Ejemplo 7.1.1 Como primer ejemplo para mostrar las posibilidades del corte, consideremos la implementacin de o la multiplicacin de nmeros naturales en Prolog. o u La semntica declarativa del predicado mult viene dada por a la notacin de usuario mult(Factor 1,Factor 2,Resultado) o cuyo signicado ser: a El resultado de la multiplicacin de Factor 1 por o Factor 2 es Resultado.
1 observar

de nuevo la importancia del orden de exploracin del conjunto de reglas del o

programa.

114

Control en Prolog: el Corte

y a partir de la cual hemos construido las clusulas del predicado a mult en la forma: La multiplicacin del cero por un n mero natural o u cualquiera es siempre cero. La multiplicacin del uno por un n mero natural o u cualquiera es ese mismo n mero. u La multiplicacin del siguiente al n mero Numero 1 o u por un n mero arbitrario Numero 2, es el n mero u u Numero 3, donde Numero 3 es el valor de sumar Numero 2 con el resultado de la multiplicacin de o Nmero 1 por Nmero 2. u u
numero_natural(0). numero_natural(siguiente(Numero)) :- numero_natural(Numero). suma(0,Numero,Numero) :- numero_natural(Numero). suma(siguiente(Numero_1),Numero_2,siguiente(Numero_3)) :suma(Numero_1,Numero_2,Numero_3). mult(0,Numero,0) :- numero_natural(Numero). mult(siguiente(0),Numero,Numero) :- !, numero_natural(Numero). mult(siguiente(Numero_1),Numero_2,Numero_3) :mult(Numero_1,Numero_2,Numero_4), suma(Numero_4,Numero_2,Numero_3).

Una vez el programa construido, consideremos como una posible pregunta: :- mult(siguiente(0),0,X). esto es, estamos preguntando por el valor de X =10 cuyo arbol de resolucin est representado en la gura 7.3. La o a unica respuesta obtenida ser la dada por a X Numero1 0

7.1. Semntica operacional a

115

Es importante observar que, en principio, es posible un retroceso sobre la segunda rama de la gura 7.3, pero ello es evitado por la presencia del corte. Supongamos que la denicin considerada o para el predicado mult fuese la siguiente:
mult(0,Numero,0) :- numero_natural(Numero). mult(siguiente(0),Numero,Numero) :- numero_natural(Numero). mult(siguiente(Numero_1),Numero_2,Numero_3) :mult(Numero_1,Numero_2,Numero_4), suma(Numero_4,Numero_2,Numero_3).

entonces la semntica declarativa de nuestro programa es a exactamente la misma, pero la operacional ha cambiado. Veamos lo que ocurre cuando interrogamos al intrprete con e nuestra nueva base de datos. De hecho estaremos en condiciones de obtener dos soluciones forzando el retroceso, sin embargo este esfuerzo de clculo es intil puesto que la segunda respuesta a u es la misma que la primera. Ms exactamente, las respuestas a obtenidas son: X Numero1 0 X Numero 31 0 siendo el correspondiente arbol de resolucin el mostrado en la o gura 7.2. 2 Este ultimo ejemplo 7.1.1 muestra una de las aplicaciones fundamentales del corte, a saber, la determinizacin del proceso o de resolucin con el objetivo nal de eliminar soluciones que o bien por la naturaleza del problema2 , bien por la naturaleza del cdigo3 , hemos decidido no tener en cuenta. o Ejemplo 7.1.2 A partir de la denicin de multiplicacin de o o nmeros naturales considerada en el anterior ejemplo 7.1.1, u podemos construir un predicado exp(Base, Exponente, Resultado)
conjunto de posibles soluciones, puede interesarnos unicamente encontrar una. consideracin de clusulas especializadas en la resolucin de un determinado caso o a o en un problema, ya que puede conducirnos a obtener varias veces una misma solucin si o no tenemos en cuenta un mtodo de control de la resolucin. e o
3 la 2 del

116

Control en Prolog: el Corte

X Numero

{ mult(siguiente(0),0,X) } Numero
1 1

X Numero_11 Numero_2

Numero_3 1 0 0

{ numero_natural(0) }

{ mult(0,0,Numero_4 1 ), suma(Numero_4 1,0,Numero_3 1 ) } Numero_4 1 Numero


1

0 0

{ } true

{ suma(0,0,Numero_3 ) }
1

Numero_3 { numero_natural(0) }

{ } true

Figura 7.2: Resolucin de :- mult(siguiente(0),0,X)., sin corte o

{ mult(siguiente(0),0,X) } X Numero 1 Numero 1 0

{ !, numero_natural(0) }

{ numero_natural(0) }

{ } true

Figura 7.3: Resolucin de :- mult(siguiente(0),0,X)., con corte o

7.1. Semntica operacional a

117

que se verique cuando BaseExponente = Resultado Esto es, se trata de implementar la exponenciacin de nmeros o u naturales. El programa propuesto posee una estructura similar a la del ejemplo 7.1.1, si nos limitamos al caso de los nmeros u naturales, y viene dado por las clusulas siguientes: a
numero_natural(0). numero_natural(siguiente(Numero)) :- numero_natural(Numero). suma(0,Numero,Numero) :- numero_natural(Numero). suma(siguiente(Numero_1),Numero_2,siguiente(Numero_3)) :suma(Numero_1,Numero_2,Numero_3). mult(0,Numero,0) :- numero_natural(Numero). mult(siguiente(0),Numero,Numero) :- !, numero_natural(Numero). mult(siguiente(Numero_1),Numero_2,Numero_3) :mult(Numero_1,Numero_2,Numero_4), suma(Numero_4,Numero_2,Numero_3). exp(Numero, siguiente(0), Numero) :- numero_natural(Numero), !. exp(Numero, 0, siguiente(0)). exp(Numero, siguiente(Exponente), Resultado) :exp(Numero, Exponente, Parcial), mult(Parcial, Numero, Resultado).

donde las unicas clusulas introducidas en relacin al a o ejemplo 7.1.1 son las tres ultimas, cuya semntica declarativa a viene dada por: El resultado de elevar un n mero natural Numero a u la potencia uno, es ese mismo n mero. u El resultado de elevar un valor numrico cualquiera e a la potencia cero, es el uno. El resultado Resultado de elevar un n mero Numero u al n mero natural siguiente a Exponente, es igual u a calcular la potencia Exponente de dicho n mero u Numero y multiplicar el resultado Parcial de dicha operacin nuevamente por Numero. o

118

Control en Prolog: el Corte

En este caso, la razn por la que hemos introducido un corte en o la parte derecha de la primera clusula del predicado exp, es para a evitar retrocesos sobre la tercera cuando el segundo argumento es un uno. 2 Siguiendo la misma pauta, podemos ahora implementar el concepto matemtico de resto. Anal a ticamente, decimos que un n mero natural Resto es el resto mdulo Y de un n mero u o u X si el resto de dividir X por Y es Resto. Como en los ejemplos anteriores, nos limitaremos por comodidad al caso de los n meros naturales. u Ejemplo 7.1.3 Para implementar el concepto matemtico de a resto, basta considerar el siguiente conjunto de reglas:
numero_natural(0). numero_natural(siguiente(Numero)) :- numero_natural(Numero). suma(0,Numero,Numero) :- numero_natural(Numero). suma(siguiente(Numero_1),Numero_2,siguiente(Numero_3)) :suma(Numero_1,Numero_2,Numero_3). mult(0,Numero,0) :- numero_natural(Numero). mult(siguiente(0),Numero,Numero) :- !, numero_natural(Numero). mult(siguiente(Numero_1),Numero_2,Numero_3) :mult(Numero_1,Numero_2,Numero_4), suma(Numero_4,Numero_2,Numero_3). inferior(0, 0) :- !, fail. inferior(0, Numero) :- numero_natural(Numero). inferior(siguiente(Numero_1), siguiente(Numero_2)) :inferior(Numero_1, Numero_2). modulo(Dividendo, Divisor, Dividendo) :inferior(Dividendo, Divisor), !. modulo(Dividendo, Divisor, Resto) :suma(Parcial, Divisor, Dividendo), modulo(Parcial, Divisor, Resto).

7.1. Semntica operacional a

119

Esta no es, sin embargo, la unica aplicacin del corte. En o efecto, el uso ms general dado a esta estructura fundamental a de control es el de optimizar la b squeda de soluciones, u eliminando posibilidades que el programador sabe que no pueden ser correctas y que el algoritmo de resolucin podr decidir o a explorar4 . En resumen, se trata de guiar al intrprete por el e buen camino, impidindole entretenerse en clculos infructuosos. e a Ejemplo 7.1.4 Se trata de implementar un programa capaz de deducir el nmero de progenitores paternos de una persona, u teniendo en cuenta que Adn y Eva no tuvieron ninguno. Para a ello, consideraremos el predicado numero de padres(Persona, Numero) que ser cierto si el nmero de progenitores de Persona es a u Numero. En este sentido, una primera versin de nuestro o programa podra ser:
numero_de_padres(Adan,0). numero_de_padres(Eva,0). numero_de_padres(Persona,2).

cuya semntica declarativa es la siguiente: a El n mero de padres de Adn es cero. u a El n mero de padres de Eva es cero. u Cualquier persona tiene dos padres. sin embargo, la posibilidad de efectuar retrocesos imprevistos hace que nuestra semntica operacional diera de nuestra idea a original. En efecto, consideremos la pregunta: :- numero de padres(Adan,X). obtendremos dos respuestas distintas si el retroceso es forzado: X0 X2
la exploracin de tales alternativas se obtendr nalmente un fail como o a respuesta.
4 en

120

Control en Prolog: el Corte

de las cuales la segunda es claramente incorrecta. El correspondiente arbol de resolucin puede verse en la gura 7.4. o La solucin en principio est en cortar la ultima posibilidad o a explorada por el intrprete; para ello bastara con corregir el e programa inicial en la forma:
numero_de_padres(Adan,0) :- !. numero_de_padres(Eva,0) :- !. numero_de_padres(Persona,2).

con lo que pudiramos pretender que la semntica operacional e a fuese: El n mero de padres de Adn es cero. u a El n mero de padres de Eva es cero. u Cualquier persona que no sea ni Eva ni Adn, tiene a dos padres.
{ numero_de_padres(adan,X) } X { } true 0 X 2 { } true

Figura 7.4: Resolucin de :- numero de padres(Adan,X)., sin corte o

Sin embargo, no es ese el caso. Aunque a la pregunta anterior :- numero de padres(Adan,X). obtenemos como respuesta X0 cuando planteamos la nueva pregunta :- numero de padres(Adan,2). la respuesta obtenida es true. La explicacin est en que o a no hemos previsto todos los casos posibles de unicacin. o

7.1. Semntica operacional a

121

Ms exactamente, no hemos guiado adecuadamente a nuestro a intrprete durante la resolucin. Una solucin efectiva sera la e o o siguiente:
numero_de_padres(Adan,N) :- !, N=0. numero_de_padres(Eva,N) :- !, N=0. numero_de_padres(Persona,2).

donde el predicado = es un predicado no lgico5 que implica o en este caso la unicacin de la variable N con el valor 0. Debe o observarse que ahora no hemos limitado ninguna posibilidad de unicacin en cuanto al nmero de padres, ni para Eva ni para o u Adn. Eso s, una vez vericado el hecho de que la persona en a cuestin es uno de los dos personajes bblicos, cortamos todas o las otras posibilidades para el predicado numero de padres. 2
{ numero_de_padres(adan,X) } X { } true 0 { } true { numero_de_padres(adan,2) }

Figura 7.5: Arboles con corte para :- numero de padres(Adan,X). y :- numero de padres(Adan,2).

Una tercera posibilidad de aplicacin del predicado de corte, o es su combinacin con el predicado predenido fail. En este o caso, se pretende emular de alg n modo el funcionamiento de u la negacin lgica, pero ello constituye por mrito propio un o o e cap tulo aparte. Un caso t pico de utilizacin del corte es la generacin de o o estructuras de control a semejanza de las existentes en los lenguajes clsicos de programacin: if, while, repeat, ... a o Ello recalca el papel del corte como estructura fundamental de control en programacin lgica. Para ilustrar este tipo de o o aplicaciones, consideremos un caso concreto de implementacin. o
5 sern a

introducidos ms tarde. a

122

Control en Prolog: el Corte

Ejemplo 7.1.5 Se trata de implementar una estructura clsica a de control, la instruccin if then else. Su semntica ser la o a a habitual. As, deniremos el predicado if then else(P,Q,R) en la forma: Si P es cierto, entonces probar Q, sino probar R. y cuya implementacin es la siguiente: o
if_then_else(P,Q,R) :- P, !, Q. if_then_else(P,Q,R) :- R.

En este caso, el corte indica que una vez probado el objetivo P, el unico camino a seguir es el indicado por la primera clusula a de la denicin, esto es, probar Q. 2 o Ejemplo 7.1.6 Un ejercicio simple consiste en implementar un predicado intentar(P) que demuestre la veracidad de P si ello es posible. En otro caso, la respuesta a nuestra pregunta debe ser true. La funcionalidad requerida requiere tan slo dos clusulas: o a
intentar(Objetivo) :- Objetivo,!. intentar(Objetivo).

cuya semntica declarativa viene dada por: a Si Objetivo es cierto, demostrarlo. Si Objetivo no es cierto, devolver true. La razn que justica en este caso la consideracin de un corte o o como ultimo literal en la parte derecha de la primera clusula, a es que cuando Objetivo ha sido demostrado ya sabemos que la respuesta debe ser armativa, y ello sin tener que recurrir a la relacin expresada por la segunda clusula. 2 o a

7.2

Tipos de cortes

Un punto importante en el que merece la pena detenerse en relacin al uso de los cortes, es su clasicacin en funcin de los o o o efectos que su desaparicin puede provocar en el signicado de o un programa. Se trata, en denitiva, de medir el impacto del uso de cortes en la mantenibilidad de los programas.

7.2. Tipos de cortes

123

7.2.1

El corte verde

Informalmente, diremos que un corte es un corte verde, cuando su presencia o no, no quita ni pone nada al signicado de un programa. Ello quiere decir simplemente que este tipo de corte expresa determinismo, esto es, se trata en todo caso de eliminar respuestas repetidas. Tal es el caso del corte del ejemplo 7.1.1, comentado ya ampliamente. 7.2.2 El corte rojo

En el caso de un corte rojo, su presencia o no en el programa provoca un cambio en el signicado del mismo. Ello implica que no se trata simplemente de determinizar un programa, sino que la inclusin del corte se justica exclusivamente desde un punto o de vista operacional. Un caso simple es el considerado en el ejemplo 7.1.4. En la prctica, cualquier utilizacin de un corte a o rojo deber estar claramente indicada en el cdigo, en forma de a o comentario. En denitiva, la utilizacin de cortes es objeto de continuas o controversias. En efecto, su uso pretende por un lado limitar el espacio de b squeda en los arboles de resolucin, no slo con el u o o objeto de mejorar las prestaciones, sino tambin para permitir e ciertas funcionalidades6 que de otro modo no ser posibles. an Sin embargo, por otro lado, su introduccin abre todav ms la o a a brecha existente entre las semnticas declarativa y operacional a de nuestros programas lgicos. A este respecto, conviene no o olvidar dos cuestiones importantes, y enfrentadas: 1. Gran parte de las aplicaciones del corte no pueden entenderse desde otro punto de vista que no sea el operacional. 2. El lenguaje Prolog pretende ser un lenguaje declarativo.
6 como

veremos en el caso de la negacin. o

124

Control en Prolog: el Corte

En este sentido, est claro que el uso del corte debe ser moderado a con el n de mejorar la ecacia sin por ello comprometer la claridad de nuestros programas.

7.3

Las variables annimas o

La mayor de los programas lgicos son susceptibles de incluir a o en algunas de sus clusulas variables que son irrelevantes a para el proceso de resolucin, pero cuya presencia implica o una complicacin innecesaria de tal proceso. Como muestra o tomemos el caso de la instruccin if then else considerada en o el ejemplo 7.1.5:
if_then_else(P,Q,R) :- P, !, Q. if_then_else(P,Q,R) :- R.

En efecto, tanto R en la primera clusula, como P y Q a en la segunda, aparecen una sola vez en la estructura de sus respectivas clusulas y por tanto se trata de variables a irrelevantes a nivel del proceso de unicacin, puesto que no o son incluidas en ninguna de las ecuaciones consideradas en el algoritmo 6.3.1. Sin embargo, una vez introducidas en la clusula, el intrprete lgico no siempre puede detectar su a e o irrelevancia. Como consecuencia, son asimiladas en el proceso de resolucin como una variable ms, sujeta a renombramientos, o a inclusin en las sustituciones, ... En denitiva, las variables en o cuestin slo consiguen dicultar innecesariamente el trabajo o o del intrprete, puesto que desde un punto de vista lgico su e o funcionalidad es nula. Con el objeto de evitar este tipo de situaciones, la mayor de a los intrpretes Prolog incluyen el concepto de variable annima, e o denotada . Este tipo de variable, simplemente es ignorada en el proceso de resolucin. As volviendo a nuestro ejemplo o , del predicado if then else, podr amos reescribir el programa anterior en la forma:
if_then_else(P,Q,_) :- P, !, Q. if_then_else(_,_,R) :- R.

7.3. Las variables annimas o

125

Suponiendo ahora que interrogamos a una cualquiera de las dos versiones consideradas para la denicin del predicado o if the else, con la pregunta :- if then else(fail,fail,true). la respuesta obtenida es true en los dos casos. Sin embargo, el lector puede comprobar que los correspondientes arboles de resolucin mostrados en la gura 7.6, aun siendo en esencia o los mismos, se distinguen por el n mero total de variables u locales manejadas, que es inferior en el caso del uso de variables annimas. Si bien es evidente que este ejemplo es sumamente o simple, con el n de facilitar la comprensin, el lector puede o imaginar fcilmente que un abuso innecesario en el uso de a variables que bien pudieran ser annimas disminuye la eciencia o del intrprete lgico tanto a nivel temporal como espacial. e o
{ if_then_else(fail,fail,true) } P 1 Q fail fail R1 true P 1 Q 1 R1 fail fail true { fail, !, fail } { if_then_else(fail,fail,true) } P 1 Q 1 R1 { true } fail fail true

{ fail, !, fail }

{ true }

fail

{ } true

fail

{ } true

Figura 7.6: Resolucin de :- if then else(fail,fail,true)., con y sin o variables annimas o

El ejemplo 7.1.5 no es el unico de los anteriormente mostrados que es susceptible de incluir el concepto de variable annima. o As por ejemplo, la nocin es perfectamente aplicable al o ejemplo 7.1.6 que implementaba el predicado intentar, como se ilustra en el ejemplo que sigue.

126

Control en Prolog: el Corte

Ejemplo 7.3.1 En el cdigo correspondiente al ejemplo 7.1.6, o la segunda clusula incluye un argumento cuya unicacin a o explcita es irrelevante para el proceso de resolucin. As, las o reglas a considerar pueden ser las siguientes:
intentar(Objetivo) :- Objetivo,!. intentar(_).

donde el argumento de la segunda clusula es ahora una variable a annima. 2 o

Cap tulo 8

La Negacin o
La denicin de la negacin en programacin lgica es, todav o o o o a hoy, un problema abierto. De hecho, constituye una de las muestras emblemticas de la diferencia existente entre lgica a o estricta y programacin lgica en la prctica. o o a

8.1

El predicado fail

La totalidad de los dialectos Prolog incluye un predicado predenido, en general denominado fail, que devuelve siempre fail como respuesta. La utilidad esencial de tal estructura es la de dar una posibilidad al programador de expresar el concepto de falsedad en programacin lgica. En efecto, por denicin o o o nuestros programas se construyen a partir de clusulas de Horn a y en consecuencia es imposible el armar la falsedad de nuestras armaciones. El nuevo predicado, contribuye en parte a paliar esta carencia. Los ejemplos que siguen ilustran el problema. Ejemplo 8.1.1 Se trata de implementar un programa Prolog capaz de representar el concepto inferior o igual a ... en los nmeros naturales. Para ello, podemos considerar el siguiente u conjunto de clusulas: a

127

128

La Negacin o

numero_natural(0). numero_natural(siguiente(Numero)) :- numero_natural(Numero). inferior_o_igual(0,Numero) :- numero_natural(Numero). inferior_o_igual(siguiente(Numero_1), siguiente(Numero_2) :inferior_o_igual(Numero_1,Numero_2).

cuya semntica declarativa viene indicada por el predicado a inferior o igual(Numero 1,Numero 2) que suponemos cierto si Numero1 Numero2 . 2 Ejemplo 8.1.2 Supongamos ahora, que deseamos implementar el concepto inferior a ... en los nmeros naturales. Es u obvio que gran parte del programa ser en esencia comn al a u considerado en el ejemplo 8.1.1, con una salvedad: necesitamos armar que el cero no es inferior a s mismo. El predicado fail nos permitir hacerlo. Una primera versin podra ser la dada a o por:
numero_natural(0). numero_natural(siguiente(Numero)) :- numero_natural(Numero). inferior(0,0) :- fail. inferior(0,Numero) :- numero_natural(Numero). inferior(siguiente(Numero_1), siguiente(Numero_2)) :inferior(Numero_1,Numero_2).

Sin embargo esta no es todava una implementacin correcta. o En efecto, si consideramos la pregunta :- inferior(0,0). la respuesta obtenida ser true, esto es, todo lo contrario de lo a que pretendamos. Para comprender la razn basta considerar el o correspondiente arbol de resolucin en la gura 8.1. En efecto, o la presencia del fail en la resolvente de la primera rama fuerza el retroceso, y como consecuencia entramos en la alternativa representada por la segunda clusula del predicado inferior, a lo que nos lleva a obtener una respuesta armativa. La solucin o est en cortar dicha rama, para ello bastar con incluir un corte a a justo despus de estar seguros de que los dos nmeros a comparar e u son cero, esto es, justo despus del literal de cabeza: e

8.1. El predicado fail

129

numero_natural(0). numero_natural(siguiente(Numero)) :- numero_natural(Numero). inferior(0,0) :- !, fail. inferior(0,Numero) :- numero_natural(Numero). inferior(siguiente(Numero_1), siguiente(Numero_2) :inferior(Numero_1,Numero_2).

{ inferior(0,0) } Numero fail 0

{ numero_natural(0) }

true

Figura 8.1: Resolucin de :- inferior(0,0)., sin corte o

El nuevo arbol de resolucin se muestra en la gura 8.2. 2 o


{ inferior(0,0) }

fail

Figura 8.2: Resolucin de :- inferior(0,0)., con corte o

La combinacin corte/fallo es un clsico de la programacin o a o lgica y su utilizacin es amplia. A este respecto, es interesante o o se alar que los cortes en este tipo de combinacin pueden ser n o tanto verdes como rojos. As el caso expuesto en el ejemplo 8.1.2 ,

130

La Negacin o

incluye un corte rojo, puesto que hemos visto que su eliminacin o conlleva un cambio en el signicado del programa. Ejemplo 8.1.3 En el siguiente ejemplo, implementaremos un predicado diferente(X,Y) que sea cierto cuando sus dos argumentos no sean unicables. Un posible programa capaz de resolver el problema sera el siguiente:
diferente(X,X):-!,fail. diferente(_,_).

donde la primera clusula asegura que en el caso de unicacin a o de los dos argumentos del predicado, se produzca un fallo sin posibilidad de retroceso sobre la segunda clusula que slo ser a o a accesible si los argumentos no son unicables. 2

8.2

La negacin por fallo o

Una de las formas ms extendidas de implementar la negacin a o en lgica es mediante la utilizacin del predicado fail. En este o o contexto, la utilizacin del corte y de dicho predicado, permiten o la denicin de un predicado not(P) que es cierto cuando P o no se puede demostrar y es falso en otro caso. A este tipo de negacin se le suele llamar negacin por fallo y en general no o o coincide con la denicin de negacin en lgica estricta. Adems o o o a debe utilizarse con extrema prudencia, puesto que la semntica a operacional de la implementacin prctica de dicho predicado no o a coincide con la semntica declarativa de la negacin por fallo. En a o particular, veremos que el orden en la resolucin de los objetivos o puede alterar las respuestas nales de un programa incluyendo esta implementacin. o Ante todo, intentemos razonar cul debe ser el proceso de a construccin de nuestro predicado de negacin. En principio, o o podr amos pensar en una denicin del tipo: o
not(P) :- P, fail. not(P).

que podr corresponderse a la semntica declarativa que a a constituye nuestro objetivo, a saber:

8.2. La negacin por fallo o

131

Si P es cierto, entonces devolvemos fail. En otro caso, not(P) es cierto. Sin embargo nuestro programa est lejos de conseguir este a objetivo. Para demostrarlo basta considerar la pregunta siguiente: :- not(true). En efecto, la respuesta obtenida es true. De hecho, justamente lo contrario de aquello que pretend amos. Para entender la razn o es necesario profundizar en la semntica operacional de nuestro a programa a partir del arbol de resolucin correspondiente a o nuestra pregunta, tal y como lo muestra la gura 8.3.
{ not(true) }

{ true, fail }

true

{ fail } fail

Figura 8.3: Resolucin de :- not(true)., sin corte o

La solucin es, en principio, simple. Se trata de cortar la o alternativa situada ms a la derecha en el arbol de resolucin, a o pero slo cuando P sea cierto. Esto es, colocaremos un corte o inmediatamente despus de haber vericado que P es cierto. e
not(P) :- P, !, fail. not(P).

Ahora, una vez interrogado nuestro programa con la pregunta :- not(true). su comportamiento parece ser el deseado de acuerdo con nuestra semntica declarativa, tal y como se muestra en la gura 8.4. a

132

La Negacin o

{ not(true) }

{ true, !, fail }

{ !, fail }

{ fail } fail

Figura 8.4: Resolucin de :- not(true)., con corte o

8.3

Anomal de la negacin por fallo as o

El hecho de que nuestra negacin, por construccin, devuelva o o fail cuando su argumento pueda probarse, plantea problemas serios en su utilizacin. o Ms exactamente, la semntica a a declarativa de nuestra negacin no siempre coincide con la o operacional, como mostramos en los ejemplos que siguen. Ejemplo 8.3.1 El problema planteado es el de implementar un programa capaz de respondernos acerca de las caractersticas estticas de un conjunto dado de personas. e Para ello, consideremos el conjunto de clusulas que sigue: a
igual(X,X). guapa(Luisa). guapa(Carmen). fea(Persona):-not(guapa(Persona)).

cuya semntica operacional1 es la siguiente: a


1 el

predicado igual se utilizar en las preguntas. a

8.3. Anomal de la negacin por fallo as o

133

Dos trminos son iguales, si unican. e Luisa es guapa. Carmen es guapa. Una persona es fea, si no se puede probar que es guapa. y que en el caso de la ultima clusula, tendemos a interpretar a declarativamente en la forma Una persona es fea, si no es guapa. Veremos que el olvido de este peque o matiz puede provocar n comportamientos imprevistos por el programador en el proceso de resolucin. Consideremos las tres preguntas siguientes: o :- fea(X), igual(X,Teresa). :- fea(Teresa). :- igual(X,Teresa),fea(X). En principio, podramos pensar que la semntica operacional a para las tres fuese la misma: Es Teresa fea ?. lo cual sera cierto slo si la resolucin Prolog fuese o o independiente del orden de las clusulas. En nuestro caso, a ninguna de las tres preguntas coincide en su respuesta. En efecto, las respuestas son respectivamente: fail true X Teresa Para ilustrar el porqu de este comportamiento, basta analizar e los correspondientes arboles de resolucin. Consideremos por o ejemplo el correspondiente a la primera pregunta. Tal y como se representa en la gura 8.5, el problema se presenta porque en el momento de intentar probar el objetivo guapa(Persona 1 ) la

134

La Negacin o

variable Persona1 no est instanciada, por lo que realmente no a nos planteamos la veracidad de guapa(Teresa) como en un principio pretendemos. De hecho, el problema expuesto para la resolucin de la pregunta se resuelve con la instanciacin o o Persona1 Luisa que en principio nada tiene que ver con la cuestin considerada. o
{ fea(X), igual(X, Teresa) } X Persona
1

{ not(guapa(Persona )), igual(Persona , Teresa) }


1

{ guapa(Persona 1 ), !, fail, igual(Persona 1, Teresa) } Persona Luisa

{ !, fail, igual(Luisa, Teresa) }

{ fail, igual(Luisa, Teresa) }

fail

Figura 8.5: Resolucin de :- fea(X), igual(X,Teresa). o

En el caso de la segunda pregunta, el comportamiento operacional es el expresado por el arbol de resolucin de o la gura 8.6, cuyo resultado es totalmente contrario al experimentado en la resolucin anterior. Esencialmente, ello se o debe a que ahora, la resolucin del objetivo relativo a la negacin o o

8.3. Anomal de la negacin por fallo as o

135

se efecta con un predicado que no contiene variables. En esta u situacin, la implementacin considerada para la negacin por o o o fallo se comporta como la negacin lgica clsica y el resultado o o a es el esperado a partir de nuestra base de datos, en la que Teresa no aparece como una persona guapa.

{ fea(Teresa) } Persona
1

Teresa { not(guapa(Teresa)) }

{ guapa(Teresa), !, fail }

true

fail

Figura 8.6: Resolucin de :- fea(Teresa). o

El ultimo caso considerado es ilustrativo como ejemplo de dos situaciones distintas en relacin al proceso de resolucin de un o o objetivo: 1. La inuencia del orden de resolucin de los objetivos en la o resolvente. Para ello basta ver la forma de la pregunta en relacin a la primera de las formuladas en este ejemplo. o 2. El hecho de que, respondiendo armativamente a la pregunta como en el segundo caso, aqu obtengamos adems a como respuesta una sustitucin. o Como es habitual, es suciente con centrar nuestra atencin en o el correspondiente arbol de resolucin para detectar las causas o del comportamiento observado. As, a partir de la gura 8.7 el

136

La Negacin o

lector puede observar que la causa de que la negacin funcione o como se espera es de nuevo el hecho de que su resolucin se o realiza con un predicado en el que no hay variables libres. En efecto, la variable en principio presente en dicho predicado queda instanciada una vez resuelto el objetivo igual(X,Teresa). La razn por la que nalmente obtenemos una sustitucin como o o respuesta es justamente porque en la pregunta aparecen variables libres. 2
{ igual(X, Teresa), fea(X) } X Teresa { fea(Teresa) }

{ not(guapa(Teresa)) }

{ guapa(Teresa), !, fail}

true

fail

Figura 8.7: Resolucin de :- igual(X,Teresa), fea(X). o

Como conclusin fundamental a considerar a partir del o ejemplo 8.3.1 est el hecho de que debe evitarse la resolucin a o de negaciones cuando estas contienen variables sin instanciar. La forma en que ello pueda hacerse depender en cada caso del a tipo de dialecto Prolog considerado2 . En caso de no disponer
2 por ejemplo, ciertos dialectos incluyen la posibilidad de inclusin por parte del o programador de mecanismos denominados de evaluacin perezosa que permiten no o evaluar un objetivo hasta que no se cumplan ciertas condiciones en su entorno.

8.3. Anomal de la negacin por fallo as o

137

de ninguno de estos mecanismos, el orden de evaluacin de los o objetivos es determinante tal y como hemos visto en el ultimo ejemplo 8.3.1. Ejemplo 8.3.2 Consideremos el programa dado por el siguiente conjunto de clusulas: a
soltero(Persona) :- varon(Persona), not(casado(Persona)). casado(Juan). varon(Juan). varon(Pepe).

cuya semntica declarativa es la dada por a Una persona es un soltero si no est casada y adems a a es un varn. o El lector puede vericar fcilmente que la semntica operacional a a coincide con la declarativa en este caso, as para las preguntas :- soltero(X). :- soltero(Juan). :- soltero(Pepe). obtenemos las respuestas X Pepe fail true respectivamente. Consideremos ahora un peque o cambio en el n orden de los trminos del predicado soltero, para obtener el e nuevo programa
soltero(Persona) :- not(casado(Persona)), varon(Persona). casado(Juan). varon(Juan). varon(Pepe).

138

La Negacin o

cuya semntica declarativa es la misma del anterior, puesto que a esta no vara con el orden de los trminos. Entonces en relacin e o a las mismas preguntas, las respuestas respectivas obtenidas son las siguientes: fail fail true Esto es, la primera no coincide con la obtenida para el programa anterior, ni con la semntica declarativa considerada. La razn a o vuelve a ser de nuevo el hecho de que cuando se resuelve la negacin, en el primer caso, el objetivo correspondiente contiene o una variable Persona sin instanciar. Observemos que ese no es el caso de la segunda y tercera preguntas, en las que adems el a resultado coincide con el obtenido para las mismas cuestiones en el programa anterior. 2

Cap tulo 9

Control de la Evaluacin o
En este cap tulo se va a tratar un conjunto de predicados que permiten retardar la evaluacin de los objetivos hasta que cierta o informacin que se considera necesaria est disponible. Este tipo o e de tcnicas se suele conocer bajo la denominacin de evaluacin e o o perezosa. Con ello se consigue una mejora en el rendimiento, a la vez que proporciona un mecanismo que facilita la denicin o del comportamiento requerido.

9.1

La primitiva freeze

Cuando se trabaja con Prolog, en ciertas ocasiones es conveniente retrasar el proceso de evaluacin hasta que se o disponga de toda la informacin que se precisa para llevar a o cabo con xito el proceso de resolucin. Esto es, se trata de e o asegurar que ciertas variables involucradas en el proceso estn e instanciadas en el momento de proceder a la evaluacin. Para o ello se utiliza la primitiva freeze, que no se encuentra disponible en todas las implementaciones de Prolog1 . Cuando est disponible, podemos utilizar freeze para a asegurar la correccin de los programas en aquellos casos en los o que se sabe a priori que el proceso de resolucin de un objetivo o
1 la

primitiva freeze est incluida en la sintaxis de Prolog II [24]. a

139

140

Control de la Evaluacin o

no podr terminar con xito si alguna de las variables no est a e a instanciada. Ejemplo 9.1.1 Se trata de construir un predicado que realice la suma de dos valores. Para ello podramos utilizar directamente el predicado no lgico is, obteniendo la siguiente denicin de o o suma: suma(X,Y,Z) :- Z is X + Y. El problema surge cuando suma forma parte de la cola de una clusula, puesto que se puede dar el caso de que el intrprete a e Prolog intente resolverlo antes de que las variables X y Y hayan sido instanciadas. En tal caso, se obtendr fail como resultado a de la evaluacin de la suma. o El problema tendra fcil solucin si existiese algn modo de a o u indicar que para realizar la suma es preciso esperar a que tanto X como Y hayan tomado valores. Esta es la tarea encomendada a freeze. La regla: sumar(X,Y,Z) :- freeze(X,freeze(Y,suma(X,Y,Z))). indica que si las variables X y Y no estn instanciadas se proceda a a congelar la evaluacin de sumar hasta que dichas variables se o instancien durante el proceso de resolucin de la clusula en o a cuya cola est incluida la aparicin de suma. 2 a o Ms exactamente, cuando se debe satisfacer un objetivo de a la forma freeze(Variable,Objetivo), donde Variable es una variable y Objetivo es un objetivo, hay que considerar los siguientes casos: 1. Si Variable est instanciada, entonces se satisface a Objetivo de la forma usual, esto es, como si la primitiva freeze no existiese. 2. Si Variable no est instanciada: a El objetivo completo freeze(Variable,Objetivo) se satisface, por lo que la evaluacin de los siguientes o objetivos proseguir normalmente. a

9.1. La primitiva freeze

141

La unicacin de Objetivo se retrasa hasta que o Variable sea instanciada. Hasta que esto ocurra, se dice que la variable Variable est congelada. a A continuacin se muestra cmo la utilizacin de la primitiva o o o freeze nos puede ayudar a resolver los problemas que surgen como consecuencia de las anomal en la negacin por fallo que as o mostramos en el cap tulo 8. Ejemplo 9.1.2 Retomando el caso mostrado en el ejemplo 8.3.2, en el cual tratbamos de establecer un predicado que a indicase si una persona estaba soltera, podemos reescribir el conjunto de reglas de la siguiente manera:
soltero(Persona) :- freeze(Persona,not(casado(Persona))), varon(Persona). casado(Juan). varon(Juan). varon(Pepe).

cuya semntica declarativa contina siendo la misma que a u entonces: Una persona es un soltero si no est casada y adems a a es un varn o Sin embargo, en este caso el lector puede comprobar que la semntica operacional coincide con la declarativa a independientemente del orden de los trminos del predicado e soltero. Por tanto, al formular las preguntas :- soltero(X). :- soltero(Juan). :- soltero(Pepe). obtendremos las respuestas X Pepe fail true

142

Control de la Evaluacin o

La razn de este comportamiento estriba en el hecho de que o la resolucin de la negacin se retarda hasta el momento en o o que la variable Persona est instanciada, con lo cual, si en la e pregunta se utiliza una variable, se resolver primero el trmino a e correspondiente a varon.2 Un caso distinto se plantea con el del ejemplo 8.3.1, puesto que al estar constituida la cola de la clusula encabezada por a fea(Persona) por un unico trmino, no es posible congelarlo e en espera de que el proceso de resolucin instancie la variable o Persona. En este caso la solucin viene dada por la utilizacin o o de declaraciones wait.

9.2

La declaracin wait o

Adems del mecanismo de la congelacin de variables, en a o 2 ciertas versiones de Prolog existe la posibilidad de establecer de antemano el comportamiento del proceso de evaluacin de o predicados seg n el estado en que se encuentren las variables u involucradas. Para ello se utiliza la declaracin wait. o Los predicados que no poseen declaraciones wait se comportan como predicados Prolog estndar, mientras que a aquellos sobre los que se ha aplicado wait pueden ver retardada su evaluacin. o Dado un predicado P con n variables, la declaracin wait correspondiente tendr la forma wait o a P (s1 , s2 , . . . , sn ), donde los si pueden tomar el valor 1 o 0. Su signicado es el siguiente: Si si es 0, entonces es preciso que la variable que ocupa la posicin i se encuentre instanciada en el momento de o proceder a la evaluacin del predicado P . Si no es este o el caso, la evaluacin de dicho predicado se congela hasta o el momento en que el proceso de resolucin proporcione o un valor a dicha variable, t picamente como resultado de
2 como

en el caso de Mu-Prolog [19].

9.2. La declaracin wait o

143

la evaluacin de alguno de los restantes trminos de la o e clusula. a Si si es 1, entonces en proceso de resolucin, en lo o concerniente a la variable que ocupa la posicin, se realizar o a siguiendo el formalismo estndar de Prolog. a Ejemplo 9.2.1 Veamos ahora cmo podemos solucionar los o ploblemas planteados en el ejercicio 8.3.1 mediante la utilizacin o de declaraciones wait. Recordemos que partamos del conjunto de clusulas a
igual(X,X). guapa(Luisa). guapa(Carmen). fea(Persona) :- not(guapa(Persona)).

y que la semntica declarativa de la ultima regla era a Una persona es fea, si no se puede probar que es guapa El problema surga al realizar las preguntas :- fea(X),igual(X,Teresa). :- igual(X,Teresa),fea(X). para las que obtenemos dos respuestas distintas, ya que el diferente orden de evaluacin provoca variaciones en la o instanciacin de las variables. Concretamente, el problema o surge cuando se evala primero el predicado fea, ya que su u variable no puede ser instanciada. Utilizando la declaracin o wait fea(0). antes de denir el predicado fea, retardamos la evaluacin de o fea hasta que su variable est instanciada, hecho que ocurre e cuando se lleva a cabo la evaluacin del predicado igual.2 o

144

Control de la Evaluacin o

Como se ha podido ver, tanto la primitiva freeze como la declaracin wait proporcionan un medio para evitar o incongruencias declarativo/operacionales, a la vez que se mantiene una estructura legible para los programas.

Parte IV

Programacin Lgica o o

145

Cap tulo 10

Las Listas
Si bien los lenguajes de programacin lgica en general, y Prolog o o en particular, no han sido optimizados para el tratamiento de listas, estas constituyen un magn co campo de experimentacin o para las tcnicas de programacin lgica, en especial para el e o o concepto de unicacin. Comenzaremos por denir lo que es una o lista. Esencialmente, se trata de estructuras de almacenamiento de datos con dos caracter sticas que las diferencian de otros tipos de estructuras: Una lista es una estructura de datos dinmica, esto es, su a tama o puede variar en el curso de la sesin de trabajo. n o Es adems una estructura de tipo secuencial. Esto es, para a acceder a un elemento contenido en una lista es necesario recorrer previamente todos los que le preceden. En nuestro caso, una lista se representar por la sucesin de sus a o elementos separados por comas, y encerrada entre corchetes. As por ejemplo, la lista cuyo primer elemento es a, cuyo segundo elemento es b y cuyo tercer elemento es c, se representar en la a forma: [a,b,c] La implementacin f o sica de la estructura de datos lista se centra en el concepto de clula o doblete. Elemento m e nimo de una lista, la clula, est compuesta de dos partes, el car y el cdr: e a
147

148

Las Listas

El car de una clula se corresponde con el contenido de la e direccin de memoria de dicha clula. Esto es, el car de o e una lista es su primer elemento. El cdr de una clula es el contenido de la direccin siguiente e o a la representada por el car. Esto es, el cdr de una lista es la lista una vez eliminado su primer elemento. En el caso de Prolog, la estructura de clula se representa e mediante el operador | en la forma indicada en la gura 10.1, donde el s mbolo [ ] representa el n de lista y habitualmente se conoce con el nombre1 de lista vac a.

[ ]

[ ]

Figura 10.1: Representacin interna de la lista [a,[b],c,d] o

Ello permite que consideremos dos tipos de representacin o Prolog para una misma lista, una enumerando sus elementos separados por comas y otra utilizando el operador |. As por ejemplo, la lista [a,b,c] puede representarse tambin en las formas: e [a|[b,c]] [a,b|[c]] [a,b,c|[ ]]
1 totalmente

inadecuado.

10.1. Denicin del tipo lista o

149

10.1

Denicin del tipo lista o

Si bien el tipo de dato lista suele estar predenido en los intrpretes Prolog, nosotros podr e amos denirlo fcilmente a a partir de los datos expuestos sobre su naturaleza y la forma en que suponemos la vamos a representar notacionalmente. Una posible implementacin ser la siguiente: o a
lista([ ]). lista([_|Cdr]) :- lista(Cdr).

cuya semntica declarativa viene dada por: a La lista vaca es una lista. Un conjunto de elementos entre corchetes es una lista, si una vez eliminado el primero, lo que queda contina siendo una lista. u que como ya veremos no coincide plenamente con la semntica a operacional del programa considerado.

10.2

Operaciones fundamentales sobre listas

En este apartado, comentaremos mediante ejemplos cmo se o pueden implementar las operaciones fundamentales para el manejo de listas, y de hecho deniremos el n cleo de un peque o u n intrprete Lisp2 , en Prolog. El objetivo es, ante todo, prctico e a y nos servir para poner en evidencia algunos problemas que a sern tratados ms tarde con cierta profundidad. Asimismo, a a esperamos adentrar al lector en el manejo de las listas, una estructura de trabajo especialmente util. Finalmente, y para aquellos lectores ya familiarizados con el manejo de lenguajes funcionales o seudofuncionales como Lisp, este apartado marcar a sin duda una sutil l nea de separacin entre ambas concepciones o de la programacin declarativa. o Es en este tipo de programas, simples y potentes a la vez, donde realmente se dise a el estilo de programacin propio de n o
2 el

lenguaje orientado a listas por excelencia.

150

Las Listas

Prolog. En efecto, no debemos centrar nuestra atencin en o razonamientos operacionales como en los lenguajes clsicos, al a menos mientras ello sea posible, sino intentar aplicar en toda su potencia el mecanismo de unicacin de las variables lgicas. o o Mecanismo que, no lo olvidemos, es ofrecido de forma gratuita por el intrprete. Comenzaremos por las dos funciones bsicas e a de acceso a los elementos de una lista: los predicados car y cdr. Ejemplo 10.2.1 Se trata pues de denir los predicados que nos den acceso al primero y al resto de los elementos de una lista, respectivamente. Como ya hemos comentado, la consideracin o del mecanismo de unicacin ser fundamental. Tomemos las o a deniciones de predicado:
car([Car|_], Car). cdr([_|Cdr], Cdr).

cuya semntica declarativa es la que sigue: a El primer elemento de una lista es el car de la misma. Todo aquello que sigue al primer elemento de una lista es el cdr de la misma. Observemos que para escribir nuestro programa slo hemos o tenido en cuenta la notacin utilizada para representar una lista, o y sobre todo, el mecanismo de unicacin que nos asegura que o las respuestas al primer predicado sern instancias de la variable a Car, y las del segundo instancias de Cdr. Tambin es curioso hacer se alar que si bien Car y Cdr son e n variables que aparecen una sola vez por clusula, no tendra a sentido el considerarlas como variables annimas puesto que son o necesarias para obtener la respuesta deseada en cada caso. 2 En este punto es importante se alar que los predicados car y n cdr no sern nunca usados tal y como han sido denidos en el a ejemplo 10.2.1. En efecto, ambos conceptos son directamente aplicables mediante el concepto de unicacin. En ese sentido, o el anterior ejemplo tiene slo un valor testimonial tal y como se o muestra en el siguiente.

10.2. Operaciones fundamentales sobre listas

151

Ejemplo 10.2.2 El problema consiste ahora en denir un predicado de la forma miembro(Elemento, Lista) que sea cierto cuando el objeto Elemento pertenezca a la lista Lista. La idea es de hecho muy simple y sirve de modelo a buen nmero u de programas Prolog para el tratamiento de listas. Se trata en resumen de: 1. Ver si Elemento unica con el car de Lista, en cuyo caso el problema tendr una respuesta armativa. a 2. En caso contrario, realizar una llamada recursiva sobre el predicado miembro con el cdr de Lista. Ello constituye la semntica declarativa de nuestra denicin a o para el predicado en cuestin, que podemos traducir en forma de o dos clusulas: a
miembro(Elemento,[Elemento|_]) :- !. miembro(Elemento,[_|Cdr]) :- miembro(Elemento,Cdr).

Es importante subrayar ciertos detalles de la implementacin, o en relacin a su semntica operacional, que adems no coincide o a a plenamente con la declarativa, aunque en este caso ello ha sido una decisin nuestra con objeto de mejorar la eciencia, como o se comenta inmediatamente: La inclusin de un corte en la primera de las clusulas o a tiene como objetivo evitar la duplicidad de soluciones en preguntas en las que Elemento aparece varias veces en el cuerpo de Lista. Se trata por tanto de un corte verde. La inclusin de variables annimas tiene por unico objetivo o o facilitar el proceso de resolucin y ms exactamente el de o a unicacin. o Los predicados car y cdr denidos en el ejemplo 10.2.1 no son utilizados explcitamente, si bien ambos conceptos son aplicados implcitamente mediante unicacin. o

152

Las Listas

Es importante indicar que no todas las preguntas posibles obtendrn la respuesta esperada3 , as por ejemplo a :- miembro(X,[1,2,3]). obtiene como unica respuesta X Elemento1 1 cuando en principio todos los elementos de la lista considerada seran vlidos. En este caso, la razn del desajuste es simple, a o tal y como se muestra en la gura 10.2. En efecto, el corte
{ miembro(X, [1, 2, 3]) } X Elemento Elemento 1 1 {!}

true

Figura 10.2: Resolucin de :- miembro(X,[1,2,3])., con corte o

es la causa ultima de este comportamiento, puesto que corta toda posibilidad de bsqueda de otras soluciones. Ello podra u plantear la supresin del mismo, lo cual resolvera este problema o en particular, pero planteara el de la duplicidad de soluciones con preguntas del tipo :- miembro(1,[1,2,1,3,1]). en caso de retroceso, tal y como habamos comentado en un principio. Esto es, sacricamos la completud de nuestro programa en favor de su eciencia. Ello ilustra la confrontacin, o habitual, entre eciencia y congruencia declarativo/operacional
3 de

nuevo una incongruencia declarativo/operacional.

10.2. Operaciones fundamentales sobre listas

153

en los programas Prolog. La decisin nal slo depende del o o criterio del programador en cada caso. Sin embargo, no todo son limitaciones en la aplicacin prctica de la programacin o a o lgica. El mecanismo de unicacin es tan simple como util, o o y la potencia de clculo que de l se deriva es con frecuencia a e arrolladora. Sirva como ejemplo el de la pregunta :- miembro(X,Y). que interroga a nuestro programa acerca del conjunto de listas que incluyen a un elemento arbitrario en su estructura. Est a claro que dicho conjunto es innito, aunque nuestras dos lneas de cdigo son ms que sucientes para obtener la respuesta o a adecuada:
X Elemento1 Y [Elemento1 | ]

X Y

Elemento 1 [ Elemento | _ ]
1

{ miembro(X, Y) }

X Y

Elemento 1 [ _ | Cdr ]
1

{ }

{ miembro(Elemento 1, Cdr1 ) } Elemento Elemento 2 1 Cdr 1 [ Elemento 2 , _ ] Elemento 2 Elemento 1 Cdr 1 [ _ | Cdr2 ] { miembro(Elemento , Cdr ) }
2 2

true

{ }

true

Figura 10.3: Resolucin de :- miembro(X,Y)., sin corte o

Evidentemente faltan respuestas, pero ello no es ms que a una consecuencia del uso del corte con objeto de acelerar la resolucin. En efecto, considerando la versin sin corte o o
miembro(Elemento,[Elemento|_]). miembro(Elemento,[_|Cdr]) :- miembro(Elemento,Cdr).

154

Las Listas

el conjunto de respuestas obtenido para la misma pregunta es el deseado:


X Elemento1 Y [Elemento1 | ] X Elemento1 Y [ , , Elemento1 | ] ... X Elemento1 Y [ , Elemento1 | ] X Elemento1 Y [ , , , Elemento1 | ]

tal y como muestra la gura 10.3. 2 En este punto, ser conveniente que el lector se plantease a cuntas l a neas de cdigo de un lenguaje imperativo ser o an necesarias para obtener la potencia de clculo descrita en los a ejemplo anteriores. La respuesta, claricadora por s sola, constituye una de las razones por las que, a pesar de todas las limitaciones prcticas de los lenguajes lgicos actuales, a o la investigacin en lo que se reere al desarrollo de nuevos o esquemas de interpretacin [2, 3, 4, 6, 11, 23, 25], e incluso o de compilacin [14, 15, 26], sigue concentrando los esfuerzos de o buen n mero de investigadores. u Casos como el planteado en el ejemplo 10.2.2, en los que la aplicacin de la unicacin se traduce en el desarrollo o o de potencialidades desconocidas en otros formalismos, son habituales en programacin lgica. De hecho, si bien es una o o completa exageracin armar que los algoritmos de resolucin o o lgica traducen el conjunto de procesos que conforman el o pensamiento humano, el lector convendr en que este estilo de a programacin conjuga la simplicidad de razonamiento con un o incremento del espectro aplicativo. Con el n de subrayar la importancia del concepto de unicacin en la denicin de la semntica de un programa o o a lgico, introduciremos nuevos ejemplos en los que el n mero de o u variables en juego se incremente de forma gradual. Este es un aspecto importante a recordar: Las semnticas declarativa y operacional de un a

10.2. Operaciones fundamentales sobre listas

155

programa lgico dependen en gran parte del proceso o de unicacin aplicado en la resolucin. o o Ejemplo 10.2.3 El ejemplo a considerar ahora es la implementacin de un predicado concatenar(Lista 1 ,Lista2 , o Resultado) describiendo la concatenacin de listas Lista 1 y o Lista2 para obtener la nueva lista resultado. La idea no es otra que la de recorrer la primera lista hasta el nal, para luego concatenarle los elementos de la segunda. Formalmente, la implementacin podra ser la siguiente: o
concatenar([],Lista,Lista). concatenar([Car|Cdr],Lista,[Car|Resultado]) :concatenar(Cdr,Lista,Resultado).

cuya semntica declarativa puede ser a La concatenacin de la lista vac con otra lista o a cualquiera, es esta ultima. La concatenacin de una lista [Car | Cdr] con otra o lista arbitraria Lista es el resultado de concatenar el Car al resultado Resultado previamente obtenido de la concatenacin de Cdr con Lista. o Tambin en este caso podemos constatar la potencia de e clculo imprimida por la aplicacin de la unicacin a nuestro a o o programa, que describe en apenas dos lneas la concatenacin de o listas. Sirva como muestra el comportamiento del programa ante una pregunta de la forma :- concatenar(X,Y,Z). obteniendo como respuestas
X [] Y Lista1 Z Lista1 X [Car1 ] Y Lista1 Z [Car1 | Lista1 ]

X [Car1 Car2 ] Y Lista1 Z [Car1 , Car2 | Lista1 ] ...

X [Car1 Car2 Car3 ] Y Lista1 Z [Car1 , Car2 , Car3 | Lista1 ]

156

Las Listas

De nuevo sera interesante que el lector intentase trasladar la semntica declarativa considerada, al caso de un lenguaje a imperativo para constatar que el mecanismo de unicacin o evita de forma elegante la inclusin de estructuras de control o condicionales tan corrientes en ese tipo de lenguajes. 2 El objetivo ahora es el de introducir distintas tcnicas e de programacin, haciendo hincapi en sus ventajas e o e inconvenientes. Esto es, una vez introducida la esencia del estilo de programacin lgico, que pudiramos denir o o e como orientado por la unicacin y naturalmente recursivo, o modelaremos estas tcnicas bsicas justicando en cada caso e a su utilizacin. Para ello consideraremos un mismo problema o que ser tratado desde distintas perspectivas, dando lugar a a diferentes implementaciones. Ms exactamente, la cuestin a o planteada ser la inversin de una lista en su primer nivel de a o profundidad. As por ejemplo, dada la lista [1, [2, 3], [4, 5], 6] pretendemos invertirla en la forma [6, [4, 5], [2, 3], 1] El predicado ser notado invertir(Lista,Inversa) que a consideraremos se vericar si Inversa es la lista inversa al a primer nivel de profundidad de Lista. Ejemplo 10.2.4 Trataremos en este ejemplo de dar una primera aproximacin al problema de la inversin de listas. o o En este sentido, un algoritmo fcilmente comprensible sera el a siguiente:
invertir([ ],[ ]). invertir([Car|Cdr],Inversa) :invertir(Cdr,Inverso_Cdr), concatenar(Inverso_Cdr,[Car],Inversa).

cuya semntica declarativa viene dada por a

10.2. Operaciones fundamentales sobre listas

157

El resultado de invertir la lista vac es la misma lista a vac a. Para invertir una lista [Car|Cdr] es suciente con invertir Cdr pegndole luego Car. a A diferencia de ejemplos anteriores como el 10.2.2 o el 10.2.3, el uso del corte en la primera clusula no es aqu necesario para a evitar la duplicacin de soluciones. Ello es debido a que si una o lista unica con la lista vaca, no lo har con una lista no vaca 4 . a Si bien el programa descrito parece cumplir su cometido, es ineciente a ms no poder. De hecho, estamos recorriendo la a lista a invertir dos veces completamente, y varias parcialmente. Ello es debido a que el predicado recursivo invertir, que recorre totalmente su primer argumento, incluye una llamada a otro predicado recursivo concatenar que como hemos visto en el ejemplo 10.2.3, recorre totalmente el primero de sus argumentos para concatenarlo con el segundo. En consecuencia, podramos decir que nuestra primera denicin de invertir es un tanto o inocente y despreocupada. Tendremos que renarla. 2 A continuacin pasamos a describir la operacin aplanar o o sobre estructuras de tipo lista. Fundamentalmente, se tratar a de eliminar todas las sublistas de una lista dada. As , consideraremos que el resultado de aplanar la lista [1,[2],[3,[4]]] es la nueva lista [1,2,3,4]. En este caso, utilizaremos dos predicados no lgicos, atomic y \ ==, que sern descritos en o a detalle ms adelante. a Ejemplo 10.2.5 Proponemos implementar el aplanamiento de una lista mediante el predicado aplanar(Lista,Resultado) que supondremos cierto cuando Resultado sea el resultado de aplanar la lista Lista. Para ello consideraremos la semntica a declarativa siguiente:
4 lo

cual subraya el hecho de que una lista vac no es realmente una lista. a

158

Las Listas

El resultado de aplanar la lista vac es la misma lista a vac a. El resultado de aplanar un elemento atmico, es una o lista formada por ese unico elemento. El resultado del aplanamiento de una lista arbitraria es el de concatenar el aplanamiento de su car con el aplanamiento de su cdr. que formalmente podemos traducir en las tres clusulas a siguientes
aplanar([],[]). aplanar(Atomo,[Atomo]) :- atomic(Atomo), Atomo \== []. aplanar([Car|Cdr], Resultado) :aplanar(Car,Car_aplanado), aplanar(Cdr,Cdr_aplanado), concatenar(Car_aplanado,Cdr_aplanado,Resultado).

donde hemos utilizado dos predicados no lgicos, que pasamos a o describir de forma breve: atomic(X) es cierto si el argumento X es un atomo. X \ == Y es cierto si los argumentos X y Y no estn a instanciados a un mismo objeto. Es preciso aclarar el signicado, en principio contradictorio, de la segunda de las clusulas en la denicin del predicado a o aplanar. En efecto, el hecho de que exijamos la generacin o de una lista en el caso del aplanamiento de un objeto atmico o permite garantizar en todos los casos el sentido de la llamada a concatenar en la clusula recursiva. 2 a Otro ejemplo de funcin esencial en el manejo de listas es el o clculo de su longitud, que pasamos a detallar inmediatamente. a En esta ocasin, y para subrayar la potencia del concepto de o unicacin, implementaremos una versin del predicado que o o calcula la longitud de una lista y que considera unicamente tcnicas lgicas. A este respecto, es conveniente recordar que e o por el momento el concepto de operacin aritmtica tradicional o e no ha sido contemplado en este texto.

10.2. Operaciones fundamentales sobre listas

159

Ejemplo 10.2.6 Vamos ahora a considerar que el predicado longitud(Lista,Longitud) es cierto cuando Longitud sea la longitud de la lista Lista. Una vez se alada la n representacin notacional, la semntica declarativa es en este o a caso especialmente simple. En efecto: La longitud de la lista vac es cero. a La longitud de una lista [Car|Cdr] es igual al valor del n mero natural siguiente al de la longitud de Cdr. u que podemos traducir en las dos clusulas que siguen a
longitud([],0). longitud([Car|Cdr],siguiente(Longitud)) :longitud(Cdr,Longitud).

2 Ejemplo 10.2.7 Abordamos en este ejemplo el problema de la duplicacin de listas. Se trata de implementar un predicado o duplicar(Lista, Duplicacin) que sea cierto slo en el caso o o en el que Duplicacin sea el resultado de concatenar la lista o Lista consigo mismo. Una posible utilizacin sera o :- duplicar([1,2], X). para la que deberamos obtener como respuesta X [1, 2, 1, 2] Claramente, una posible solucin pasara por usar directamente o el predicado concatenar anteriormente denido en el ejemplo 10.2.3. Sin embargo, y por razones exclusivamente didcticas, no lo usaremos. En ese caso, una posible solucin es a o la dada por el programa:
duplicar(Lista,Dup) :- duplicar_aux(Lista,Lista,Dup). duplicar_aux([],Lista,Lista). duplicar_aux([Car|Cdr],Lista,[Car|Duplicado_Cdr]) :duplicar_aux(Cdr,Lista,Duplicado_Cdr).

cuya semntica declarativa es obvia. 2 a

160

Las Listas

10.3

Operaciones sobre conjuntos

Como ejemplo recapitulatorio de esta seccin dedicada al o tratamiento de listas, proponemos la implementacin del o concepto de conjunto as como de las operaciones fundamentales que tiene asociadas: inclusin, unin, interseccin y producto o o o cartesiano. 10.3.1 El tipo conjunto

Para comenzar, debemos formalizar la denicin del tipo o conjunto. Ello implica dos tareas complementarias: 1. El dise o de una estructura de datos que represente al n conjunto. 2. La implementacin de una denicin de tipo, que verique o o sobre la estructura del apartado anterior si se cumplen o no las condiciones exigidas al conjunto. En relacin al primer punto, convendremos en representar un o conjunto mediante una lista en la que no aparezcan elementos repetidos. La implementacin exigida en 2. queda recogida en o la denicin del predicado o conjunto(Lista) que ser cierto si Lista verica que no contiene elementos a repetidos. Anal ticamente la implementacin se reduce a las o tres clusulas siguientes: a
conjunto([]). conjunto([Car|Cdr]) :- miembro(Car,Cdr),!,fail. conjunto([_|Cdr]) :- conjunto(Cdr).

donde el predicado miembro es el mismo denido en el ejemplo 10.2.2 y la semntica declarativa viene dada por: a La lista vaca representa al conjunto vaco. Si el primer elemento, Car, de una lista [Car|Cdr]

10.3. Operaciones sobre conjuntos

161

aparece repetido en su Cdr, entonces la lista no representa a un conjunto. Si el primer elemento, Car, de una lista [Car|Cdr] no aparece repetido en su Cdr, entonces la lista representar a un conjunto si dicho Cdr no contiene a elementos repetidos. El uso del corte en la segunda de las clusulas se justica a por el hecho de que es necesario evitar un posible retroceso sobre la tercera clusula cuando el Car no aparezca en el Cdr. a Dicho retroceso es forzado en el momento de la ocurrencia del predicado fail. Evidentemente se trata de un corte rojo. 10.3.2 La unin o

El siguiente paso ser la implementacin de la operacin unin a o o o de conjuntos. Si bien dicha operacin se suele considerar para un o n mero arbitrario de argumentos, en nuestro caso y con el n de u simplicar la exposicin, nos restringiremos al caso de la unin o o de dos conjuntos. Para ello, implementaremos el predicado union(Conjunto 1,Conjunto 2,Union) que ser cierto si Union es el resultado de la unin de a o los conjuntos Conjunto 1 y Conjunto 2. Anal ticamente, consideraremos el programa dado por las tres clusulas que a siguen
union(Conjunto,[],Conjunto). union(Conjunto,[Car|Cdr],Union_con_Cdr) :miembro(Car,Union_con_Cdr), union(Conjunto,Cdr,Union_con_Cdr), !. union(Conjunto,[Car|Cdr],[Car|Union_con_Cdr]) :union(Conjunto,Cdr,Union_con_Cdr).

cuya semntica declarativa viene dada por: a La unin de un conjunto cualquiera y el conjunto o vaco, da como resultado el primer conjunto.

162

Las Listas

La unin de un conjunto con otro de la forma o [Car|Cdr], da como resultado el mismo que el de la unin con Cdr, en el caso en el que Car sea un o elemento de la unin de dicho conjunto con Cdr. o La unin de un conjunto con otro de la forma o [Car|Cdr], da como resultado [Car|Union con Cdr] donde Union con Cdr es la unin con Cdr, en el caso o en el que Car no sea un elemento de Union con Cdr. La consideracin del corte en la segunda de las clusulas o a viene justicada por la necesidad de cortar las posibilidades de retroceso cuando Car sea un elemento del resultado de la unin de Conjunto y Cdr. En este sentido, es necesario recordar o que la ultima de las clusulas slo tiene sentido cuando Car no a o pertenece a dicha unin. Se trata en denitiva de un nuevo caso o de corte rojo. 10.3.3 La inclusin o

En relacin a la operacin inclusin de conjuntos, la o o o implementacin es muy sencilla y se limita a la consideracin de o o un recorrido recursivo de la lista representando al conjunto cuya inclusin se desea vericar, donde en cada llamada recursiva o se aplicar un test de pertenencia sobre los elementos del a otro conjunto. Anal ticamente, las dos clusulas siguientes son a sucientes:
inclusion([Car|Cdr],Conjunto) :- miembro(Car,Conjunto), inclusion(Cdr,Conjunto). inclusion([],Conjunto).

donde miembro es el predicado anteriormente denido en el ejemplo 10.2.2. 10.3.4 La interseccin o

Para la implementacin de la operacin interseccin de o o o conjuntos, podr amos hacer la misma consideracin que en el o caso de la unin. Esto es, para simplicar la notacin del o o

10.3. Operaciones sobre conjuntos

163

programa slo consideraremos el caso de la interseccin de o o dos conjuntos. Ello no supone, en cualquier caso, ning n u tipo de restriccin real, ni prdida de generalidad. Para ello o e consideraremos el predicado interseccion(Conjunto 1,Conjunto 2,Interseccion) que ser cierto si Interseccion es el resultado de la interseccin a o de los conjuntos Conjunto 1 y Conjunto 2. Desde un punto de vista anal tico, consideraremos el siguiente conjunto de clusulas a
interseccion([Car|Cdr],Conjunto,[Car|Inter]) :miembro(Car,Conjunto),!, interseccion(Cdr,Conjunto,Inter). interseccion([_|Cdr],Conjunto,Inter) :interseccion(Cdr,Conjunto,Inter). interseccion([],Conjunto,[]).

cuya semntica declarativa bien pudiera ser la siguiente: a El resultado de la interseccin de un conjunto de la o forma [Car|Cdr] con un conjunto arbitrario, es igual a la interseccin de este con Cdr ms Car, cuando Car o a pertenece al mismo. El resultado de la interseccin de un conjunto de o la forma [Car|Cdr] con un conjunto arbitrario, es igual a la interseccin de este con Cdr, cuando Car o no pertenece al mismo. La interseccin del vaco con cualquier conjunto da o como resultado el vaco. Es tambin importante se alar la consideracin de variables e n o annimas en el caso de la segunda clusula. Ello se justica o a por el hecho de que el car del primer argumento no aparece en ning n otro lugar de la clusula. Esto indica su absoluta u a inutilidad al nivel del proceso de resolucin, como ya hab o amos comentado en la seccin 7.3. o De forma anloga a implementaciones anteriores, el corte de a la primera clusula es un corte rojo cuya utilizacin se justica a o por el hecho de que se deben evitar posibles retrocesos sobre la segunda clusula cuando Car pertenezca a Conjunto. a

164

Las Listas

10.3.5

El producto cartesiano

La ultima operacin sobre conjuntos que vamos a tratar es el o producto cartesiano de dos conjuntos. Para ello consideraremos el predicado cartesiano(Conjunto 1,Conjunto 2,Cartesiano) que ser cierto cuando Cartesiano sea el producto cartesiano a de los conjuntos Conjunto 1 y Conjunto 2. Anal ticamente, el programa viene dado por las clusulas siguientes a
cartesiano([],Conjunto,[]). cartesiano([Car|Cdr],Conjunto,Resultado) :linea(Car,Conjunto,Linea), cartesiano(Cdr,Conjunto,Resto), concatenar(Linea,Resto,Resultado). linea(Elemento,[],[]). linea(Elemento,[Car|Cdr],[[Elemento,Car]|Resto]) :linea(Elemento,Cdr,Resto).

cuya semntica declarativa viene dada por: a El producto cartesiano del conjunto vaco y cualquier otro, es el mismo conjunto vaco. El producto cartesiano de un conjunto de la forma [Car|Cdr] con otro conjunto, es el resultado de concatenar el resultado del producto cartesiano de Cdr con dicho conjunto y a cuyo resultado concatenamos la lnea del cartesiano correspondiente a Car. La lnea correspondiente a un elemento arbitrario es la vaca si el conjunto por el que realizamos el producto es el vaco. En otro caso, el conjunto tiene la forma [Car|Cdr] y para calcular la lnea resultante es suciente con a adir el par [Elemento|Car] a la lnea resultante del n producto de Elemento por Cdr.

Cap tulo 11

Tcnicas de Programacin e o
El problema planteado en el anterior ejemplo 10.2.4, no es una situacin aislada, sino bastante com n entre los programadores o u inexpertos para los que la mxima a Si el ordenador lo hace, es que necesariamente el algoritmo es rpido. a es vlida, lo cual supone una velocidad innita del ordenador ... a grave error. En efecto, la aplicacin de la recursividad no debe o ser ciega y deber estar supeditada a criterios de complejidad a algor tmica, al menos cuando la aplicacin a desarrollar exija o un m nimo de eciencia tanto temporal como espacial bien por la complejidad de la misma, bien por la escasez de los recursos disponibles. Ello ser objeto de un estudio ms detallado, pero a a por el momento nos limitaremos a mostrar que no todos los problemas exigen el uso de la recursividad y que esta puede, a veces, ser eliminada si ello fuese requerido.

11.1

Los acumuladores

Una tcnica bastante extendida para la eliminacin de la e o recursividad es la del uso de los denominados acumuladores. Esencialmente se trata de utilizar una variable que se inicializa a un conjunto vac para luego a adirle en cada llamada recursiva o n
165

166

Tcnicas de Programacin e o

la parte de la solucin construida en dicha llamada. Ello permite o en muchos casos eliminar las situaciones de doble recursividad como la comentada con invertir y concatenar, tal y como mostraremos inmediatamente. Ejemplo 11.1.1 Aplicaremos la tcnica de los acumuladores e para eliminar la llamada al predicado concatenar en la denicin de invertir del ejemplo 10.2.4. Consideremos esta o nueva denicin del predicado invertir: o
invertir(Lista, Inversa) :- invertir(Lista,[ ],Inversa). invertir([ ],Acumulador,Acumulador). invertir([Car|Cdr],Acumulador,Inversa) :invertir(Cdr,[Car|Acumulador],Inversa).

cuya semntica declarativa es la siguiente: a Invertir una lista seg n el predicado invertir/2 u equivale a invertirla con el predicado invertir/3, con un acumulador inicial que es la lista vac a. El resultado de invertir una lista vac con un a acumulador inicial dado, es este mismo acumulador. El resultado de invertir una lista [Car|Cdr] con un acumulador inicial dado, es igual al resultado de invertir Cdr con un nuevo acumulador que es el resultado de a adir Car en cabeza del anterior n acumulador. La semntica operacional es idntica a la del cdigo del a e o ejemplo 10.2.4, si bien la complejidad espacial y temporal es considerablemente inferior en la nueva versin. 2 o Es importante observar que el uso del acumulador es en este programa transparente para el usuario. Ello facilita su utilizacin y hace el cdigo ms elegante. Por otro lado, y o o a en relacin a nuestro objetivo inicial, es evidente que hemos o eliminado la llamada al predicado concatenar y con ello los recorridos in tiles de nuestra lista argumento a invertir. u Siguiendo en la misma tnica, presentamos ahora un nuevo o ejemplo, que de hecho es continuacin del anterior 10.2.5 en el o

11.1. Los acumuladores

167

que den amos el predicado aplanar para las listas. En este caso, aplicaremos nuevamente la tcnica de los acumuladores e para eliminar la llamada a concatenar. Ejemplo 11.1.2 La tcnica para implementar el aplanamiento e de listas con acumuladores es similar a la aplicada en el anterior ejemplo 11.1.1, esto es, se trata de aplicar el mismo algoritmo que el utilizado en la versin que inclua a concatenar, pero o sustituyndola aqu por la utilizacin de los acumuladores. As, e o obtenemos por traslacin casi automtica el siguiente conjunto o a de clusulas: a
aplanar(Lista,Resultado) :- aplanar_ac(Lista,[],Resultado). aplanar_ac([],Acumulador,Acumulador). aplanar_ac(Atomo,Acumulador,[Atomo|Acumulador]) :atomic(Atomo), Atomo \== []. aplanar_ac([Car|Cdr],Acumulador,Resultado) :aplanar_ac(Cdr,Acumulador,Cdr_aplanado), aplanar_ac(Car,Cdr_aplanado,Resultado).

donde la primera es un simple protocolo de interfaz que inicializa el acumulador a la lista vaca. Ms exactamente, lo que estamos haciendo es actualizando a el valor del acumulador en cada llamada recursiva. Para ello consideramos que Acumulador es en cada momento el valor de la parte ya aplanada de la lista en ese instante de la ejecucin del o programa. Esto es, en la siguiente llamada recursiva el valor del acumulador ser el resultado de aplanar todo el cdr de la lista a a aplanar en la llamada actual. En este sentido, la tercera de las clusulas en el programa considerado es especialmente ilustrativa a del concepto de acumulacin. 2 o Como nuevo ejemplo ilustrativo del uso de acumuladores, consideraremos una nueva versin para la implementacin del o o producto cartesiano de conjuntos, propuesta en la seccin 10.3. o Ejemplo 11.1.3 Para considerar una versin con acumuladores de la implementacin propuesta en o o la seccin 10.3, eliminaremos la utilizacin que aquel haca del o o

168

Tcnicas de Programacin e o

predicado concatenar, incluyendo el uso de un acumulador que en cada momento representa la porcin calculada del producto o cartesiano, o del conjunto de pares en el caso del predicado linea. Analticamente, el conjunto de clusulas es el siguiente: a
cartesiano(Conj_1,Conj_2,Result) :cartesiano_ac(Conj_1,Conj_2,[],Result). cartesiano_ac([],Conj,Acumulador,Acumulador). cartesiano_ac([Car|Cdr],Conj,Acumulador,Result) :linea(Car,Conj,Acumulador,Lineas), cartesiano_ac(Cdr,Conj,Lineas,Result). linea(Elem,[],Acumulador,Acumulador). linea(Elem,[Car|Cdr],Acumulador,Lineas) :linea(Elem,Cdr,[[Elem,Car]|Acumulador],Lineas).

2 La consideracin del concepto de acumulador, no es privativa o de las listas. Se trata de una tcnica general, aplicable e a cualquier tipo de estructura de datos. Para ilustrarlo, abordaremos un problema numrico recursivo t e pico: la denicin del factorial de un n mero. En primer lugar, o u ilustraremos la denicin recursiva del concepto para despus o e pasar a la implementacin con acumuladores. Ante todo, o debemos recordar que la denicin matemtica de factorial de o a un n mero natural es la siguiente: u n! = 1 si n=0 n (n 1)! en otro caso

Ejemplo 11.1.4 El programa Prolog correspondiente a la denicin recursiva, y natural, del factorial es el dado por las o reglas:

numero_natural(0). numero_natural(siguiente(Numero)) :- numero_natural(Numero).

11.1. Los acumuladores

169

suma(0,Numero,Numero) :- numero_natural(Numero). suma(siguiente(Numero_1),Numero_2,siguiente(Numero_3)) :suma(Numero_1,Numero_2,Numero_3). mult(0,Numero,0) :- numero_natural(Numero). mult(siguiente(0),Numero,Numero) :- !, numero_natural(Numero). mult(siguiente(Numero_1),Numero_2,Numero_3) :mult(Numero_1,Numero_2,Numero_4), suma(Numero_4,Numero_2,Numero_3). factorial(0, siguiente(0)). factorial(siguiente(Numero), Factorial) :factorial(Numero, Parcial), mult(siguiente(Numero), Parcial, Factorial).

El nuevo predicado introducido es factorial(Numero, Factorial) que ser cierto cuando Numero! = Factorial. En a este caso, la semntica declarativa se corresponde exactamente a con el concepto matemtico expuesto con anterioridad y no a requiere una explicacin a mayores. 2 o Ejemplo 11.1.5 Una posible versin del factorial con uso o de acumuladores es la que sigue, que utiliza el predicado a factorial ac como estructura auxiliar de clculo para el almacenamiento de los resultados parciales acumulados. Las clusulas del programa estn en la pgina 170. a a a El lector no debe en este caso sentirse confundido por la utilizacin de la recursividad del predicado factorial ac. En o efecto, se trata de una recursividad nal, y por tanto el programa es iterativo en sentido estricto. 2 Otro ejemplo interesante y en la misma l nea del anterior 11.1.5 es una versin del predicado longitud que utiliza un o acumulador aritmtico. e Ejemplo 11.1.6 Una posible alternativa a la resolucin del o problema de la longitud de una lista, es la consideracin de un o acumulador aritmtico. Eso si, sacricando toda la elegancia e de la programacin lgica pura, mediante la introduccin de o o o

170

Tcnicas de Programacin e o

numero_natural(0). numero_natural(siguiente(Numero)) :- numero_natural(Numero). suma(0,Numero,Numero) :- numero_natural(Numero). suma(siguiente(Numero_1),Numero_2,siguiente(Numero_3)) :suma(Numero_1,Numero_2,Numero_3). mult(0,Numero,0) :- numero_natural(Numero). mult(siguiente(0),Numero,Numero) :- !, numero_natural(Numero). mult(siguiente(Numero_1),Numero_2,Numero_3) :mult(Numero_1,Numero_2,Numero_4), suma(Numero_4,Numero_2,Numero_3). factorial(Numero,Factorial) :factorial_ac(Numero,siguiente(0),Factorial). factorial_ac(0, Factorial, Factorial). factorial_ac(Numero, Acumulador, Factorial) :mult(Numero, Acumulador, Parcial), suma(X, siguiente(0), Numero), factorial_ac(X, Parcial, Factorial).

11.2. Estructuras de datos incompletas

171

nuevos predicados no lgicos. El programa aplica el mismo o formalismo notacional que el del ejemplo 10.2.6, y viene dado por las clusulas siguientes a
longitud([],0). longitud([Car|Cdr],Longitud) :- longitud (Cdr,Longitud_cdr), Longitud is 1 + Longitud_cdr.

que declarativamente podemos traducir en: La longitud de la lista vac es cero. a La longitud de una lista [Car|Cdr] es uno ms la a longitud de Cdr. y donde hemos introducido un nuevo predicado no lgico y o habitualmente predenido en la mayora de los intrpretes e Prolog. Se trata de X is Y que asigna a X el valor resultante de la evaluacin de la expresin o o aritmtica Y. 2 e

11.2

Estructuras de datos incompletas

La implementacin del predicado concatenar propuesta con o anterioridad en el ejemplo 10.2.3 se ha mostrado como altamente ineciente en ejemplos como el 10.2.4, puesto que su uso implica forzosamente recorrer todos los elementos de su primera lista argumento, generando una copia de esta que se concatena a otra copia del segundo de sus argumentos. El origen de este comportamiento tan poco afortunado no es otro que el hecho de que una lista es, tal y como se ha descrito hasta el momento en el texto, un puntero sobre el primero de sus elementos, y donde cada elemento de la misma guarda a su vez un puntero sobre el elemento siguiente. Frente a este dise o n estructural que fuerza el acceso secuencial a los elementos de la lista, el usuario desear en ocasiones, poder acceder de forma a, directa al ultimo de los elementos de la lista. Tal es el caso del predicado concatenar, cuya semntica, que nos servir para a a

172

Tcnicas de Programacin e o

introducir el concepto de diferencia de listas, es un caso t pico para ilustrar el uso de estructuras de datos incompletas. 11.2.1 Diferencias de listas

Esencialmente una diferencia de listas puede ser interpretada de una forma sencilla, como una lista indicada por dos punteros: uno a su primer elemento y otro al ultimo de sus elementos. Sobre el papel, este planteamiento suprime de ra los problemas z que planteaba el uso del concatenar tradicional. La notacin o utilizada ser la siguiente: a X \ Y donde el operador \ recibe el nombre de operador diferencia de listas, y no suele ser incluido de forma estndar en los intrpretes a e Prolog. Ello implicar que en general tendremos que denirlo a sistemticamente antes de su utilizacin. a o Una vez en este punto, estamos en condiciones de denir la semntica declarativa del nuevo predicado concatenar dl a que utilizar al operador diferencia de listas ya denido. El a predicado se describe de forma anal tica en la forma: concatenar dl(X \ Y,Y \ Z,X \ Z) siendo su semntica declarativa, ilustrada por la gura 11.1, la a siguiente: El resultado de concatenar la lista cuyo primer elemento es el apuntado por X y cuyo ultimo elemento es el apuntado por Y, con la lista cuyo primer elemento es el apuntado por Y y cuyo ultimo elemento es el apuntado por Z; es la lista cuyo primer elemento es el apuntado por X y cuyo ultimo elemento es el apuntado por Z. Este nuevo formalismo permite una gran exibilidad en la representacin de listas. As considerando por ejemplo la o , estructura [1,2]

11.2. Estructuras de datos incompletas

173

{
X\Y Y

{
Y\Z Z

Figura 11.1: Representacin grca de la relacin entre listas tradicionales o a o y diferencias de listas.

podemos asociarle un n mero innito u equivalentes, utilizando diferencias de listas: [1, 2] \ [ ] [1, 2, 3] \ [3] [1, 2, 3, 4] \ [3, 4] . . . [1, 2 | X] \ X

{
X\Z

de

expresiones

Como nuevo ejemplo ilustrativo, consideraremos en primer lugar una implementacin del predicado invertir cuya o semntica fue ya descrita en los ejemplos 10.2.4 y 11.1.1, pero a utilizando ahora la tcnica de las diferencias de listas. e Ejemplo 11.2.1 La nueva versin del predicado invertir, o mediante aplicacin del concepto de lista incompleta, queda o denida por el siguiente conjunto de reglas:
invertir(Lista,Invertir) :- invertir_dl(Lista,Invertir\[]). invertir_dl([Car|Cdr],Invertir\Cola) :invertir_dl(Cdr,Invertir\[Car|Cola]). invertir_dl([],Invertir\Invertir).

que describimos ahora de forma breve y por orden: La primera clusula es simplemente una regla de interfaz a para la introduccin del operador diferencia de listas. o

174

Tcnicas de Programacin e o

En la segunda, indicamos que para invertir la lista [Car|Cdr] basta con concatenar al inverso de Cdr el primer elemento Car de la lista considerada. Finalmente, la tercera clusula indica simplemente que a en la nueva notacin, la lista vaca puede representarse o mediante la diferencia de dos listas cualesquiera. Es importante subrayar el hecho de que es necesario haber denido previamente el operador diferencia de listas, \. Para ello, utilizaremos la clusula a op(600, xfy, [\]). que utiliza la declaracin no lgica predenida op para o o la construccin de nuevos operadores del lenguaje. Dicha o facilidad ser descrita detalladamente ms adelante. Aqu nos a a limitaremos a admitir que dicha regla equivale a la denicin o del operador diferencia de listas como un operador asociativo por la derecha y con una prioridad 600 en el conjunto total de operadores del lenguaje. Es importante observar que el algoritmo base es el mismo considerado en el ejemplo 10.2.4, simplemente se trata de una versin ms econmica para la implementacin de la o a o o concatenacin de listas. 2 o En este punto, es importante subrayar que la semntica a declarativa de los programas que utilizan las diferencias de listas para la implementacin de la concatenacin de listas es la o o misma que la considerada en las versiones utilizando el predicado clsico concatenar, como ilustra el ejemplo precedente. Ello a puede servir de referencia al programador inexperto en su familiarizacin con la nueva tcnica. o e

Ejemplo 11.2.2 Consideramos ahora como nuevo ejemplo, el del predicado aplanar que implementa el concepto de

11.2. Estructuras de datos incompletas

175

aplanamiento de una lista, y que ya haba sido objeto de nuestra atencin en los ejemplos anteriores 10.2.5 y 11.1.2. En este o caso, la semntica permanece invariable en relacin al ejemplo a o inicial 10.2.5, que adems puede servirnos de referencia para a la introduccin de las diferencias de listas, como ya habamos o comentado. Analticamente, el nuevo programa viene dado por las clusulas que siguen: a
aplanar(Lista,Resultado) :- aplanar_dl(Lista,Resultado\[]). aplanar_dl([],Lista\Lista). aplanar_dl(Atomo,[Atomo|Cdr]\Cdr) :- atomic(Atomo), Atomo \== []. aplanar_dl([Car|Cdr],Cabeza\Dif) :aplanar_dl(Car,Cabeza\Dif_car), aplanar_dl(Cdr,Dif_car\Dif).

que como hemos indicado, se corresponden exactamente con la versin que utilizaba concatenar. A se alar la utilizacin del o n o predicado predenido atomic(X), que se verica cuando X est a instanciada a un valor que es un atomo o un nmero. La u gura 11.2 muestra un ejemplo de arbol de resolucin para el o predicado aplanar tal y como acabamos de denir. La pregunta considerada es :- aplanar([a,[b]],Resultado). y la respuesta obtenida es la dada por la sustitucin: o
Resultado Resultado1 Cabeza1 [a|Cdr2 ] [a|Cabeza3 ] [a|Cabeza4 ] [a|[b|Cdr5 ]] [a|[b|Dif car3 ]] [a|[b|[]]] = [a,b]

Evidentemente, es necesario haber denido previamente el operador \ mediante la declaracin op, tal y como hemos hecho o en el ejemplo 11.2.1. 2 Siguiendo en la misma l nea, plantearemos ahora la resolucin del producto cartesiano de dos conjuntos, cuestin o o ya considerada anteriormente en la seccin 10.3 y en el o ejemplo 11.1.3, pero utilizando ahora las diferencias de listas.

176

Tcnicas de Programacin e o
{ aplanar([ a | [ [ b ] ] ], Resultado)} Resultado Lista 1 Car 1 Cdr 1 Resultado 1 Dif 1 Atomo 1 Dif_car
1

Resultado 1 [a|[[b]]] { aplanar_dl( [ a | [ [ b ] ] ], Resultado \ [ ] ) } 1 a [[b]] Cabeza 1 []


1 1 1

{ aplanar_dl(a, Cabeza \ Dif_car ), aplanar_dl( [ [ b ] ], Dif_car \ [ ] ) }

a
Cdr
2

Cabeza 1

[ a | Cdr 2]
2

{ atomic(a), a \== [ ], aplanar_dl( [ [ b ] ], Cdr \ [ ] ) }

{ a \== [ ], aplanar_dl( [ [ b ] ], Cdr 2 [ ] ) } \

{ aplanar_dl( [ [ b ] ], Cdr 2\ [ ] ) }

Car3 Cdr3
Cdr
2

[b]

Dif 3 Car4 Cdr 4


Cabeza 3

[] Cabeza 3 []
b

{ aplanar_dl( [ b ], Cabeza 3\ Dif_car 3), aplanar_dl( [ ], Dif_car \3[ ] ) }

[] Cabeza 4
Dif_car3
4 3 3

Dif 4
4 4

{ aplanar_dl(b, Cabeza \ Dif_car ), aplanar_dl( [ ], Dif_car \ Dif_car ), aplanar_dl( [ ], Dif_car \ [ ] ) }

Cabeza 4 Dif_car

[ b | Cdr 5]

4 5

Cdr 5
3 3

{ aplanar_dl( [ ], Cdr \ Dif_car ), aplanar_dl ( [ ], Dif_car \ [ ] ) } Cdr


5

Dif_car3

{ aplanar_dl ( [ ], Dif_car 3 [ ] ) } \ Dif_car


3

[]
{ } true

Figura 11.2: Resolucin de :- aplanar([a,[b]],Resultado)., con o diferencias de listas.

11.2. Estructuras de datos incompletas

177

Ejemplo 11.2.3 El proceso para la inclusin de las diferencias o de listas en la resolucin del producto cartesiano de o dos conjuntos, es similar al aplicado en los ejemplos anteriores 11.2.1 y 11.2.2. En efecto, en este caso la semntica a declarativa es la misma que la considerada en la implementacin o de la seccin 10.3, en la cual la utilizacin de concatenar ha o o sido directamente sustituida por la consideracin de diferencias o de listas. Analticamente, el programa resultante es el siguiente:
cartesiano(Conj_1, Conj_2, Result) :cartesiano_dl(Conj_1, Conj_2, Result \ []). cartesiano_dl([], Conj, Dif \ Dif). cartesiano_dl([Car|Cdr], Conj, Lineas \ Resto) :linea(Car, Conj, Lineas \ Acum), cartesiano_dl(Cdr, Conj, Acum \ Resto). linea(Elem, [], Dif \ Dif). linea(Elem, [Car|Cdr], Acum \ Resto) :linea(Elem, Cdr, Acum \ [[Elem,Car]|Resto]).

habiendo denido previamente el operador \ tal y como hemos hecho con anterioridad en el ejemplo 11.2.1. 2 Ejemplo 11.2.4 Consideraremos ahora el problema de obtener a partir de una lista arbitraria, otra nueva que est formada por e los mismos elementos de la primera a los que se les ha a adido n el inverso de dicha lista. As por ejemplo, si denominamos concatenar inverso al nuevo predicado, la respuesta ante una pregunta del tipo :- concatenar inverso([1,2], X). sera el valor de X dado por: X [1, 2, 2, 1] Evidentemente, un predicado as sera fcilmente programable a a partir de los anteriormente denidos concatenar e invertir. Sin embargo, lo haremos sin hacer un uso explcito de estos, aplicando simplemente el concepto de diferencia de listas. Una posible solucin es la dada por las clusulas que siguen: o a

178

Tcnicas de Programacin e o

concatenar_inverso(Lista, Resultado) :concatenar_inverso_dl(Lista, Resultado\[]). concatenar_inverso_dl([], Lista\Lista). concatenar_inverso_dl([Car|Cdr], [Car|Resultado]\Cola) :concatenar_inverso_dl(Cdr,Resultado\[Car|Cola]).

Bsicamente la idea es muy simple. En efecto, tomando como a base el programa inicial de inversin de listas del ejemplo 11.2.1, o lo que hacemos es a adir los elementos de la lista, a la lista n misma en proceso de inversin en la clusula recursiva. 2 o a 11.2.2 Diferencias de estructuras

El concepto bsico aplicado en la nocin de diferencias de a o listas es generalizable a otras estructuras. Este es el principio de las llamadas estructuras de datos incompletas o diferencias de estructuras para representar los resultados parciales de un clculo. Uno de sus usos ms representativos es la normalizacin a a o de expresiones numricas y su consiguiente aplicacin a la e o resolucin de ecuaciones. o Intuitivamente, una expresin o normalizada es aquella que se corresponde a la consideracin o de un patrn predenido para su construccin. Ello permite la o o aplicacin posterior de mtodos que presuponen la existencia de o e estos patrones. Como ejemplo ilustrativo, podemos considerar las expresiones aritmticas, a las que supondremos las prioridades establecidas e por el uso expl cito de parntesis. As por ejemplo, a la expresin e o (a+b) + (c+d) podemos asociarle la correspondiente estructura sintctica a representada en forma de arbol a la izquierda de la gura 11.3. De la misma forma, podemos considerar la expresin o ((a+b) + c) + d que se corresponde con el uso de las prioridades habituales para las sumas aritmticas, y cuya estructura sintctica es la e a representada a la derecha de la gura 11.3.

11.2. Estructuras de datos incompletas

179

+ + + + a b c d + b c

0 (a+b) + (c+d)

a ((a+b) + c) + d

Figura 11.3: Arboles para las expresiones (a+b)+(c+d) y ((a+b)+c)+d.

Frente a este tipo de estructuras sintcticas, irregulares en el a sentido de que sus representaciones no responden a un patrn o determinado, consideraremos la construccin de expresiones o aritmticas normalizadas a la derecha1 para las sumas. Se e trata en denitiva de obtener arboles sintcticos para estas a operaciones, en los que los operadores se sit en sobre la vertiente u derecha del arbol, esto es, estamos suponiendo que la operacin o es asociativa por la derecha. As en el caso de las expresiones , consideradas en la gura 11.3, el arbol normalizado por la derecha es el representado en la gura 11.4. El problema planteado es, en denitiva, el de la implementacin de un programa capaz de normalizar en o el sentido descrito, las sumas aritmticas. e Para ello, consideraremos la introduccin del operador diferencia de o sumas, que representaremos por ++. La semntica de la a que vamos a dotar al nuevo operador ser similar a aquella a considerada en el caso de las diferencias de listas. Se trata en denitiva de representar una suma mediante dos punteros: uno indicando su principio y otro su nal. As por ejemplo, la suma 1+2
1 las

prioridades habituales resultan de una normalizacin a la izquierda. o

180
+

Tcnicas de Programacin e o

Figura 11.4: Arbol sintctico asociativo por la derecha para a+b+c+d. a

puede representarse de formas tan variadas como las siguientes: 1+2+3 ++3 1+2+3+4 ++ 3+4 . . . 1+2+X ++X Particularmente interesante es la ultima expresin considerada, o puesto que siendo X una variable, su valor es arbitrario. Esto es, en cada momento su valor puede asignarse a aquel que ms a nos convenga. Es igualmente evidente que cualquier expresin o aritmtica e X puede representarse mediante X ++ 0 Grcamente, obtenemos una interpretacin similar a la de a o la diferencia de listas y que en este caso representamos en la gura 11.5. En base a la utilizacin del operador ++, introducimos el o predicado normalizar(Suma,Norma)

11.2. Estructuras de datos incompletas

181

{ {
Y ++ Z Z X ++ Y Y

Figura 11.5: Representacin grca de la relacin entre sumas tradicionales o a o y diferencias de sumas.

que ser cierto si Norma es la expresin normalizada por la a o derecha de la suma aritmtica contenida en Suma. Las siguientes e clusulas constituyen el programa: a
normalizar(Suma, Norma) :- normalizar_ds(Suma, Norma ++ 0). normalizar_ds(Suma_1 + Suma_2, Norma ++ Resto) :normalizar_ds(Suma_1, Norma ++ Resto_1), normalizar_ds(Suma_2, Resto_1 ++ Resto). normalizar_ds(Atomo, Atomo + Resto ++ Resto) :- atomic(Atomo).

cuya semntica declarativa con a normalizar ds viene dada2 por:

{
X ++ Z

respecto

al

predicado

Normalizar una suma de la forma Suma 1 + Suma 2 es equivalente a normalizar el primer sumando y a adir al arbol resultante, el obtenido de la n normalizacin del segundo sumando. o Expresa el resultado trivial X ++ 0 = X, en el caso de atomos. Como en el caso ya estudiado en el ejemplo 11.2.1, hemos de denir previamente el operador ++, por ejemplo mediante op(600,xfy,[++]). lo cual equivale a la denicin del operador ++, como asociativo o por la derecha y con una prioridad de 600 en el registro de operadores del lenguaje.
2 la

primera clusula es simplemente de interfaz para el operador ++. a

182

Tcnicas de Programacin e o

Cap tulo 12

Predicados No Lgicos o
Los programas lgicos basados exclusivamente en los conceptos o de unicacin y resolucin son sin duda elegantes, pero no es o o menos cierto que su inecacia es maniesta desde un punto de vista exclusivamente temporal, en muchos casos. As por ejemplo, la implementacin de la operacin suma en el o o ejemplo 6.5.4 se encuentra a unos niveles de eciencia, en cuanto a la velocidad de tratamiento se reere, muy por debajo de las posibilidades ofrecidas por los microprocesadores de uso com n u mediante la aplicacin de instrucciones apropiadas. o A este respecto, los distintos dialectos de Prolog incluyen una serie de predicados no lgicos predenidos cuya funcin es la de o o implementar funcionalidades que no expresan ning n tipo de u relacin lgica entre objetos. o o

12.1

Predicados aritmticos e

Entre los predicados no lgicos ms importantes encontramos o a las interfaces para las operaciones aritmticas habituales, que e nos permiten acceder directamente a la capacidad aritmtica e del ordenador. Evidentemente, el precio a pagar es la prdida e de generalidad que otorgan las programas puramente lgicos. Se o trata de los predicados aritmticos. e
183

184

Predicados No Lgicos o

La mayor de los intrpretes Prolog incluyen el predicado de a e evaluacin aritmtica is, cuya funcionalidad es la evaluacin o e o de expresiones aritmticas representadas por los operadores e habituales: +, , /, . La sintaxis correspondiente viene dada por X is Y op Z la cual instancia X al valor resultante de evaluar la expresin o Y op Z, donde op es un operador aritmtico binario. Tambin e e podemos utilizar is con operadores unarios en la forma X is op Z o simplemente para asignar un valor numrico a una variable e X is 5 Evidentemente, cuando la expresin a la derecha del is no es o evaluable en el momento de la ejecucin1 , se produce un error. o Ello plantea una diferencia fundamental con los programas lgicos puros. En efecto, en estos ultimos la semntica est o a a completamente denida y por tanto no existe el concepto de error en tiempo de ejecucin, circunstancia siempre posible o cuando utilizamos una interfaz directa con el procesador del ordenador. Ms exactamente, nos encontramos nuevamente con a los problemas clsicos derivados de la programacin imperativa. a o Para evitar este tipo de problemas, algunos dialectos Prolog incluyen mecanismos de control de la evaluacin tales como la o declaracin wait [19] o la primitiva freeze [24] que pueden o retardar la evaluacin de un trmino. Sin embargo, al no tratarse o e de mecanismos estndar, es conveniente evitar su utilizacin con a o el n de hacer nuestro cdigo lo ms portable posible. o a En la misma l nea, la mayor de los dialectos Prolog a suelen incluir predicados predenidos en relacin al resto de las o
es, contiene alguna variable sin instanciar o se le ha aplicado un valor no numrico. e
1 esto

12.2. Entradas y salidas

185

operaciones aritmticas habituales; as tenemos: e X X X X X = Y < Y =< Y > Y >= Y Cierto Cierto Cierto Cierto Cierto si si si si si X X X X X es es es es es igual a Y. menor que Y. menor o igual que Y. mayor que Y. mayor o igual que Y.

12.2

Entradas y salidas

Una clase importante de predicados interesantes slo por sus o efectos colaterales son aquellos encargados de la gestin de las o interfaces de entrada y salida de datos. En efecto, esta labor slo puede entenderse desde el punto de vista del sistema y de o hecho, el modelo de ejecucin de Prolog excluye las entradas y o salidas de la componente pura del lenguaje. El predicado fundamental de entrada es read(X), el cual lee un trmino del ujo actual de entrada2 . El trmino as le se e e do unica con X y read es cierto. En cualquier caso, la instanciacin o de X a un valor exterior al programa se realiza fuera del modelo lgico considerado, puesto que a cada llamada de read(X) el o resultado es cierto con un valor eventualmente distinto de la variable. El predicado fundamental de salida es write(X), el cual escribe el trmino X en el ujo de salida actual3 denido por e el sistema operativo subyacente. Otro predicado interesante es system(X), predicado sistema por autonomasia puesto que su misin es ejecutar sobre el o sistema operativo subyacente el comando X. As por ejemplo, la llamada :- system("date"). tiene como efecto colateral, la ejecucin del comando date en el o sistema operativo, que en este caso supondremos Unix. El efecto
2 habitualmente 3 habitualmente

el teclado. el terminal.

186

Predicados No Lgicos o

es el de la salida por pantalla4 de la fecha actual, que podr ser: a Thu Feb 10 10:32:34 MET 1994 Finalmente hemos de introducir los predicados halt de salida de Prolog, y trace para visualizar el proceso de resolucin. o Asimismo consult(Programa) para cargar un programa en el intrprete y reconsult(Programa), con la misma nalidad, e pero actualizando los posibles predicados predenidos. El predicado untrace provoca la salida del modo de traza.

12.3

Predicados de memorizacin o

Los predicados de memorizacin salvaguardan los resultados o de clculos intermedios realizados durante la ejecucin de un a o programa, cuando estos puedan resultar utiles para clculos a posteriores. Ello permite la construccin de programas o inteligentes capaces de aprender de su propia experiencia. De forma similar, ser posible eliminar ciertos conocimientos a cuando se estime que ya no son utiles para la resolucin del o problema tratado. Claramente, a este tipo de comportamientos no podemos asignarle una semntica congruente en Prolog puesto que no a expresan ning n tipo de relacin lgica. Por el contrario, u o o se trata de desencadenar efectos colaterales sobre el cdigo o fuente del programa. Para ello se utilizan tres predicados fundamentalmente: asserta(X) que introduce la regla X en cabeza del conjunto de clusulas que a se encuentran en la memoria del intrprete, e assert(X) que introduce la regla X al nal del conjunto de clusulas que se a encuentran en la memoria del intrprete, y e retract(X)
4o

ms exactamente, por el ujo de salida actual. a

12.3. Predicados de memorizacin o

187

que retira la primera regla que unique con X en la memoria del intrprete, en un orden de b squeda de arriba hacia abajo. e u Como ejemplo ilustrativo, consideremos el caso de la funcin o de Fibonacci, que anal ticamente viene denida en la forma siguiente:
siX = 0 0 1 siX = 1 bonacci(X) = bonacci(X 1) + bonacci(X 2) en otro caso

y que podemos implementar con el conjunto de clusulas: a


fib(0,0) :- !. fib(1,1) :- !. fib(N,R) :- N1 is N-1, fib(N1,R1), N2 is N-2, fib(N2,R2), R is R1+R2.

donde el predicado fib(N,R) es cierto cuando bonacci(N ) = R. Claramente, la semntica de la implementacin es correcta, a o sin embargo la interpretacin del cdigo presenta ciertas o o caracter sticas indeseables. As para el clculo de bonacci(2) , a ser necesario conocer bonacci(1) y bonacci(0), valores que a ya estn calculados en las dos primeras clusulas. El problema a a se complica cuando queremos calcular bonacci(3), puesto que necesitaremos conocer bonacci(2) y bonacci(1), mientras que en principio slo tenemos acceso directo en nuestro programa a o bonacci(1), lo cual implica el clculo expl a cito de bonacci(2). Si seguimos avanzando en el valor considerado para el argumento de la funcin de Fibonacci, los clculos van a multiplicarse de o a forma innecesaria. Como ejemplo, consideremos el clculo del a valor de bonacci(4) = bonacci(3) + bonacci(2) Puesto que ninguno de los valores a la derecha de la igualdad aparecen calculados directamente en el programa, tendremos que calcularlos a partir de la relacin recursiva dada por la o ultima clusula. Ello implica la duplicacin del clculo de a o a bonacci(2): 1. Una vez para el clculo de bonacci(2). a

188

Predicados No Lgicos o

2. Otra vez para el clculo de bonacci(3). a La misma situacin se repite para la resolucin de o o bonacci(X), X 3. Evidentemente, podr amos evitar estas duplicaciones si una vez calculado un valor que previsiblemente va a ser utilizado en un futuro, este se incluyera en la memoria del intrprete. La solucin viene de la mano del programa e o siguiente:
fib(0,0) :- !. fib(1,1) :- !. fib(N,R) :- N1 is N-1, fib(N1,R1), N2 is N-2, fib(N2,R2), R is R1+R2, asserta((fib(N,R) :- !)).

El procedimiento anterior permite en principio una optimizacin de nuestra aplicacin. Sin embargo, puede ocurrir o o que a partir de un momento dado, las clusulas incluidas a dinmicamente en la memoria del intrprete puedan no ser a e utiles para clculos futuros. As por ejemplo, una vez calculado a bonacci(4), podemos eliminar la regla correspondiente a bonacci(2) puesto que no nos ser necesaria en el clculo de a a bonacci(X), X > 4. El nuevo programa que incluye la eliminacin de dichas reglas viene dado por el siguiente conjunto o de clusulas: a
if_then_else(P,Q,R) :- P,!,Q. if_then_else(P,Q,R) :- R. fib(0,0) :- !. fib(1,1) :- !. fib(N,R) :- N1 is N-1, fib(N1,R1), N2 is N-2, fib(N2,R2), R is R1+R2, asserta((fib(N,R) :- !)), if_then_else(N>3,retract((fib(N2,_) :- !)),true).

Un problema importante en relacin al uso de los predicados o de memorizacin es que los retrocesos no tienen ning n tipo o u de efecto sobre ellos. La razn estriba en la naturaleza misma o de los predicados en cuestin. Ms claramente, una vez hemos o a introducido una clusula mediante la utilizacin de un predicado a o como asserta, cualquiera que sea el retroceso en el que se vea involucrado el proceso de resolucin la clusula no ser borrada. o a a Ello puede ser contraproducente en tanto que el programa queda

12.3. Predicados de memorizacin o

189

modicado en cualquier caso, a n cuando las relaciones que u hayan establecido la oportunidad de dicha modicacin hayan o sido invalidadas. En consecuencia, el programador deber tener a presente esta posibilidad en todo momento para asegurar la correccin de sus programas. Una posible alternativa pasa por o la redenicin de estos predicados con el n de hacerlos sensibles o a los retrocesos, tal y como ocurre con los predicados lgicos. o Ejemplo 12.3.1 En este ejemplo mostraremos cmo el o programador puede redenir el predicado asserta con el n de hacerlo sensible a los retrocesos. Esto es, si en el transcurso del proceso de resolucin se produce un retroceso sobre el objetivo o asserta(Clausula) que haba determinado la inclusin de la o clusula Clausula en nuestra base de datos, el intrprete debe a e ser capaz de detectarlo y eliminar dicha clusula de la memoria a del mismo. Usaremos la notacin assertb para designar al nuevo o predicado. Una posible implementacin es la dada por las o clusulas: a
assertb(Clausula) :- asserta(Clausula). assertb(Clausula) :- retract(Clausula), fail.

cuya semntica operacional viene dada por: a La primera vez que se ejecuta, assertb(Clausula) funciona tal y como lo har asserta(Clausula). a En caso de retroceso sobre el objetivo assertb(Clausula), retiramos la clusula Clusula a a de la base de datos del intrprete y continuamos con e el retroceso. Es importante se alar que la inclusin del predicado fail n o al nal de la segunda alternativa del predicado assertb es necesaria con el objeto de conseguir que el proceso natural de retroceso del intrprete no se vea interrumpido. En efecto, e si eliminamos dicho fail el resultado ser que el proceso de a retroceso se pare en la segunda alternativa de assertb puesto que retract(Clausula) se vericar siempre por denicin a o

190

Predicados No Lgicos o

de retract. A este respecto, baste observar que en caso de haber utilizado un predicado asserta clsico, el retroceso hubiese a simplemente continuado puesto que no habra alternativa posible a la ya aplicada. 2 A continuacin se mostrar la utilizacin de los predicados o a o de memorizacin mediante uno de los ejemplos clsicos de o a programacin en inteligencia articial: las Torres de Hanoi. o Ejemplo 12.3.2 En el juego de las Torres de Hanoi se parte de un escenario en el que se dispone de los siguientes elementos: Tres palos en posicin vertical. o Un conjunto de discos de diferente dimetro. Todos ellos a disponen de un oricio en la parte central mediante el cual pueden ser insertados en cualquiera de los palos. La dinmica del juego consiste en mover un determinado nmero a u de discos desde el palo en el que estn iniciamente situados a a un palo de destino. El tercer palo puede utilizarse para colocar temporalmente los discos. En todo momento del juego debe satisfacerse la siguiente condicin: o Sobre un disco cualquiera solamente pueden colocarse discos de menor dimetro. a Aqu es donde reside la dicultad del juego, puesto que todos los movimientos deben realizarse de tal forma que nunca sea necesario situar un disco sobre otro de inferior tama o. n Como elemento ilustrativo, en la gura 12.1 mostramos los movimientos necesarios para mover dos discos del palo A al palo C, utilizando el palo B como elemento intermedio. En este caso, basta realizar cuatro movimientos. Sin embargo, la complejidad del juego aumenta a medida que se incrementa el nmero de u discos. El nmero de movimientos necesarios para alcanzar la u solucin no es proporcional al nmero de discos, sino que la o u relacin es de tipo exponencial. En una primera aproximacin o o al problema mediante Prolog, denimos el siguiente conjunto de reglas:

12.3. Predicados de memorizacin o

191

concatenar([],Lista,Lista) :- !. concatenar([Car|Cdr],Lista,[Car|Resultado]) :concatenar(Cdr,Lista,Resultado). hanoi(1,A,B,_,[A a B]). hanoi(N,A,B,C,Movimientos) :N > 1, N1 is N - 1, hanoi(N1,A,C,B,Movimientos_1), hanoi(N1,C,B,A,Movimientos_2), concatenar(Movimientos_1,[A a B|Movimientos_2],Movimientos).
C

1)

2)

3)

4)

Figura 12.1: Juego de las Torres de Hanoi para dos discos.

Las dos primeras reglas denen el predicado concatenar introducido con anterioridad en el ejemplo 10.2.3. Las que estn a encabezadas por hanoi son las que realmente se encargan de resolver el ncleo del problema, esto es, el movimiento de los u discos. Mediante la primera regla hanoi se establece directamente la solucin para el caso trivial, el cual no es otro que aquel en o el que se dispone de un unico disco. La segunda regla es ms a compleja y resuelve los casos no triviales del problema. En la

192

Predicados No Lgicos o

variable Movimientos se van almacenando, en forma de lista, los movimientos que se deben realizar para trasladar N discos desde el palo A hacia el B, utilizando el C como palo intermedio, para lo cual es necesario realizar previamente los siguientes pasos: 1. Mover N-1 discos de A hacia C utilizando B como palo intermedio. Con ello dejamos en A un unico disco: el que estaba en la base, soportando a todos los dems. a 2. Mover el disco situado en A a B. 3. Trasladar los N-1 discos situados en C a B, para lo cual se puede hacer uso de A como palo intermedio. Para que el programa funcione correctamente es necesario declarar el operador a, que se utiliza para representar los movimientos. Para ello se utiliza la declaracin no lgica op: o o op(600,yfx,a). Si se desea obtener una visualizacin en pantalla de los o movimientos aplicados, se deben introducir en los puntos adecuados llamadas al predicado no lgico write. Una posible o solucin es la que se muestra en el siguiente conjunto de o clusulas: a
concatenar([],Lista,Lista) :- !. concatenar([Car|Cdr],Lista,[Car|Resultado]) :concatenar(Cdr,Lista,Resultado). hanoi(1,A,B,_,Nom_A,Nom_B,_,[A a B]) :write(Nom_A),write(->),write(Nom_B),write(, ). hanoi(N,A,B,C,Nom_A,Nom_B,Nom_C,Movimientos) :- N > 1, N1 is N - 1, hanoi(N1,A,C,B,Nom_A,Nom_C,Nom_B,Movimientos_1), write(Nom_A),write(->),write(Nom_B),write(, ), hanoi(N1,C,B,A,Nom_C,Nom_B,Nom_A,Movimientos_2), concatenar(Movimientos_1,[A a B|Movimientos_2],Movimientos).

Estas implementaciones presentan un problema: la repeticin o de soluciones previamente alcanzadas, ya que para alcanzar la solucin relativa al movimiento de N discos es preciso trasladar o

12.4. Predicados metalgicos o

193

dos veces N 1 discos. Evidentemente, la solucin para estos o dos ultimos traslados es la misma. Sin embargo, el programa realiza los clculos dos veces, una vez para cada caso. El remedio a para evitar la duplicidad de clculos consiste en incorporar al a programa un mecanismo de aprendizaje que le permita recordar la solucin obtenida para aquellos problemas ya resueltos. o Bajo estas consideraciones, el nuevo programa consta del siguiente conjunto de reglas, en el cual, por simples razones de claridad de texto, no se han incluido las llamadas al predicado no lgico write: o
concatenar([],Lista,Lista) :- !. concatenar([Car|Cdr],Lista,[Car|Resultado]) :concatenar(Cdr,Lista,Resultado). hanoi(1,A,B,_,[A a B]). hanoi(N,A,B,C,Movimientos) :N > 1, N1 is N - 1, hanoi(N1,A,C,B,Movimientos_1), asserta((hanoi(N1,A,C,B,Movimientos_1) :- !)), hanoi(N1,C,B,A,Movimientos_2), concatenar(Movimientos_1,[A a B|Movimientos_2],Movimientos).

Por induccin, se puede demostrar que la complejidad del o problema es de 2N 1 movimientos para N discos. Por ejemplo, en el caso de N = 10, el nmero total de movimientos utilizando u esta versin es de: o 2101 = 29 = 512 2

12.4

Predicados metalgicos o

Los predicados metalgicos son un tipo especial de los no o lgicos, cuya misin es interrogar al sistema acerca del o o estado actual del proceso de resolucin. Para introducir al o lector en la conveniencia de disponer de un conjunto tal de facilidades, reconsideraremos el problema del ejemplo 6.6.2.

194

Predicados No Lgicos o

Como se recordar, en esa ocasin qued de maniesto que un a o o acercamiento exclusivamente lgico a determinados problemas o no siempre es garant para la obtencin de los resultados a o deseados. Ms exactamente, en aquel caso ve a amos que la resolucin de ecuaciones del tipo o X +Y =Z no siempre est garantizado utilizando el acercamiento mostrado a en el ejemplo 6.5.4, que consideraba slo mecanismos lgicos o o para la resolucin. A este respecto, el ejemplo a desarrollar o podr ser una alternativa en cuanto a la tcnica empleada. a e Ejemplo 12.4.1 En esta ocasin, intentaremos abordar la o resolucin de ecuaciones de la forma X + Y = Z o evitando la utilizacin de funciones lgicas. Esto es, no o o consideraremos ningn tipo de notacin para la representacin u o o de los argumentos. Como en el caso del ejemplo 6.5.4 nos limitaremos al caso de los nmeros naturales. Adems, y con u a objeto de facilitar la comprensin de las ideas fundamentales, o consideraremos que la ecuacin contiene slo una variable. o o La ultima de las hiptesis permite una simplicacin notable o o del problema. En efecto, si dispusisemos de un predicado e capaz de indicarnos cundo una variable est instanciada o no, a a nosotros podramos preveer el comportamiento en funcin de o dicha respuesta. As por ejemplo, si estuvisemos en condiciones e de armar que tanto la variable X como la Z estn instanciadas a a algn valor, podramos preveer que la solucin a la ecuacin u o o sera el valor Y = Z X. Un rendimiento tal, es unicamente posible mediante la utilizacin de un predicado metalgico. o o En nuestro caso particular, la solucin viene de la mano del o predicado predenido nonvar(X) que es cierto cuando X es una variable instanciada. Tambin e utilizaremos el predicado no lgico is. El programa resultante o est formado por las clusulas siguientes: a a

12.5. Comentarios suma(X,Y,Z) :- nonvar(X), nonvar(Y), Z is X+Y. suma(X,Y,Z) :- nonvar(X), nonvar(Z), Y is Z-X. suma(X,Y,Z) :- nonvar(Y), nonvar(Z), X is Z-Y.

195

2 El ejemplo comentado, ilustra perfectamente la utilidad fundamental del tipo de predicados estudiado: el test metalgico. o Ms exactamente, se trata de utilizar un predicado para decidir, a en funcin del estado actual del intrprete, qu opcin de o e e o resolucin debemos seguir. Si bien el conjunto de predicados o metalgicos ofertados depende en general del dialecto Prolog o utilizado, los ms usuales son los siguientes: a nonvar(X) var(X) Es cierto cuando X es una variable instanciada. Es cierto cuando X es una variable sin instanciar. atom(X) Es cierto cuando X est instanciada a un valor a que es un atomo. number(X) Es cierto cuando X est instanciada a un valor a que es un n mero. u integer(X) Es cierto cuando X est instanciada a un valor a que es un n mero entero. u float(X) Es cierto cuando X est instanciada a un valor a que es un n mero real. u atomic(X) Es cierto cuando X est instanciada a un valor a que es un atomo o un n mero. u

12.5

Comentarios

Si bien los comentarios no merecen el calicativo de predicados, puesto que simplemente son ignorados por el intrprete, hemos e decidido presentarlos en este cap tulo a n siendo conscientes u de la contradiccin que ello representa. En efecto, como en o la mayor de los lenguajes de programacin, este tipo de a o estructuras son simplemente ignoradas incluso a nivel lxico, sin e

196

Predicados No Lgicos o

llegar en la inmensa mayor de los casos a la fase de anlisis a a sintctico5 . a En lo que se reere a su uso prctico, simplemente indicar a que en un lenguaje fuertemente declarativo como Prolog, su utilizacin se hace aconsejable para evidenciar los posibles o conictos declarativo/operacionales de los programas. En todo caso, un programa bien comentado es un programa con garant as de continuidad. En la mayor de los dialectos Prolog, los comentarios suelen a delimitarse mediante / al principio y / al nal, no siendo habitualmente multil neas. Como ejemplo sirva el siguiente: /* Esto es un simple comentario */

5 slo sistemas en los que el analizador sintctico tenga asociada una aplicacin que o a o exija la recuperacin o ntegra del texto a partir del arbol de derivacin, requieren que los o comentarios tengan un tratamiento espec co a este nivel. Tal es el caso del entorno de generacin de lenguajes Centaur [9]. o

Cap tulo 13

Los Operadores
Un operador es, en Prolog, simplemente una conveniencia notacional. As por ejemplo, la expresin 2+1 podr ser notada o a como +(2, 1) para representar al arbol

y no como parecer natural, al n mero 3. En Prolog, existen a u tres tipos de operadores: Injos, aquellos que aparecen entre sus dos argumentos. Prejos, aquellos que aparecen delante de su unico argumento. Sujos, aquellos que aparecen detrs de su unico a argumento. Cada operador tiene una prioridad, la cual indica el orden de evaluacin de los operadores, y que en Prolog viene dada por o un n mero entre 1 y 1200 siendo el 1 el indicativo de mayor u
197

198

Los Operadores

prioridad. As por ejemplo, en C-Prolog la suma posee una prioridad 500 y la multiplicacin una prioridad 400. Adems es o a necesario asociar a cada operador un tipo de asociatividad. La necesidad de jar estos dos parmetros ya hab sido justicada a a en la seccin 2.3. Tambin se hab planteado en ese momento o e an las dos alternativas posibles para resolver el problema. Por un lado una v expl a cita caracterizada por la dinamicidad de su aplicacin, y otra impl o cita que pasaba por modicar la gramtica subyacente al lenguaje que incorporaba al operador. a En nuestro caso particular, es evidente que un cambio directo en la gramtica que dene el lenguaje mismo de programacin a o no representa un acercamiento prctico. En este sentido, se a impone la solucin representada por la denicin expl o o cita de prioridades y asociatividades.

13.1

Denicin de operadores o

La discusin precedente ilustra perfectamente la necesidad de o denir una prioridad y una asociatividad para cada operador considerado en el lenguaje. En consecuencia, cualquier posibilidad de introduccin de nuevos operadores pasa por el o cumplimiento de tres requisitos previos: 1. Denicin de la representacin f o o sica del operador, esto es, de su notacin. o 2. Declaracin de su prioridad en relacin a los dems o o a operadores presentes en el lenguaje. 3. Declaracin del tipo de asociatividad del operador. o En relacin a la prioridad, ya hemos comentado que en Prolog o viene dada por un n mero entero entre 1 y 1200. Respecto a u la declaracin de la asociatividad distinguiremos entre los casos o correspondientes a los operadores binarios1 y los unarios2 .
1 esto 2 aquellos

es, aquellos que tienen asociados dos operandos. que tienen asociado un unico operando.

13.1. Denicin de operadores o

199

13.1.1

Operadores binarios

En este caso, el lenguaje considera tres tipos distintos de operador binario: Operadores del tipo xfx. Operadores del tipo xfy. Operadores del tipo yfx. donde: f representa al operador binario, respecto al cual intentamos denir la asociatividad. x indica que dicha subexpresin debe tener una prioridad o 3 estrictamente menor que la del funtor f. y indica que dicha subexpresin puede tener una prioridad o menor o igual que la del funtor f. considerando que la prioridad de una expresin viene dada por la o prioridad de su funtor principal, esto es, del funtor que aparece en la ra de su arbol de anlisis sintctico. En denitiva, lo que z a a estamos diciendo es que un operador del tipo xfy tendr una a asociatividad por la derecha, mientras que un operador de tipo yfx tendr un asociatividad por la izquierda. a En este punto, lo unico que necesitamos es un predicado no lgico capaz de permitirnos la introduccin de un nuevo o o operador en el lenguaje a partir de una notacin, una prioridad o y una asociatividad. Este operador tiene la sintaxis siguiente: op(Prioridad, Asociatividad, Lista de notaciones) As por ejemplo, op(500,yfx,[+]) declara al operador + como asociativo por la izquierda y con una prioridad de 500. Adems, dado que se trata de un simple a
3 es

decir, un indicativo de prioridad mayor.

200

Los Operadores

predicado de interfaz con el sistema, no cabe esperar respuestas congruentes a preguntas del tipo :- op(Prioridad,yfx,[+]). o :- op(500,Asociatividad,[+]). En cualquier caso, la denicin de nuevos operadores es una o tarea delicada que debe tener muy en cuenta el comportamiento deseado de la nueva estructura en relacin al comportamiento o de los operadores ya existentes. 13.1.2 Operadores unarios

Hasta ahora hemos visto cmo se denen los operadores binarios, o que son realmente los ms utilizados. Sin embargo, tambin a e es posible denir en Prolog un operador unario, es decir, un operador que cuenta con un unico operando. Para ello se utiliza la misma declaracin op que en el caso de los operadores o binarios. Las variaciones vienen dadas por el valor que se le pasa al segundo parmetro de op, mediante el cual se establece a la asociatividad. Los otros dos parmetros, que se reeren a la a asociatividad y a la notacin, mantienen su signicado. o Respecto a la asociatividad, existen cuatro tipos de operadores unarios: Operadores unarios del tipo fx. Operadores unarios del tipo fy. Operadores unarios del tipo xf. Operadores unarios del tipo yf. Los dos primeros se reeren a operadores prejos, mientras que los dos ultimos a operadores sujos. El signicado de los tipos es anlogo al de los operadores binarios, ya que: a

13.1. Denicin de operadores o

201

f representa al operador en s mismo. Si aparece a la izquierda indica que el operador es prejo. Consecuentemente, si est situado a la derecha indica el a carcter sujo del operador. a x indica que dicha subexpresin debe tener una prioridad o menor que la del funtor f. y indica que dicha subexpresin debe tener una prioridad o menor o igual que la del funtor f. Todo operador op declarado de tipo fy o yf tiene carcter a asociativo, por lo que es vlido escribir4 a op op . . . op operando puesto que la expresin op operando tiene igual prioridad que o op y en consecuencia puede ser utilizada como operando de este ultimo operador. En cambio, un operador op denido como fx o xf no puede ser utilizado asociativamente, puesto que una expresin como o op op . . . op operando no ser vlida al no ser op operando de menor prioridad que op, a a lo cual implica que no puede ser utilizada como operando de este ultimo operador. Como comentario, diremos que es posible denir ms de un a operador con el mismo nombre, siempre que sean de diferente tipo. Es lo que se conoce como sobrecarga de un operador, del cual se dice que est sobrecargado. El intrprete Prolog a e identica el operador concreto que se est utilizando mediante a el examen de los operandos en anlisis sintctico. La utilizacin a a o de operadores sobrecargados debe restringirse en lo posible.
4 en

este caso suponemos que op es de tipo fy, es decir, un operador unario prejo.

202

Los Operadores

13.2

Operadores y potencia expresiva

La denicin de operadores no debe ser considerada en nig n o u caso como una prctica limitada en Prolog. Lejos de eso, su a introduccin facilita la lectura declarativa de los programas y o por tanto su comprensin y mantenibilidad. o Ejemplo 13.2.1 En este ejemplo, mostraremos la utilidad de la potencia de las notaciones lgicas y en particular de los o operadores. Para ello, consideraremos un problema clsico en a inteligencia articial: el Problema de la Analog a. Esencialmente se trata de establecer analogas entre formas geomtricas. Como ejemplo concreto, a partir del conjunto e de formas representadas en la gura 13.1, podemos considerar la existencia de algn tipo de relacin entre ellas. Nuestro u o

figura a

figura b

figura c

figura d

figura e

figura f

Figura 13.1: Un conjunto de guras para el problema de la analog a

objetivo ser el de dise ar un programa capaz de detectar a n las relaciones, indicando su naturaleza. Ms exactamente, a a partir de una relacin entre dos objetos y un tercer objeto, o se trata de encontrar el anlogo a este tercer objeto segn la a u relacin establecida entre los dos primeros. Para alcanzar este o objetivo, la forma de proceder es sistemtica: se expresan en a

13.2. Operadores y potencia expresiva

203

forma de hechos todas las posibles relaciones y se establece una regla de deduccin para encontrar las analogas. Para ello, o consideraremos el predicado analogia( es a(Figura 1,Figura 2), es a(Figura 3,Figura 4), Relacin) o que ser cierto si la gura Figura 1 es a la Figura 2 lo a que la gura Figura 3 es a la Figura 4 mediante la analoga Relacin. Tambin consideraremos el predicado auxiliar o e verifican(Figura 1,Figura 2,Relacion) que es cierto cuando las guras Figura 1 y Figura 2 se relacionan mediante Relacion. Una primera solucin podra o venir dada por las clusulas de la pgina 204. a a Como muestra del correcto comportamiento del programa, el lector puede comprobar que las respuestas a la pregunta :- analogia(es a(X,a),es a(b,Y),Relacion). vienen dadas por los triples
Xb Xd Ya Yc Relacion inversion Relacion contorno Xd Xe Yf Yf Relacion contorno Relacion interior Xf Ya Relacion inversion

Sin embargo, el programa anterior es insatisfactorio por varias razones, entre ellas: 1. Un mecanismo de deduccin de las relaciones muy poco o exible. En efecto, procediendo como hasta ahora estamos obligados a considerar de forma exhaustiva todas las

204

Los Operadores

analogia(es_a(X,Y),es_a(Z,W),Relacion) :verifican(X,Y,Relacion), verifican(Z,W,Relacion). verifican(a,b,inversion). verifican(a,d,contorno). verifican(a,e,interior). verifican(a,f,inversion). verifican(b,a,inversion). verifican(b,c,contorno). verifican(b,f,contorno). verifican(b,f,interior). verifican(b,f,igualdad). verifican(c,b,contorno). verifican(c,d,interior). verifican(c,e,inversion). verifican(c,f,contorno). verifican(d,a,contorno). verifican(d,c,interior). verifican(e,a,interior). verifican(e,c,inversion). verifican(f,a,inversion). verifican(f,b,contorno). verifican(f,b,interior). verifican(f,b,igualdad). verifican(f,c,contorno).

13.2. Operadores y potencia expresiva

205

relaciones posibles entre todas las guras consideradas e incluirlas en el programa en forma de hechos. Ello puede provocar fallos en el comportamiento nal del programa simplemente por omisin de alguna de las relaciones. o 2. La consideracin de la funcin es a como tal, y no como o o operador injo diculta la lectura declarativa del programa y por tanto su comprensin. o

Figura a b c d e f

Descripcin o cuadrado dentro de triangulo triangulo dentro de cuadrado circulo dentro de cuadrado circulo dentro de triangulo cuadrado dentro de circulo triangulo dentro de cuadrado

Tabla 13.1: Tabla de nombres para el problema de la analog a

Para solucionar el primer punto, incluiremos la descripcin de o cada gura, una informacin que ahora vamos a utilizar para o la resolucin de nuestro problema. El protocolo de descripcin o o es el propuesto en la tabla 13.1, a partir de las denominaciones ya introducidas en la gura 13.1. Declararemos por lo tanto dentro de como operador injo mediante op(200,xfy,[dentro de]) En relacin a la segunda cuestin, la solucin pasa por la o o o declaracin como operador injo de es a, por ejemplo mediante o op(300,xfy,[es a]) Es importante observar que hemos denido es a como un operador con menor prioridad que dentro de. Ello es imprescindible para la buena marcha del programa, puesto que

206

Los Operadores

queremos que es a se evale ms tarde que dentro de en las u a expresiones en las que aparecen juntos ambos operadores. Ahora ya podemos escribir nuestro nuevo programa:
analogia(X es_a Y, Z es_a W, Relacion) :figura(X,FormaX), figura(Y,FormaY), X \== Y, figura(Z,FormaZ), figura(W,FormaW), Z \== W, verifican(FormaX,FormaY,Relacion), verifican(FormaZ,FormaW,Relacion). verifican(Figura_1 Figura_1 verifican(Figura_1 Figura_2 verifican(Figura_1 Figura_1 verifican(Figura_1 Figura_3 figura(a, figura(b, figura(c, figura(d, figura(e, figura(f, dentro_de dentro_de dentro_de dentro_de dentro_de dentro_de dentro_de dentro_de Figura_2, Figura_2,igualdad). Figura_2, Figura_1,inversion). Figura_2, Figura_3,interior). Figura_2, Figura_2,contorno).

cuadrado dentro_de triangulo). triangulo dentro_de cuadrado). circulo dentro_de cuadrado). circulo dentro_de triangulo). cuadrado dentro_de circulo). triangulo dentro_de cuadrado).

que ante la pregunta :- analogia(X es a a, b es a Y, Relacion). proporciona las respuestas esperadas:


Xb Xd Ya Yc Relacion inversion Relacion contorno Xe Xd Yf Yf Relacion contorno Relacion interior Xf Ya Relacion inversion

Cap tulo 14

Lgica y Anlisis o a Sintctico a


Una vez establecidos los mecanismos fundamentales de la programacin lgica, nuestro objetivo es ahora el de centrarnos o o en una de sus aplicaciones fundamentales: el anlisis de a lenguajes naturales1 . Ello nos llevar a explotar la relacin a o existente entre el dise o de compiladores lgicos para programas n o constituidos por clusulas de Horn y el anlisis sintctico de a a a un lenguaje de contexto libre tradicional. Este aspecto fue observado por primera vez por Colmerauer [5], quien introdujo el concepto de gramtica de clusulas denidas, ms conocido a a a por DCG2 [5, 20]. Intuitivamente, las DCGs son una generalizacin de las o gramticas de contexto libre, pero a diferencia de estas no son a simples formalismos denotacionales sino tambin operacionales, e esto es, pueden ejecutarse directamente. Ms exactamente, a podemos centrar las principales diferencias en torno a las siguientes caracter sticas: Los no terminales pueden ser trminos compuestos, por lo e que no estn restringidos a ser simples atomos. a
1 esto 2 por

es, los lenguajes de comunicacin humana. o Denite Clause Grammar.

207

208

Lgica y Anlisis Sintctico o a a

El lado derecho de las reglas puede contener, adems de a terminales y no terminales, llamadas a procedimientos mediante los cuales es posible expresar condiciones adicionales que se deben satisfacer para que la regla sea considerada vlida. Esto es lo que habitualmente hemos a denominado objetivos. La utilizacin de DCGs constituye un potente mecanismo o para la construccin de analizadores de lenguajes. En esta o capacidad juega un papel muy importante la forma en que se va construyendo la estructura correspondiente al arbol sintctico. a En efecto, Prolog construye estas estructuras por trozos, tratando como variables aquellas partes que no pueden ser especicadas en un momento dado. La estructura puede seguir siendo construida, ya que el proceso de unicacin instancia o las variables que han quedado libres a medida que las partes anteriormente especicadas se pueden construir.

14.1

Un acercamiento intuitivo

Introduciremos este nuevo concepto de forma prctica, con un a ejemplo de programacin muy simple. Se trata de implementar o un reconocedor de pal ndromos, o lo que es lo mismo, de palabras cuya lectura es simtrica de derecha a izquierda, y de izquierda e a derecha. Algunos ejemplos podr ser los siguientes: an abba aba aa Como en la mayor de los problemas planteados en informtica, a a su resolucin pasa por el dise o de una gramtica en la que o n a las sentencias del lenguaje generado consituyan las soluciones buscadas. Se trata pues simplemente de describir formalmente la naturaleza de estas. La siguiente gramtica es perfectamente a

14.1. Un acercamiento intuitivo

209

vlida para este cometido: a (0) (1) (2) (3) P P P C CP C C carcter a

con el condicionante adicional de que los caracteres C de la regla (0) deben ser idnticos. Esta ultima exigencia es de tipo e contextual y no puede ser resuelta de forma simple utilizando un formalismo de contexto libre tradicional. En nuestro caso, su resolucin ser gratuita por unicacin. o a o 14.1.1 Una tcnica simple e

Como primera alternativa de solucin para el problema o planteado, utilizaremos para la implementacin de nuestro o analizador sintctico una funcin de rma p/3, que servir para a o a representar las estructuras sintcticas generadas. La base de la a implementacin es el predicado o palindromo(Arbol,Inicial,Final) que ser cierto si Arbol es el arbol sintctico correspondiente a a al anlisis de la cadena considerada entre los caracteres de a posiciones Inicial y Final. Incluiremos adems el predicado a caracter(X,Inicial,Final) que ser cierto si X es un s a mbolo carcter entre las posiciones a Inicial y Final de la cadena considerada. Anal ticamente el programa propuesto tiene la lectura declarativa siguiente: Una cadena es un palndromo si el primer y el ultimo carcter coinciden y el resto de la cadena es a un palndromo. La cadena vaca es un palndromo. Un slo carcter es por s mismo un palndromo. o a

210

Lgica y Anlisis Sintctico o a a

palindromo(p(C,P,C),X,W) :- caracter(C,X,Y), palindromo(P,Y,Z), caracter(C,Z,W). palindromo(p(nil),X,X). palindromo(p(C),X,Y) :- Y is X+1, caracter(C,X,Y). caracter(a,0,1). caracter(b,1,2). caracter(a,2,3). caracter(a,3,4). caracter(a,4,5). caracter(b,5,6). caracter(a,6,7).

Es importante observar que la tcnica aplicada obliga a un e conocimiento exacto de las posiciones de los caracteres en la cadena de entrada, posiciones que adems deben indicarse en a el programa al tiempo que se dene el diccionario, que en nuestro caso est representado por las siete ultimas clusulas. a a Ello implica que el programa es distinto para cada cadena de caracteres considerada en entrada. Adems estamos obligados a a conocer incluso el n mero de caracteres de la frase a analizar. u As las llamadas son del tipo , :- palindromo(Arbol,0,7). Esto es, la cadena de entrada no se incluye en la llamada sino expl citamente en el programa, lo cual supone una limitacin o evidente. La respuesta obtenida viene dada por: Arbol p(a,p(b,p(a,p(a),a),b),a) Un punto importante a subrayar, es el de la resolucin del o problema contextual planteado por la identidad de los caracteres de la regla (0) de la gramtica de los pal a ndromos. En efecto, se ha resuelto simplemente mediante unicacin en la primera de o las clusulas del programa. a

14.1. Un acercamiento intuitivo

211

14.1.2

Una tcnica exible e

Est claro, por las razones expuestas anteriormente, que el a mtodo descrito no es el ms apropiado desde una perspectiva de e a simple usuario. Como alternativa, la utilizacin de diferencias o de listas exige unicamente la creacin de un diccionario de o trminos, independizando el programa lgico de la cadena de e o entrada considerada en cada caso. Anal ticamente, el conjunto de clusulas a considerar puede ser el siguiente: a
analiza(Arbol, F) :- palindromo(Arbol,F\[]). palindromo(p(C,P,C),P0\P3) :- caracter(C,P0\P1), palindromo(P,P1\P2), caracter(C,P2\P3). palindromo(p(nil),P0\P0). palindromo(p(C),P0\P1) :- caracter(C,P0\P1). caracter(a,[a|X]\X). caracter(b,[b|X]\X).

donde previamente habremos denido el operador diferencia de listas tal y como se ha hecho en el ejemplo 11.2.1. Ahora, las dos ultimas clusulas denen el diccionario, pero sin referenciar a de forma expresa una cadena de entrada en particular. Ante la pregunta :- analiza(Arbol,[a,b,a,a,a,b,a]). obtenemos la respuesta Arbol p(a,p(b,p(a,p(a),a),b),a) Esto es, la misma obtenida con la tcnica anterior. Observemos e que la unica exigencia en relacin a la introduccin de la cadena o o de caracteres de entrada es la utilizacin de una lista cuyos o elementos son justamente dichos caracteres. Es importante tambin indicar cul es en este ultimo caso la lectura declarativa: e a Tenemos un palndromo entre las posiciones P0 y P3 cuyo arbol sintctico viene dado por la funcin a o p(C,P,C), si tenemos:

212

Lgica y Anlisis Sintctico o a a

1. Un carcter C entre las posiciones P0 y P1 y cuyo a arbol es C. 2. Un palndromo entre las posiciones P1 y P2, cuyo arbol viene dado por P. 3. El mismo carcter C entre las posiciones P2 y P3, a con un arbol asociado que tambin viene dado por e C. En todo caso, la palabra vaca es un palndromo. Tenemos un palndromo entre las posiciones P0 y P1 con un arbol asociado p(C), si tenemos un carcter C a entre esas mismas posiciones. El carcter a puede constituir el primer elemento de a una lista. Ello se traduce en este caso en que es una palabra del diccionario que deseamos reconocer. Esto es, a es uno de los caracteres que pueden formar parte de los palndromos que queremos reconocer. El arbol reconocido es en este caso el mismo carcter a. a El carcter b verica las mismas condiciones que el a carcter a. a

14.2

El problema de la recursividad por la izquierda

El problema que tratamos de abordar ahora es el de la implementacin de un analizador sintctico para las expresiones o a con parntesis bien equilibrados. Como paso previo, es necesario e el dise o de una gramtica que genere como lenguaje a las n a mismas. Una primera posibilidad ser la siguiente: a (0) (1) (2) (3) F rase F rase F rase F rase ( F rase ) F rase F rase carcter a

14.2. El problema de la recursividad por la izquierda

213

Esta gramtica es interesante por varias razones, entre ellas a el hecho de que pueden generarse innitos arboles sintcticos a para una cadena de entrada de longitud nita. Ello queda de maniesto en la gura 14.1, que muestra los innitas posibilidades para las estructuras sintcticas de salida dada la a cadena de entrada (), donde las l neas discontinuas representan las ambig edades, las echas los ciclos en los arboles, y los iconos u los nodos compartidos. Si bien esta caracter stica no impide una
S

S S S

 
S

 S
( S

Figura 14.1: Bosque sintctico para la cadena (), con innitos arboles a

implementacin vlida en Prolog, s lo hace el hecho de que se o a trate de una gramtica recursiva por la izquierda. En efecto, a en la seccin 6.4 hab o amos hecho hincapi en el hecho de que e el algoritmo de resolucin constru los correspondientes arboles o a en profundidad. Ello imped la terminacin de los programas a o cuando estos eran recursivos por la izquierda. En este caso, el hecho de que la gramtica de partida posea esta caracter a stica, se traduce en la generacin de un programa Prolog igualmente o recursivo por la izquierda y por tanto incompleto desde un punto de vista operacional, tal y como se hab justicado en la a

214

Lgica y Anlisis Sintctico o a a

seccin 6.6. En efecto, el analizador sintctico correspondiente o a vendr dado por el siguiente conjunto de clusulas: a a
analiza(F, Arbol) :- frase(F\[], Arbol). frase(P0\P3, f(Abierto,F,Cerrado)) :parentesis_abierto(P0\P1, Abierto), frase(P1\P2, F), parentesis_cerrado(P2\P3, Cerrado). frase(P0\P2, f(F1,F2)) :- frase(P0\P1, F1), frase(P1\P2, F2). frase(P0\P1, f(T)) :- terminal(P0\P1, T). frase(P0\P0, f(nil)). terminal([a|X]\X, a). parentesis_abierto([(|X]\X, (). parentesis_cerrado([)|X]\X, )).

el cual ante la pregunta :- analiza([(,)], Arbol). entra en un bucle innito que provoca el agotamiento de la memoria. La solucin pasa por suprimir la recursividad por o la izquierda en la gramtica de partida. En este punto, tenemos a dos alternativas posibles: 1. Dise ar una nueva gramtica no recursiva por la izquierda. n a 2. Transformar, de forma sistemtica y automtica, la a a gramtica de la que disponemos en otra que genere el mismo a lenguaje, pero en la que la recursividad por la izquierda sea eliminada. Teniendo en cuenta lo habitual de la situacin discutida, o haremos una completa descripcin del proceso de transformacin o o de una gramtica recursiva por la izquierda a otra directamente a implementable en Prolog. Ante todo, presentamos un resultado muy simple que permite la eliminacin de este tipo de o recursividad cuando es directa.

14.2. El problema de la recursividad por la izquierda

215

Teorema 14.2.1 Sea G = (N, , P, S) una gramtica de a contexto libre, y sean A A1 | . . . | Ar todas las Aproducciones de G para las cuales A aparece como primer smbolo del lado derecho de la produccin. Sean nalmente A 1 | o . . . | s el resto de las A-producciones. Entonces la gramtica a G1 = (N1 , 1 , P1 , S1 ) en la cual N1 = N {B}, S1 = S, 1 = , y donde las A-producciones de P han sido sustituidas por: A i A i B 1is B i B i B 1ir

genera el mismo lenguaje que G. 2 El mtodo general para eliminar cualquier tipo de e recursividad por la izquierda es considerablemente ms a complicado y consiste en trasformar la gramtica en una a equivalente escrita en la Forma Normal de Greibach [1]. Las gramticas escritas siguiendo este mtodo se caracterizan a e por incrementar la longitud del prejo de terminales con la aplicacin de cada regla. En consecuencia, el primer elemento o de la parte derecha de toda regla debe ser un terminal. Evitando la aparicin de no terminales en tal posicin, se evita o o completamente la aparicin de recursividades a la izquierda. El o precio a pagar viene dado por la obtencin de una gramtica nal o a muy alejada, en cuanto a su forma, de la dise ada originalmente n por el programador. A continuacin se muestran los distintos conjuntos de reglas o que se van obteniendo como consecuencia de la aplicacin de los o pasos conducentes a la normalizacin de la gramtica de partida: o a 1. El primero consiste en crear un nuevo s mbolo inicial que tan slo aparezca en el lado izquierdo de una sola o regla. Esto es, se trata de generar la correspondiente gramtica aumentada. Con ello obtenemos las siguientes a

216

Lgica y Anlisis Sintctico o a a

producciones:
(0) (1) (2) (3) (4) S F rase F rase F rase F rase F rase ( F rase ) F rase F rase carcter a

2. En el siguiente paso se deben eliminar todas las reglas. Si L(G), como es nuestro caso, se permite la existencia de la regla S . El nuevo conjunto de reglas que se obtiene es el siguiente:
(0) (1) (2) (3) (4) (5) S S F rase F rase F rase F rase F rase () ( F rase ) F rase F rase carcter a

3. A continuacin se debe proceder a transformar las reglas o de transmisin simple. Una vez eliminadas, la gramtica o a queda como sigue:
(0) (1) (2) (3) (4) (5) (6) (7) (8) S S S S S F rase F rase F rase F rase () ( F rase ) F rase F rase carcter a () ( F rase ) F rase F rase carcter a

4. Puesto que en la gramtica anterior no hay s a mbolos in tiles, ya que cada uno de los no terminales contribuye a u la generacin de las sentencias del lenguaje, podemos pasar o a transformar la gramtica a una forma normal intermedia a denominada Forma Normal de Chomsky [1], en la que cada

14.2. El problema de la recursividad por la izquierda

217

regla tiene una de las formas siguientes: A a A BC S donde A, B N , a , y S es el axioma de la gramtica. a El conjunto de reglas de la gramtica escrita de esta forma a es ahora el siguiente:
(0) (1) (2) (3) (4) (5) S S S S S F rase Pi Pd Pi T F rase F rase carcter a Pi Pd (6) (7) (8) (9) (10) (11) F rase F rase F rase Pi Pd T Pi T F rase F rase carcter a ( ) F rase P d

5. Para la realizacin de los siguientes pasos es preciso o establecer un orden entre los s mbolos no terminales. En nuestro caso, el orden elegido ha sido el siguiente: S, F rase, T, P i, P d. Una vez hecho esto, los pasos restantes se encaminan hacia la consecucin de una o gramtica en la que las reglas sean de la forma a A a A 1 A2 . . . An A a S donde A N , a , y S es el axioma. 6. A continuacin se proceder a eliminar la recursividad o a izquierda directa en F rase, el primer no terminal en el orden establecido para el que existe este tipo de recursividad, aplicando el teorema 14.2.1. Con ello obtenemos las siguientes reglas:
(0) (1) (2) (3) (4) (5) (6) (7) S (8) F rase S Pi Pd (9) F rase S Pi T (10) F rase S F rase F rase (11) P i S carcter a (12) P d F rase P i P d (13) T F rase P i T (14) Z F rase carcter a (15) Z Pi Pd Z Pi T Z carcter Z a ( ) F rase P d F rase Z F rase

218

Lgica y Anlisis Sintctico o a a

7. Al transformar la regla 13 para evitar que el primer elemento de la parte derecha de la regla sea un no terminal con menor orden que T , obtenemos una gramtica cuyas a reglas son el resultado de copiar todas las de la gramtica a anterior excepto la 13, la cual es reemplazada por el conjunto de reglas obtenido mediante la sustitucin de o F rase por cada una de las producciones que tienen a dicho no terminal como lado izquierdo. Puesto que en todos los casos el primer elemento de la parte derecha de las reglas encabezadas por F rase tiene orden mayor que T o bien son s mbolos terminales, no ser preciso volver a repetir este a paso para las nuevas reglas obtenidas. En el caso hipottico e de que hubisemos obtenido una regla con recursin directa e o sobre T 3 ser preciso aplicar de nuevo el paso anterior para a eliminarla. El n mero de iteraciones por estos dos pasos u viene acotado por el orden de T . La gramtica resultante a se muestra a continuacin: o
(0) S (1) S (2) S (3) S (4) S (5) F rase (6) F rase (7) F rase (8) F rase (9) F rase (10) F rase Pi Pd (11) P i Pi T (12) P d F rase F rase (13) T carcter a (14) T Pi Pd (15) T Pi T (16) T carcter a (17) T Pi Pd Z (18) T Pi T Z (19) Z carcter Z a (20) Z

( ) Pi Pd Pd Pi T Pd carcter P d a Pi Pd Z Pd Pi T Z Pd carcter Z P d a F rase Z F rase

8. En el ultimo paso sustituimos los no terminales que aparecen como primer s mbolo del lado derecho de las reglas por la parte derecha de las producciones en la cual dicho no terminal aparece como lado izquierdo. Esto es, dadas

caso se dar si existiese una regla de F rase que tuviese a T como primer s a mbolo del lado derecho, lo cual es en principio posible ya que T tiene mayor orden que F rase.

3 este

14.2. El problema de la recursividad por la izquierda

219

las reglas A B C 1 , C2 . . . Cn B w1 | w2 . . . | wm donde A, B, Ci N y wi transformar en a , la primera de ellas se

A w 1 C1 , C2 . . . Cn | w2 C1 , C2 . . . Cn . . . | wm C1 , C2 . . . Cn El proceso de transformacin comenzar por las reglas con o a el lado izquierdo de mayor orden. Una vez terminado todo el proceso obtenemos una gramtica en Forma Normal a de Greibach, que en nuestro caso est constituida por el a siguiente conjunto de producciones :
(0) (1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) S S S S S S S S S S F rase F rase F rase F rase F rase F rase (16) P i ( Pd (17) P d (T (18) T carcter a (19) T ( P d F rase (20) T ( T F rase (21) T carcter F rase (22) T a ( Pd Z (23) T (T Z (24) Z carcter Z a (25) Z ( Pd (26) Z (T (27) Z carcter a (28) Z ( Pd Z (29) Z (T Z (30) Z carcter Z a (31) Z (32) Z ( ) ( Pd Pd ( T Pd carcter P d a ( Pd Z Pd ( T Z Pd carcter Z P d a ( Pd (T carcter a ( Pd Z (T Z carcter Z a ( Pd Z Z (T ZZ carcter Z Z a

Tal como se hizo anteriormente, podemos traducir directamente las producciones de la gramtica en reglas de Prolog, obteniendo a

220

Lgica y Anlisis Sintctico o a a

el programa de las pginas 221 y 222. Esta implementacin ya a o no produce bucles innitos. Como ejemplo, volvamos a tomar la pregunta conictiva mostrada anteriormente: :- analiza([(,)],Arbol). La respuesta que obtenemos es el arbol correcto correspondiente a la expresin (): o Arbol s((, pd())) Supongamos ahora que la pregunta es la dada por la clusula: a :- analiza([(,(,a,),),(,a,)],Arbol). entonces la respuesta es la expresada por la sustitucin o
Arbol s((, t((, t(a, pd())), pd())), frase((, t(a, pd()))))

Obsrvese que la estructura de los arboles de las respuestas, e aunque correcta, se asemeja poco a la pensada para la gramtica a 4 original y resulta dif cilmente reconocible .

es el inconveniente fundamental de aplicar un mtodo sistemtico de eliminacin e a o de la recursividad por la izquierda.

4 este

14.2. El problema de la recursividad por la izquierda

221

analiza(F,Arbol) :- s(F\[],Arbol). s(P0\P0,s(nil)). s(P0\P2,s(Abierto,Pd)) :parentesis_abierto(P0\P1,Abierto), pd(P1\P2,Pd). s(P0\P2,s(Abierto,T)) :parentesis_abierto(P0\P1,Abierto), t(P1\P2,T). s(P0\P1,s(Terminal)) :- terminal(P0\P1,Terminal). s(P0\P3,s(Abierto,Pd,Frase)) :parentesis_abierto(P0\P1,Abierto), pd(P1\P2,Pd), frase(P2\P3,Frase). s(P0\P3,s(Abierto,T,Frase)) :parentesis_abierto(P0\P1,Abierto), t(P1\P2,T), frase(P2\P3,Frase). s(P0\P2,s(Terminal,Frase)) :terminal(P0\P1,Terminal), frase(P1\P2,Frase). s(P0\P3,s(Abierto,Pd,Z)) :parentesis_abierto(P0\P1,Abierto), pd(P1\P2,Pd), z(P2\P3,Z). s(P0\P3,s(Abierto,T,Z)) :parentesis_abierto(P0\P1,Abierto), t(P1\P2,T), z(P2\P3,Z). s(P0\P2,s(Terminal,Z)) :terminal(P0\P1,Terminal), z(P1\P2,Z). frase(P0\P2,frase(Abierto,Pd)) :parentesis_abierto(P0\P1,Abierto), pd(P1\P2,Pd). frase(P0\P2,frase(Abierto,T)) :parentesis_abierto(P0\P1,Abierto), t(P1\P2,T). frase(P0\P1,frase(Terminal)) :- terminal(P0\P1,Terminal). frase(P0\P3,frase(Abierto,Pd,Z)) :parentesis_abierto(P0\P1,Abierto), pd(P1\P2,Pd), z(P2\P3,Z). frase(P0\P3,frase(Abierto,T,Z)) :parentesis_abierto(P0\P1,Abierto), t(P1\P2,T), z(P2\P3,Z). pi(P0\P1,pi(Abierto)) :- parentesis_abierto(P0\P1,Abierto). pd(P0\P1,pd(Cerrado)) :- parentesis_cerrado(P0\P1,Cerrado).

222

Lgica y Anlisis Sintctico o a a

t(P0\P3,t(Abierto,Pd,Pd)) :parentesis_abierto(P0\P1,Abierto), pd(P1\P2,Pd), pd(P2\P3,Pd). t(P0\P3,t(Abierto,T,Pd)) :parentesis_abierto(P0\P1,Abierto), t(P1\P2,T), pd(P2\P3,Pd). t(P0\P2,t(Terminal,Pd)) :terminal(P0\P1,Terminal), pd(P1\P2,Pd). t(P0\P4,t(Abierto,Pd,Z,Pd)) :parentesis_abierto(P0\P1,Abierto), pd(P1\P2,Pd), z(P2\P3,Z), pd(P3\P4,Pd). t(P0\P4,t(Abierto,T,Z,Pd)) :parentesis_abierto(P0\P1,Abierto), t(P1\P2,T), z(P2\P3,Z), pd(P3\P4,Pd). t(P0\P3,t(terminal,Z,Pd)) :terminal(P0\P1,Terminal), z(P1\P2,Z), pd(P2\P3,Pd). z(P0\P2,z(Abierto,Pd)) :parentesis_abierto(P0\P1,Abierto), pd(P1\P2,Pd). z(P0\P2,z(Abierto,T)) :parentesis_abierto(P0\P1,Abierto), t(P1\P2,T). z(P0\P1,z(Terminal)) :- terminal(P0\P1,Terminal). z(P0\P3,z(Abierto,Pd,Z)) :parentesis_abierto(P0\P1,Abierto), pd(P1\P2,Pd), z(P2\P3,Z). z(P0\P3,z(Abierto,T,Z)) :parentesis_abierto(P0\P1,Abierto), t(P1\P2,T), z(P2\P3,Z). z(P0\P2,z(Terminal,Z)) :terminal(P0\P1,Terminal), z(P1\P2,Z). z(P0\P4,z(Abierto,Pd,Z,Z)) :parentesis_abierto(P0\P1,Abierto), pd(P1\P2,Pd), z(P2\P3,Z), z(P3\P4,Z). z(P0\P4,z(Abierto,T,Z,Z)) :parentesis_abierto(P0\P1,Abierto), t(P1\P2,T), z(P2\P3,Z), z(P3\P4,Z). z(P0\P3,z(Terminal,Z,Z)) :terminal(P0\P1,Terminal), z(p1\P2,Z). terminal([a|X]\X,a). parentesis_abierto([(|X]\X,(). parentesis_cerrado([)|X]\X,))

Cap tulo 15

Anlisis del Lenguaje a Natural


El objetivo de este cap tulo es el de abordar el anlisis prctico a a de textos escritos en lenguaje natural, mediante la utilizacin o de Prolog. Para ello aplicaremos el concepto de DCG, aunque este caso particular presente caracter sticas propias que lo hacen especialmente interesante, lo que justica un tratamiento aparte. Ms concretamente, nuestro objetivo ser el de mostrar la a a adecuacin de Prolog para el tratamiento de ciertos problemas o espec cos: La ambig edad, a todos los niveles: lxico, sintctico y u e a semntico. a La existencia de dependencias contextuales, lo cual implica la introduccin de restricciones semnticas a nivel de las o a reglas sintcticas. a Para ilustrar la discusin que sigue, construiremos una o gramtica que describa un peque o subconjunto del espa ol, a n n as como el analizador sintctico capaz de tratarlo. Nuestro a propsito ser ante todo didctico, por lo que en ning n o a a u momento pretendemos presentar los resultados expuestos como un sistema completo en cuanto a su dise o. Por el contrario, n
223

224

Anlisis del Lenguaje Natural a

nuestro animo es el de proponer un conjunto de tcnicas cuya e extensin, en cuanto a su aplicacin al problema concreto, se o o deja al lector.

15.1

Anlisis sintctico a a

Antes de introducirnos de lleno en el mundo de las DCGs, examinaremos una peque a gramtica de contexto libre que nos n a permitir analizar frases sencillas tales como a un hombre ama a una mujer En primer lugar, debemos escribir las reglas de la gramtica a que genere el lenguaje deseado y que son las que se muestran a continuacin: o
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) F rase F rase nominal | | | | | | | F rase nominal F rase verbal Determinante N ombre Clausula relativa a Determinante N ombre Clausula relativa N ombre V erbo transitivo F rase nominal V erbo intransitivo que F rase verbal F rase verbal un una hombre mujer ama

F rase verbal Clausula relativa

Determinante N ombre V erbo transitivo

Mediante esta gramtica podemos generar sentencias que a estn formadas por una frase nominal ms una frase verbal. a a Las frases nominales desempe an las funciones de sujeto o n de complementos del verbo. En su forma ms sencilla estn a a formadas unicamente por un sustantivo, o un determinante y un sustantivo, a los que puede preceder la preposicin a o cuando desempe an la funcin de complemento del verbo. n o Adicionalmente, puede poseer una clusula relativa, que a generalmente se construye anteponiendo el relativo que a una frase verbal, aunque puede estar constituida tan solo por

15.1. Anlisis sintctico a a

225

esta ultima. Una frase verbal est formada por un verbo, a que en el caso de tener carcter transitivo debe ir seguido por a un complemento directo en la forma de una frase nominal. Con el objeto de simplicar la presentacin de los conceptos o fundamentales, no se contempla la existencia de complementos indirectos ni circunstanciales. 15.1.1 Una tcnica simple e

Siguiendo una tcnica estndar de contruccin de DCGs, e a o vamos a asociar a cada no terminal de la gramtica un a predicado binario con su mismo nombre, en el cual los argumentos representan las posiciones entre las que se sit a la u categor sintctica referida. Los argumentos de tales predicados a a representan los puntos de inicio y nal de la cadena de caracteres generada por el no terminal correspondiente. La tcnica aplicada e en este caso es exactamente la misma considerada para el problema del pal ndromo en la subseccin 14.1.1. El resultado o obtenido es el programa de la pgina 226. a La semntica declarativa de su primera regla es a Podemos reconocer una frase entre las posiciones S0 y S, si podemos reconocer una frase nominal entre S0 y S1, y una verbal entre S1 y S. La semntica de las dems clusulas es fcilmente deducible a a a a por analog Para representar los s a. mbolos terminales se ha utilizado un predicado ternario, denominado conecta. La utilizacin de conecta(S0,T,S1) signica o El smbolo terminal T est localizado entre las a posiciones S0 y S1 de la cadena de entrada. Cada frase que se desee analizar deber ser transformada en su a correspondiente conjunto de predicados conecta. Por ejemplo, la sentencia un hombre ama a una mujer

226

Anlisis del Lenguaje Natural a

frase(S0,S) :- frase_nominal(S0,S1), frase_verbal(S1,S). frase_nominal(S0,S) :- determinante(S0,S1), nombre(S1,S2), clausula_relativa(S2,S). frase_nominal(S0,S) :- conecta(S0,a,S1), determinante(S1,S2), nombre(S2,S3), clausula_relativa(S3,S). frase_nominal(S0,S) :- nombre(S0,S). frase_verbal(S0,S) :- verbo_transitivo(S0,S1), frase_nominal(S1,S). frase_verbal(S0,S) :- verbo_intransitivo(S0,S). clausula_relativa(S0,S) :- conecta(S0,que,S1), frase_verbal(S1,S). clausula_relativa(S0,S) :- frase_verbal(S0,S). clausula_relativa(S,S). determinante(S0,S) :- conecta(S),un,S). determinante(S0,S) :- conecta(S),una,S). nombre(S0,S) :- conecta(S0,hombre,S). nombre(S0,S) :- conecta(S0,mujer,S). verbo_transitivo(S0,S) :- conecta(S0,ama,S).

15.1. Anlisis sintctico a a

227

se traduce en1
conecta(1,un,2). conecta(2,hombre,3). conecta(3,ama,4). conecta(4,a,5). conecta(5,una,6). conecta(6,mujer,7).

Para probar ahora que esta frase es gramaticalmente correcta, deber realizrsele al intrprete Prolog la siguiente pregunta: a a e :- frase(1,7). cuya semntica declarativa viene dada por: a Es posible reconocer una frase entre las posiciones 1 y 7 del texto ? Es importante resaltar que la representacin de una o gramtica de contexto libre es independiente de los datos, con a este tipo de tcnica. En efecto, la representacin real de la e o cadena que va a ser analizada no es conocida, sino que se tiene en cuenta el objetivo establecido por la pregunta y el predicado conecta. 15.1.2 Una tcnica exible e

Si en vez de utilizar un entero para etiquetar un determinado punto en una cadena, utilizsemos una lista con los s a mbolos ubicados a partir de ese punto en la cadena, no ser necesario a emplear una clusula conecta individual para cada s a mbolo de la cadena. En su lugar, se podr denir con una unica clusula a a el predicado conecta, en la forma: conecta([P | S]\S,P). que denotacionalmente signica
1 debemos hacer notar que no se aplica factorizacin alguna en el anlisis lxico para o a e reducir el tamao del diccionario, sino que ste contiene todas las formas derivadas de n e cada palabra. Esta ultima funcionalidad es perfectamente implementable en la prctica, a pero por cuestiones exclusivamente didcticas hemos decidido limitarnos al tratamiento a de la componente sintctica del lenguaje. a

228

Anlisis del Lenguaje Natural a

La posicin de la cadena etiquetada por la lista con o cabeza P y cola S est conectada mediante el smbolo a P a la posicin de la cadena etiquetada como S. o En consecuencia, podr amos reescribir la pregunta formulada anteriormente de la siguiente manera: :-frase([un,hombre,ama,a,una,mujer]\[]). Se trata en esencia de repetir el razonamiento que hab amos hecho para el caso del pal ndromo en la subseccin 14.1.2. o Un diccionario ms compacto a Una de las primeras ventajas que se obtiene al utilizar DCGs es la posibilidad de denir el diccionario de una manera ms a compacta y eciente. Para ello, en vez de utilizar clusulas del a tipo categora :- palabra. utilizaremos clusulas de la forma: a categora :- P, es categora(P, S1 , . . . , Sn ). De este modo, la clusula a nombre(S0\S) :- gato. se traduce2 en nombre(Palabra) :- conecta(S0\S,Palabra), es nombre(Palabra). con un conjunto adicional de predicados en los que se especican los valores vlidos para que una palabra sea considerada un a nombre. Por ejemplo, mediante
2 los argumentos S , . . . , S a a n se considerarn opcionales, y se reservarn para la 1 introduccin de las restricciones semnticas derivadas de la consideracin de diversos o a o accidentes gramaticales, tales como las concordancias de gnero y nmero. e u

15.2. Anlisis semntico a a es_nombre(gato). es_nombre(perro). es_nombre(hombre). es_nombre(mujer).

229

establecemos como hechos que gato, perro, hombre y mujer son nombres. La construccin de estructuras sintcticas o a La utilizacin de argumentos adicionales en los no terminales o permite construir estructuras que representen el avance del proceso de anlisis sintctico de las oraciones. La estructura a a generada por un no terminal se construye cuando se expande dicho no terminal como consecuencia del proceso de resolucin. o En la pgina 230 se muestra una versin modicada, para tal a o n, de la gramtica presentada anteriormente. a La semntica declarativa de la primera clusula es a a Una frase con estructura f(FN,FV) est formada por a una frase nominal que da lugar a la estructura FN y una frase verbal que da lugar a FV. Como se puede observar, la estructura construida a partir de las clusulas se corresponde con una representacin del arbol de a o anlisis sintctico. En nuestro caso, la ra de dicho arbol est a a z a etiquetada con el funtor f.

15.2

Anlisis semntico a a

En los lenguajes de comunicacin humana existen multitud o de aspectos contextuales que no pueden ser representados adecuadamente mediante la utilizacin de gramticas de o a contexto libre. Tal es el caso de las concordancias de gnero e y n mero. La utilizacin de un formalismo DCG nos permite u o introducir restricciones semnticas en las clusulas mediante a a una adecuada utilizacin de las llamadas a procedimientos que o explota de forma gratuita el concepto de unicacin. o

230

Anlisis del Lenguaje Natural a

frase(f(FN,FV),S0\S) :frase_nominal(FN,S0\S1), frase_verbal(FV,S1\S). frase_nominal(fn(Det,Nom,Rel),S0\S) :determinante(Det,S0\S1), nombre(Nom,S1\S2), clausula_relativa(Rel,S2\S). frase_nominal(fn(a,Det,Nom,Rel),S0\S) :conecta(S0\S1,a), determinante(Det,S1\S2), nombre(Nom,S2\S3), clausula_relativa(Rel,S3\S). frase_nominal(fn(Nom),S0\S) :- nombre(Nom,S0\S). frase_verbal(fv(VT,FN),S0\S) :verbo_transitivo(VT,S0\S1), frase_nominal(FN,S1\S). frase_verbal(fv(VI),S0\S) :- verbo_intransitivo(VI,S0\S). clausula_relativa(rel(que,FV),S0\S) :conecta(S0\S1,que), frase_verbal(FV,S1\S). clausula_relativa(rel(FV),S0\S) :- frase_verbal(FV,S0\S). clausula_relativa(rel(nil),S\S). determinante(det(Palabra),S0\S) :conecta(S0\S,Palabra), es_determinante(Palabra). nombre(nom(Palabra),S0\S) :conecta(S0\S,Palabra), es_nombre(Palabra). verbo_transitivo(vt(Palabra),S0\S) :conecta(S0\S,Palabra), es_verbo_trans(Palabra). es_determinante(mi). es_determinante(un). es_determinante(una). es_nombre(gato). es_nombre(hombre). es_nombre(mujer). es_verbo_trans(ama).

15.2. Anlisis semntico a a

231

15.2.1

Concordancias de gnero y nmero e u

Mediante la utilizacin de las llamadas a procedimientos o incluidas en el formalismo de las DCGs es posible representar tales concordancias al nivel de anlisis sintctico, incluyendo un a a conjunto de restricciones semnticas. a Incorporacin del nmero o u Para establecer las concordancias de n mero, algunos de los no u terminales debern poseer argumentos adicionales cuyo rango a de valores posibles viene representado por el conjunto {singular, plural, neutro} As mismo, los predicados mediante los cuales se representa el diccionario debern ser modicados, ya que es preciso incluir a un nuevo argumento para indicar el n mero de la palabra u correspondiente y otro ms que proporcione el lema de la a palabra3 . En el entorno que estamos considerando, no es conveniente utilizar el lexema en lugar del lema debido al gran n mero de irregularidades existentes en el espa ol. u n Tras aplicar los cambios mencionados a las clusulas a involucradas, obtenemos el conjunto de clusulas de la a pgina 232. a Ahora ya podemos analizar frases del tipo un gato come ratones o unos gatos comen un ratn. Resulta interesante o estudiar la semntica declarativa de algunas de las clusulas. a a Por ejemplo, en la primera tenemos que: Una frase es correcta si est formada por una a frase nominal y una frase verbal que concuerdan en nmero. u
3 el lema es la forma que encabeza el grupo de palabras derivadas de una dada. En el caso de sustantivos, adjetivos y art culos, el lema lo constituye la forma masculina y singular; en el caso de los verbos, el innitivo.

232

Anlisis del Lenguaje Natural a

frase(f(FN,FV),S0\S) :frase_nominal(Numero,FN,S0\S1),frase_verbal(Numero,FV,S1\S). frase_nominal(Numero,fn(Det,Nom,Rel),S0\S) :determinante(Numero,Det,S0\S1), nombre(Numero,Nom,S1\S2), clausula_relativa(Numero,Rel,S2\S). frase_nominal(Numero,fn(a,Det,Nom,Rel),S0\S) :conecta(S0\S1,a), determinante(Numero,Det,S1\S2), nombre(Numero,Nom,S2\S3),clausula_relativa(Numero,Rel,S3\S). frase_nominal(Numero,fn(Nom),S0\S) :- nombre(Numero,Nom,S0\S). frase_verbal(Numero_verbo,fv(VT,FN),S0\S) :verbo_transitivo(Numero_verbo,VT,S0\S1), frase_nominal(Numero_nombre,FN,S1\S). frase_verbal(Numero,fv(VI),S0\S) :verbo_intransitivo(Numero,VI,S0\S). clausula_relativa(Numero,rel(que,FV),S0\S) :conecta(S0\S1,que), frase_verbal(Numero,FV,S1\S). clausula_relativa(Numero,rel(FV),S0\S) :frase_verbal(Numero,FV,S0\S). clausula_relativa(Numero,rel(nil),S\S). determinante(Numero,det(Palabra),S0\S) :conecta(S0\S,Palabra), es_determinante(Numero,Palabra). nombre(Numero,nom(Palabra),S0\S) :conecta(S0\S,Palabra), es_nombre(Numero,Palabra,Lema). verbo_transitivo(Numero,vt(Palabra),S0\S) :conecta(S0\S,Palabra), es_verbo_trans(Numero,Palabra,Lema). es_determinante(singular,un,un). es_determinante(singular,una,una). es_determinante(plural,unos,un). es_determinante(plural,unas,un). es_nombre(singular,gato,gato). es_nombre(singular,gata,gato). es_nombre(plural,gatos,gato). es_nombre(plural,gatas,gato). es_verbo_trans(singular,come,comer). es_verbo_trans(plural,comen,comer).

15.2. Anlisis semntico a a

233

Un caso distinto aparece en la tercera clusula relativa a las a frases verbales, ya que expresa Una frase verbal es correcta si est constituida por un a verbo transitivo y una frase nominal. La diferencia radica en que ya no se fuerza la concordancia, puesto que es l cito construir frases como un gato come ratones , en la que el verbo come est en singular mientras que la frase a nominal ratones est en plural. Es por ello que resulta preciso a distinguir entre Numero verbo y Numero nombre. Incorporacin del gnero o e Con el ultimo conjunto de clusulas obtenido, hemos creado una a gramtica que permite construir frases del tipo una gato come a ratones gracias a la carencia total de restricciones en cuanto al gnero. El tratamiento de las concordancias de gnero se realiza e e de manera anloga al comentado para las concordancias de a n mero. Por consiguiente, se introduce un argumento adicional u en los no terminales que contendr un valor del conjunto a {masculino, f emenino, neutro} As mismo, los predicados mediante los cuales se construye el diccionario vern aumentada su aridad en una unidad para a incorporar un argumento en el cual se almacene el gnero de e la palabra. El lema se sigue almacenando en el argumento creado para establecer las concordancias de n mero. Una vez u realizados estos cambios, obtenemos el conjunto de clusulas de a las pginas 234 y 235. a En este caso ha sido preciso modicar menos clusulas que a cuando hab amos introducido el n mero, puesto que existen u construcciones para las cuales la separacin en gneros no o e es aplicable. Concretamente, las frases verbales no tienen dependencias de gnero, puesto que su n cleo, el verbo4 , no e u
4 que

determina el nmero de la frase verbal. u

234

Anlisis del Lenguaje Natural a

frase(f(FN,FV),S0\S) :- frase_nominal(Numero,Genero,FN,S0\S1), frase_verbal(Numero,Genero,FV,S1\S). frase_nominal(Numero,Genero,fn(Det,Nom,Rel),S0\S) :determinante(Numero,Genero,Det,S0\S1), nombre(Numero,Genero,Nom,S1\S2), clausula_relativa(Numero,Genero,Rel,S2\S). frase_nominal(Numero,Genero,fn(a,Det,Nom,Rel),S0\S) :conecta(S0\S1,a), determinante(Numero,Genero,Det,S1\S2), nombre(Numero,Genero,Nom,S2\S3), clausula_relativa(Numero,Rel,S3\S). frase_nominal(Numero,Genero,fn(Nom),S0\S) :nombre(Numero,Genero,Nom,S0\S). frase_verbal(Numero_verbo,fv(VT,FN),S0\S) :verbo_transitivo(Numero_verbo,VT,S0\S1), frase_nominal(Numero_nombre,Genero,FN,S1\S). frase_verbal(Numero,fv(VI),S0\S) :verbo_intransitivo(Numero,VI,S0\S). clausula_relativa(Numero,rel(que,FV),S0\S) :conecta(S0\S1,que), frase_verbal(Numero,FV,S1\S). clausula_relativa(Numero,rel(FV),S0\S) :frase_verbal(Numero,FV,S0\S). clausula_relativa(Numero,rel(nil),S\S).

15.2. Anlisis semntico a a

235

determinante(Numero,Genero,det(Palabra),S0\S) :conecta(S0\S,Palabra), es_determinante(Numero,Genero,Palabra,Lema). nombre(Numero,Genero,nom(Palabra),S0\S) :conecta(S0\S,Palabra), es_nombre(Numero,Genero,Palabra,Lema). verbo_transitivo(Numero,vt(Palabra),S0\S) :conecta(S0\S,Palabra), es_verbo_trans(Numero,Palabra,Lema). es_determinante(singular,masculino,un,un). es_determinante(singular,femenino,una,una). es_determinante(plural,masculino,unos,un). es_determinante(plural,femenino,unas,un). es_nombre(singular,masculino,gato,gato). es_nombre(singular,femenino,gata,gato). es_nombre(plural,masculino,gatos,gato). es_nombre(plural,femenino,gatas,gato). es_nombre(singular,raton,raton) es_nombre(singular,ratones,raton). es_verbo_trans(singular,come,comer). es_verbo_trans(plural,comen,comer).

236

Anlisis del Lenguaje Natural a

las posee a este nivel. Consecuentemente, al no ser aplicable el gnero a las frases verbales, tampoco lo es a las frases relativas. e 15.2.2 El signicado de las frases

El problema que abordamos ahora es, sin duda, el ms complejo a en lo que al tratamiento de los lenguajes naturales se reere: la representacin de su semntica. Se trata, sin embargo, de o a una cuestin inevitable en problemas tan cercanos como la o traduccin automtica entre lenguas naturales o la generacin o a o de interfaces en lengua natural. La solucin que a continuacin o o esbozamos es, pese a sus innegables limitaciones, una tcnica de e aplicacin com n entre la comunidad especializada. o u En esencia la idea es simple y atractiva, se trata de encontrar una representacin formal de los conceptos usados en los o lenguajes de comunicacin humana. Una vez establecido el o objetivo, la experiencia nos permite asegurar que: La utilizacin de lenguajes de programacin lgica parece o o o adaptarse adecuadamente a la implementacin prctica de o a analizadores de lenguajes naturales. La base que sirve de fundamento a los lenguajes lgicos, o el clculo de predicados, presenta todas las garant de a as formalidad. Los conceptos expresados en el clculo de predicados a constituyen un lenguaje universal, y por tanto aplicable a cualquier tipo de nocin, independientemente de cul sea o a la forma externa de expresar dicha nocin. o En estas condiciones, la idea de considerar el clculo de a predicados como punto de partida para la representacin de o la semntica de los lenguajes de comunicacin humana parece a o reunir buenas espectativas de xito. Para ilustrar mejor este e proceso volveremos a nuestra peque a gramtica del espa ol y n a n trataremos de construir un traductor que convierta frases en espa ol como n

15.2. Anlisis semntico a a

237

todo hombre que vive ama a una mujer en sus equivalentes en lgica de predicados, en este caso: o ( X : (hombre(X) & vive(X) Y & ama(X, Y ))) donde :,& y son operadores binarios injos que deben ser denidos como tales en Prolog. Para ello utilizaremos las siguientes declaraciones:
:- op(900, yfx, [=>]). :- op(800, yfx, [&]). :- op(300, yfx, [:]).

en las que se establece que los tres son operadores binarios asociativos por la izquierda y con proridades decrecientes. Mostramos el programa en la pgina 238. Para facilitar la a comprensin de los conceptos que se tratan de inculcar aqu o , hemos decidido no tener en cuenta ciertos aspectos considerados anteriormente, como son las concordancias de gnero y n mero e u y la construccin del arbol sintctico, puesto que su presencia o a aumenta el n mero de argumentos en los predicados y no son u indispensables en este ejemplo. Cada no terminal posee uno o ms argumentos, con el objeto a de proporcionar la interpretacin de la frase correspondiente. o Para facilitar la compresin, las variables X e Y se reeren o precisamente a las variables que posteriormente sern acotadas a por el y el , respectivamente. Las variables cuyo nombre comienza por P representan predicados parciales cuya composicin dar lugar al predicado nal contenido en la o a variable que se llama simplemente P. Para mostrar cmo se construye la interpretacin de una o o frase, comenzaremos por las partes ms simples. Por ejemplo, a el verbo ama tiene por interpretacin amar(X,Y), la cual o depende de X e Y, cuyos valores dependen a su vez de las restantes partes de la frase. Un caso un poco ms complejo tiene lugar a con la palabra todo, que tiene la interpretacin o forall(X) : (P1 => P2)

238

Anlisis del Lenguaje Natural a

conecta([P|S]\S,P). frase(P, S0\S) :- frase_nominal(X, P2, P, S0\S1), frase_verbal(X, P2, S1\S). frase_nominal(X, P2, P2, S0\S) :- nombre_propio(X,S0\S). frase_nominal(X, P2, P, S0\S) :determinante(X, P1, P2, P, S0\S1), nombre(X, P3, S1\S2), clausula_relativa(X, P3, P1, S2\S). clausula_relativa(X, P3, P3 & P4, S0\S) :conecta(S0\S1, que), frase_verbal(X, P4,S1\S). clausula_relativa(_,P3,P3,S0\S0). frase_verbal(X,P2,S0\S) :- verbo_intransitivo(X, P2, S0\S). frase_verbal(X,P2,S0\S) :- verbo_transitivo(X, Y, P5, S0\S1), prep_a(S1\S2), frase_nominal(Y, P5, P2, S2\S). prep_a(S0\S) :- conecta(S0\S, a). prep_a(S\S). determinante(X,P1, P2, forall(X) : (P1 => P2), S0\S) conecta(S0\S, determinante(X, P1, P2, exists(X) : (P1 & P2), S0\S) conecta(S0\S, :todo). :una).

nombre(X, hombre(X), S0\S) :- conecta(S0\S, hombre). nombre(X, mujer(X), S0\S) :- conecta(S0\S, mujer). nombre_propio(Miguel,S0\S) :- conecta(S0\S, Miguel). nombre_propio(Adriana,S0\S) :- conecta(S0\S, Adriana). verbo_transitivo(X,Y,amar(X,Y),S0\S) :- conecta(S0\S, ama). verbo_intransitivo(X,vive(X),S0\S) :- conecta(S0\S, vive).

15.2. Anlisis semntico a a

239

en el contexto de las propiedades P1 y P2 de un individuo X, en donde la propiedad P1 se corresponde con la frase nominal que contiene la palabra todo y la propiedad P2 vendr del resto de a la frase. Como ejemplo ilustrativo, analizamos la frase todo hombre vive mediante la pregunta: :- frase(P,[todo,hombre,vive]\[]). obteniendo como respuesta P forall( A):(hombre( A)=>vive( A)) Podemos observar cmo la presencia del determinante todo o produce la interpretacin o forall( A) : (P1 => P2), donde A representa el valor sin instanciar de la variable X, universalmente cuanticada por forall. A continuacin, el o sustantivo hombre provocar la identicacin de P1 con a o hombre( A), mientras que el verbo vive provocar a su vez a la identicacin de P2 con vive( A). o El orden en el que se realiza el anlisis sintctico es tal que a a algunas partes de la traduccin de la frase no estn disponibles o a cuando esa traduccin se construye. Es el caso de nuestro o ejemplo, en el cual la determinacin de la estructura o forall(X) : (P1 => P2) es establecida nada ms leer la primera palabra, momento en el a cual los valores para P1 y P2 son desconocidos. En general, en nuestro programa la estructura de la interpretacin P de o una frase es producida por el sujeto, pero depende a su vez de la interpretacin, todav no conocida, de la frase verbal que o a completa la sentencia a analizar. Tales elementos desconocidos se convierten en variables que se instancian posteriormente, como es el caso de P1 y P2 en este ejemplo.

240

Anlisis del Lenguaje Natural a

Para nalizar, consideremos un ejemplo algo ms complejo, a plantendole al programa el anlisis de la frase a a todo hombre que vive ama a una mujer La pregunta correspondiente es:
:- frase(P,[todo,hombre,que,vive,ama,a,una,mujer]\[]).

cuya respuesta se corresponde con lo que se pretend obtener: a


P forall( B):(hombre( B) & vive( B) => exists( A):(mujer( A) & amar( B, A)))

Mediante este sencillo programa no slo podemos interpretar o una cierta clase de frases, sino que podemos aprovechar la potencia de la programacin lgica para generar aquellas o o frases que son vlidas de acuerdo con el programa, as como a sus interpretaciones. Esto podemos conseguirlo realizando la pregunta :- frase(P,Q). cuya primera respuesta es la siguiente:
P vive(Miguel) Q [Miguel,vive| A]\ A

El programa nos dice que Miguel vive, menos mal. Veamos la siguiente respuesta:
P amar(Miguel,Miguel) Q [Miguel,ama,a,Miguel| A]\ A

Parece que este chico es un poco narcisista. Sigamos:


P amar(Miguel,Adriana) Q [Miguel,ama,a,Adriana| A]\ A

Parece que el programa, adems de inteligente, tambin es un a e poco cotilla. Continuemos:


P forall( A):(hombre( A) & vive( A) => amar(Miguel, A)) Q [Miguel,ama,a,todo,hombre,que,vive| B]\ B

15.2. Anlisis semntico a a

241

El tal Miguel es realmente un chico encantador. Prosigamos:


P forall( A):(hombre( A) & amar( A,Miguel) => amar(Miguel, A)) Q [Miguel,ama,a,todo,hombre,que,ama,a,Miguel| B]\ B

Amigo de sus amigos, como debe ser. Veamos que ms nos dice a el programa:
P forall( A):(hombre( A) & amar( A,Adriana) => amar(Miguel, A)) Q [Miguel,ama,a,todo,hombre,que,ama,a,Adriana| B]\ B

Una de dos, o Miguel no es celoso, o el programa ha cometido un peque o fallo esta vez. Dejemos este asunto aparte y pasemos a n la siguiente respuesta:
P forall( A):(hombre( A) & forall( B): (hombre( B) & vive( B) => amar( A, B)) => amar(Miguel, A)) Q [Miguel,ama,a,todo,hombre,que,ama,a,todo,hombre,que, vive| C]\ C

Entre pacistas, todos hermanos. Este peque o conjunto de n respuestas puede servirnos para ver la potencia del lenguaje. Evidentemente, el tipo de frase que puede ser analizada y generada es reducido, pero podemos ampliar el dominio de aplicacin del programa mediante la simple adicin de nuevas o o clusulas que sigan la misma estructura. Si adems a adimos a a n otros aspectos semnticos, como por ejemplo las concordancias a vistas anteriormente, podremos mejorar notablemente la exactitud del anlisis y de la interpretacin de las frases. a o

242

Anlisis del Lenguaje Natural a

Referencias
[1] Aho, A. V. and Ullman, J. D. The Theory of Parsing, Translation and Compiling. 1973. Prentice-Hall, Englewood Clis, vol. 1,2, New Jersey, U.S.A. [2] Bancilchon, F.; Maier, D.; Sagiv, Y.; and Ullman, J. D. Magic Sets: Algorithms and Examples. 1985. MCC Technical Report DB-168-85. [3] Beeri, C.; and Ramakristan, R. On the Power of Magic. 1987. Proc. of the 6th ACM SIGACT-SIGMOD-SIGART Syposium on Principles of Database Systems (pp. 269-283), San Diego, California, USA. [4] Bird, R. S. Tabulation Techniques for Recursive Programs. 1980. Computing Survey, vol. 12, no 4 (pp.403-417). [5] Colmerauer, A. Metamorphosis Grammars. 1978. Natural Language Communication with Computers, L. Bolc ed., Springer LNCS 63. [6] Dietrich, S. W. Extension Tables: Memo Relations in Logic Programming. 1987. Proc. of the 4th Symposium on Logic Programming (pp. 264-272), San Francisco, California, USA.
243

244

Referencias

[7] Giannesini, F. and Cohen, J. Parser Generation and Grammar Manipulations Using Prologs Innite Trees. 1984. Journal of Logic Programming vol.1, no 3 (pp. 253265). [8] Hill, R. LUSH-Resolution and its Completeness 1974. DCL Memo 78, Departament of Articial Intelligence, University of Edimburgh. [9] Jacobs, I. The Centaur 1.2 Manual. 1992. INRIA Sophia-Antipolis, France. [10] Kay, M. Unication in Grammar. 1984. Proc. of the First International Workshop on Natural Language Understanding and Logic Programming, Rennes, France (pp. 233-240). [11] Kim, W.; Reiner, D. S. and Batory, D. S. Query Processing in Database Systems 1985. Springer-Verlag, New York, U.S.A. [12] Kowalski, R. A. Logic for Problem Solving. 1980. North-Holland Publishing Company, New York, U.S.A. [13] Kowalski, R. A. and Van Emden, M. H. The Semantics of Predicate Logic as a Programming Language. 1976. Journal of the ACM, vol. 23, no 4 (pp. 133-742). [14] Lang, B. Datalog Automata. 1988. Proc. of the 3rd International Conference on Data and Knowledge Bases, C. Beeri, J. W. Schmidt, U. Dayal (eds), Morgan Kaufmann Pub., Jerusalem, Israel (pp. 389-404).

Referencias

245

[15] Lang, B. Complete Evaluation of Horn Clauses, an Automata Theoretic Approach. 1988. Research Report no 913, INRIA Rocquencourt, France. [16] Lang, B. Towards a Uniform Formal Framework for Parsing. 1991. Current Issues in Parsing Technology, M. Tomita ed., Kluwer Academic Publishers (pp. 153-171). [17] Lloyd, J. W. Foundations of Logic Programming. 1987. Springer-Verlag, 2nd edition. [18] Maier, D. and Warren, D. S. Computing with Logic 1988. The Benjamin/Cummings Publishing Company Inc., Menlo Park, California, U.S.A. [19] Naish, L. MU-Prolog 3.2. Reference Manual 1990. Technical Report 85/11. Dept. of Computer Sciences, University of Melbourne, Parkville, Victoria 3052, Australia. [20] Pereira, F. C. N. and Warren, D. H. D. Denite Clause Grammars for Language Analysis. A Survey of the Formalism and a Comparison with Augmented Transition Networks. 1980. Articial Intelligence, vol.13 (pp. 231-278). [21] Pereira, F. C. N. and Warren, D. H. D. Parsing as Deduction. 1983. Proc. of the 21st Annual Metting of the Association for Computational Linguistics, Cambridge, Massachusetts, U.S.A (pp. 137-144).

246

Referencias

[22] Robinson, J. A. A Machine-Oriented Logic Based on the Resolution Principle 1965. Journal of the ACM, vol. 12. [23] Tamaki, H. and Sato, T. OLD Resolution with Tabulation. 1986. Proc. of the 3rd International Conference on Logic Programming, London, United Kingdom, Springer LNCS 225 (pp. 84-98). [24] Van Emdem, M. H., and Lloyd, J. W. A Logical Reconstruction of Prolog II 1990. The Journal of Logic Programming, vol. 1, no 2. [25] Vieille, L. Database-Complete Proof Procedures Based on SLD Resolution. 1987. Proc. of the 4th International Conference on Logic Programming, Melbourne, Australy. [26] Villemonte de la Clergerie, E. Automates a Piles et Programmation Dynamique. ` 1993. Doctoral Thesis, University of Paris VII, France. [27] Vilares Ferro, M. Ecient Incremental Parsing for Context-Free Languages. 1992. Doctoral thesis, University of Nice, France.

Indice
=, 26 , 26 , 49 , 48 , 26 regla, 7, 216 , 26 , 26 N , 50 ,, 83 ., 83 :, 4850, 237 :-, 83 ;, 95 &, 237 arbol de derivacin, 13, 15, o 199 de resolucin, 67, 91 o Prolog, 92 sintctico, 14 a atomo, 83 asserta, 186 assert, 186 atomic, 195 atom, 195 float, 195 integer, 195
247

is, 184 nonvar, 195 number, 195 retract, 186 var, 195 cand, 46 cor, 46 fail, 121, 127 freeze, 139 not, 130 op, 174 acumulador, 165 ambig edad u lxica, 223 e semntica, 223 a sintctica, 8, 213, 223 a anlisis a ascendente, 12, 20 descendente, 15, 16, 20, 94 lxico, 11, 227 e predictivo, 15 sintctico, 3, 20, 207, a 229 analizador ascendente, 17, 18 descendente, 12, 15, 18

248

INDICE

lxico, 11 e sintctico, 11, 12 a de los pal ndromos, 209 de los parntesis, 212 e del espa ol, 223 n aplanamiento de listas, 157, 167, 175 argumento de un funtor, 81 aridad de un funtor, 81 axioma, 41 clula, 147 e clculo a de predicados, 44, 50, 54, 61 de proposiciones, 25, 35, 38 cabeza de una clusula, 66, a 83 cadena vac 5 a, car, 148 categor a lxica, 4 e sintctica, 4 a cdr, 148 clusula, 64, 83 a de Horn, 83 comentario, 195 completud, 100 concatenacin de listas, 155 o conicto desplazamiento/reduccin, o 19 reduccin/reduccin, 19 o o

congruencia declarativo/operacional, 100 conjuncin, 26 o condicional, 46 constante lgica, 82 o contraejemplo, 67 control de la resolucin, 111 o correccin, 100 o corte, 111 rojo, 123 verde, 123 cuanticador existencial, 49 numrico, 50 e universal, 48 cuerpo de una clusula, 83 a declaracin no lgica, 174 o o derivacin, 5 o cannica, 8 o directa, 5 indirecta, 5 por la derecha, 8, 12 por la izquierda, 8, 12 desplazamiento, 19 diferencia de estructuras, 178 de listas, 172 de sumas, 179 disyuncin, 26 o condicional, 46 doblete, 147 duplicacin de listas, 159 o entrada, 185

INDICE

249

equivalencia de cuanticadores, 51 lgica, 35 o estado, 29, 44 estructura de datos incompleta, 172, 178 evaluacin o de predicados, 45 de proposiciones, 27 perezosa, 139 evaluacin o aritmtica, 184 e exploracin en profundidad, o 15, 94, 213 exponenciacin de n meros o u naturales, 117 expresin o aritmtica, 184 e atmica, 44 o normalizada por la derecha, 181 por la izquierda, 179 factorial de un n mero, 168 u rma de un funtor, 82, 209 forma normal de Chomsky, 216 de Greibach, 13, 215, 219 sentencial, 6 frontera de un arbol, 14, 15 funcin, 82 o de Fibonacci, 187 funtor principal, 81 gramtica, 3 a

ambigua, 8, 13 aritmtica, 4 e aumentada, 11, 215 de contexto libre, 6, 224 de las proposiciones, 27, 32 de los pal ndromos, 208 de los parntesis, 212, e 219 no ambigua, 9 reducida, 10 del espa ol, 224 n sensible al contexto, 209, 223, 229 hecho, 65 identicador acotado, 54 libre, 54 ligado, 54 igualdad, 26 implicacin, 26 o inclusin de conjuntos, 162 o inconsistencia, 70 lgica, 66 o inferior, 128 o igual, 127 instanciacin, 85 o intrprete e lgico, 92 o Prolog, 89, 92 interseccin de conjuntos, o 162 inversin de listas, 156 o lgica o

250

INDICE

de predicados de primer orden, 43 de proposiciones, 26, 43 lema de una palabra, 231, 233 lenguaje ambiguo, 8 de contexto libre, 207 generado por una gramtica, 7 a natural, 207 lexema de una palabra, 231 ley de la contradiccin, 36, o 47 de la identidad, 37 de la igualdad, 37 de la implicacin, 37 o de la negacin, 36 o del medio excluido, 36, 47 leyes asociativas, 36, 47 conmutativas, 36 de De Morgan, 36, 47 de equivalencia, 36 de la simplicacin del o , 37 de la simplicacin del o , 37 de la simplicacin del o cand, 48 de la simplicacin del o cor, 48 distributivas, 36, 47 LIFO, 87

lista, 147 vac 148 a, literal, 83 longitud de una lista, 159 mtodo e de resolucin SLD, 89 o de unicacin o de Robinson, 87 mgu, 86 multiplicacin de n meros o u naturales, 113 n mero u natural, 84, 93 impar, 98 par, 97 negacin, 26, 83, 121, 127, o 130 por fallo, 130, 135 nombre de un funtor, 81 objetivo, 67, 91 operador, 20, 21, 174, 197, 198 binario, 199 lgico, 26, 31, 46 o Prolog, 197 unario, 200 pal ndromo, 208 paradigma declarativo, 104 pertenencia a una lista, 151 predicado, 25, 45, 83 aritmtico, 183 e de memorizacin, 186 o metalgico, 194 o

INDICE

251

no lgico, 109, 171 o pregunta, 64, 83 problema de la analog 202 a, proceso de resolucin, 65 o produccin, 4 o producto cartesiano de conjuntos, 164, 167, 175 programa lgico, 64, 84 o proposicin o bien denida, 29 proposicin o constante, 28 rango de un cuanticador, 49 reconocedor sintctico, 11 a recursividad, 165 izquierda, 13, 22, 213 215 directa, 13, 217 reduccin, 17 o al absurdo, 65 regla, 4 de resolucin, 61 o de resolucin, 38 o de sustitucin, 38 o de transitividad, 38 de transmisin simple, 7, o 216 resolvente, 67, 90 respuesta, 67 resto, 118 retroceso, 95 s mbolo

de una gramtica, 5 a in til, 10, 216 u inaccesible, 9 inicial, 4, 6, 7 no terminal, 3 terminal, 4 variable, 4 salida, 185 semntica a declarativa, 83, 85 operacional, 83, 85 sentencia, 6, 208, 216, 224 signicado, 100 declarativo, 64 deseado, 100 SLD, 89 suma de n meros naturales, u 98 sustitucin, 85 o simultnea, 59 a textual, 56 trmino, 81 e compuesto, 81 simple, 81 tabla de verdad, 27 tautolog 34 a, teorema, 41 test de ciclicidad, 88 metalgico, 195 o tipo, 44 conjunto, 160 registro, 82 torres de Hanoi, 190

252

INDICE

transformacin o de implicaciones, 40 unin de conjuntos, 161 o unicacin, 62, 82, 86 o unicador, 86 ms general, 86 a valor indenido, 46 variable, 81 annima, 124 o

También podría gustarte