Swi Prolog
Swi Prolog
Swi Prolog
Indice
1. Introducci on 2. Comandos b asicos 3. Sintaxis de Prolog 4. Ayuda 5. Consultando y modicando programas 5.1. Consultar programas . . . . . . . . . . 5.2. Errores y avisos . . . . . . . . . . . . . 5.3. Mostrar base de clausulas . . . . . . . 5.4. Modicando la base de clausulas . . . 2 2 2 4 5 5 6 6 6 6 6 7 8 8 9 10 10 12 12 12 13
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
6. Depurador 6.1. Depurador en modo texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2. Depurador gr aco . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7. Manejo de t erminos 7.1. Jerarqu a . . . . . . . . . . . . 7.1.1. Atomos . . . . . . . . . 7.1.2. N umeros . . . . . . . . . 7.2. Escritura y lectura de t erminos 8. Listas 9. Conjuntos 10.Manejo de archivos 11.Todas las soluciones a un objetivo
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
1.
Introducci on
Este peque no manual pretende ser una introducci on al uso de SWI-Prolog poni endolo en relaci on con los conceptos de la asignatura de Programaci on L ogica de las Ingenier as T ecnicas de Gesti on y de Sistema. La versi on sobre la que versa este manual es la u ltima que se puede encontrar, a d a de hoy, en la p agina www.swi-prolog.com, que es la 5.6.6 para Windows NT/2000/XP.
2.
Comandos b asicos
Una vez instalado SWI-Prolog y procediendo a su ejecuci on observamos el shell visto como un n umero m as los caracteres ?-. Desde ah es de donde vamos a ajecutar todos los objetivos. Los siguientes apartados explican de forma muy general todo aquello que es fundamental conocer a la hora de usar este int erprete. 1. Consultar un programa Prolog: la manera m as f acil de consultar un programa Prolog es usando el men u le/consult y navegando por los directorios. Tambi en existe la posibilidad de hacerlo desde el shell escribiendo el nombre del programa, sin la extensi on .pl, encerrada por corchetes [ ] y seguida de punto. Ej: [mi_prog]. 2. Ayuda: SWI-Prolog posee una ayuda gr aca f acil de usar. Basta con poner en el shell help.. Si se quiere consultar un tema o un predicado en concreto basta con escribir el tema de la siguiente forma: help(Tema). 3. Ejecuci on de objetivos: para ejecutar un objetivo simplemente lo escribimos en el shell (seguido de punto). Si el objetivo no tiene exito SWI-Prolog responder a no. Si ha tenido exito y el objetivo ten a variables entonces devolver a la unicaci on de esas variables que ha producido el exito y el programa esperar a una acci on del usuario. Ahora debemos escribir un u nico car acter. Si buscamos m as respuestas escribiremos ; (punto y coma), si no pulsamos enter. Para una lista de comandos escribimos h. 4. Depuraci on: Para entrar en el modo trace hay que escribir trace.. Al lado del shell deber a aparecer la palabra [trace]. Para salir de este modo hay que escribir notrace. y nodebug.. Existe la posibilidad de utilizar un depurador gr aco escribiendo guitracer.
3.
Sintaxis de Prolog
Cualquier programa en Prolog tiene que estar escrito en un chero de texto plano (sin formato). La manera m as sencilla es usar el Bloc de Notas. Dicho archivo debe poseer la extensin .pl para indicar que contiene c odigo fuente de Prolog. Un programa Prolog est a formado con un conjunto de hechos y de reglas junto con un objetivo. El archivo del c odigo fuente de Prolog contendr a el conjunto de hechos y de reglas y el objetivo ser a lanzado desde el shell de SWI-Prolog. Existen ciertas consideraciones sobre la sintaxis de Prolog: 1. Variables: El identicador de una variable tendr a que tener su primera letra en may usculas. Ej: X, Atapuerca, Cobaltina, RADgtfCdf 2
2. Constantes: La primera letra de una constante deber a estar escrita en min usculas. Ej: a, incienso, roberto, rADgtfCdf Tambi en se consideran constantes a los n umeros, Ej: 1, 5.02, 0.7 las palabras entre comillas simples Ej: a, A, a a y la lista vac a [ ]. 3. Funciones: Al igual que las constantes, su primera letra debe ser una min uscula. Deber a estar seguido de un conjunto de t erminos (otras funciones, variables o constantes) encerrados entre par entesis. Ej: f(c,X), conc arbol(Hijo Izq, Raiz, Hijo Der), rADgtfCdf(RADgtfCdf, rADgtfCdf) 4. Predicados: Su sintaxis es la misma que la de las funciones aunque, por su localizaci on dentro de la cl ausula (es decir, dentro del programa Prolog), el compilador los identicar a como tal, y no como funciones. Ej: f(c,X), conc arbol(Hijo Izq, Raiz, Hijo Der), rADgtfCdf(RADgtfCdf, rADgtfCdf) Tambi en existe la posibilidad de tener predicados 0-arios. 5. Hechos: Son cl ausulas de Horn que poseen un u nico predicado en la cabeza y ninguno en el cuerpo. Tienen la siguiente forma en sintaxis de l ogica de primer orden: P En Prolog no se escribe la echa sino que se pone un punto al nal: p. donde p es un predicado y tiene que seguir su sintaxis. Ej: padre(aaron, maria). compositor(shostakovich). shostakovich(compositor). 6. Reglas: Son cl ausulas de Horn que poseen un u nico predicado en la cabeza y uno o m as en el cuerpo. Tienen la siguiente pinta: P Q1, Q2, Q3 escritos en sintaxis clausular o P Q1 Q2 Q3 escritos en sintaxis de l ogica de primer orden. En Prolog la echa se sustituye por :-, las conectivas conjuntivas se escriben como comas , y la regla termina en punto: p :- q1, q2, q3. donde, al igual que los hechos, p y q 1, q 2 y q 3 son predicados. Ej: cuadrado(X) :- poligono(X), numero_lados(X,4). 7. Objetivos: Son cl ausulas de Horn que no poseen ning un predicado en su cabeza: Q1, Q2, Q3 Los predicados se escriben separados por comas y terminados en punto. S olo pueden sen lanzados desde el shell de SWI-Prolog. 3
4.
Ayuda
En la ayuda de SWI-Prolog, la denici on de los predicados tiene su propia sintaxis. El nombre y la aridad determinan un vocamente a un predicado. Esto en Prolog se escribe pred/arid donde pred es el nombre del predicado y arid su aridad. Despu es del nombre del predicado se escribe un n umero de variables, dependiendo de la aridad, con un s mbolo delante de la variable: + : signica que esa variable debe estar instanciada, es decir, que no puede ser una variable sin estar unicada con nada, en el momento es que se llega a ese predicado. Desde el punto de vista del programador se puede ver como un par ametro de entrada. A pesar de que en l ogica de primer orden ello no tendr a mucho sentido, en SWI-Prolog se dan cosas as debido a que, por ejemplo, dicho predicado puede estar relacionado con una llamada a C (como sort/2 ) o con operaciones aritm eticas (como is/2 ). Ej: ?- sort(X,[1,2,3,4]). ERROR: sort/2: Arguments are not sufficiently instantiated - : identico a + pero esta vez como predicado de salida. Pongamos lo que le pongamos va a intentar unicar con ello. Ej: ?- sotr([5,4,3,2,1], L). L = [1, 2, 3, 4, 5] ?- sort([5,4,3,2,1], [C|R] ). C = 1 R = [2, 3, 4, 5] ?- sort([5,4,3,2,1], [2,1,3,5,4] ). No ?: se considera de entrada o de salida. Esto sigue el procedimiento normal de resoluci on de la programaci on l ogica. Para ver la ayuda sobre el predicado pred escribimos help(pred). Si adem as nos referimos a un predicado concreto tambi en tenemos que escribir su aridad: help(pred/2). Podemos indicar una secci on del manual: la seccion 2.4 se escribira como 2-4: help(2-4). Si no tenemos informaci on tan concreta podemos usar el predicado apropos/1. A este predicado se le pasa el nombre aproximado de lo que buscamos. Nos devolvera predicados, funciones o secciones del manual que contengan ese nombre. S le importa las may usculas o min usculas (cuidado si la primera es mayusculas porque, l ogicamente, pensar a que el argumento es una variable). Tambi en podemos proporcionarle frases escritas entre comillas simples. Ej: apropos(file). apropos(file). apropos(File). apropos(the file). 4
Los predicados explain/1 y explain/2 dan cierta informaci on sobre el argumento, como su funci on o referencias aunque es demasiado escueto. Esta informaci on est a recogida en la secci on 2.6 del manual.
5.
5.1.
Cargar y compilar un programa en Prolog se conoce como consultar. Existe varias formas. La m as f acil consiste en usar el men u FileConsult, aunque esta opci on s olo est a disponible en el entorno Windows. Tambi en podemos usar el predicado consult/1. consult/1 puede ser invocado de varias formas. La m as f acil consiste en llamar a consult/1 con el nombre del programa sin la extensi on. Es indiferente el uso de may usculas o min usculas excepto para la primera letra, que debe ser min uscula para que Prolog no piense que es una variable. Ej: consult(practica3_chunga). En este caso buscar a en el directorio actual y en una serie de directorios que tiene para buscar. Otra forma consiste en escribir la ruta del archivo completa entrecomillada con comillas simples. La barra que separa los directorios en Windows debe estar inclinada hacia la derecha (y no como en Windows que est a escrita hacia la izquierda). Ej: consult(c:/hlocal/practica3_suspensa). consult(c:/hlocal/practica3_suspensa.pl). Otra alternativa a este predicado es el uso de los corchetes. Su funcionamiento es identico al de consult/1 pero poniendo el nombre del archivo entre corchetes. Ej: consult(practica3_chunga). [practica3_chunga]. [practica3_chunga]. [practica3_chunga.pl]. [c:/hlocal/practica3_chunga.pl]. Para consultar en qu e directorio estamos usamos el predicado pwd/0. Para cambiar la ruta usamos el predicado cd/1. Se usa escribiendo entre comillas simples la ruta absoluta o relatica. Ej: 1 ?- pwd. c:/hlocal yes 2 ?- cd(..). yes 3 ?- pwd. c: yes Existe m as informaci on detallada en la secci on 4.3 del manual y, una m as u til en la 4.3.2. 5
5.2.
Errores y avisos
Cuando se consulta un archivo pueden aparecer mensajes de error o de aviso. Los m as comunes son: 1. Error sint actico: el int erprete mostrar a el error que se ha producido, donde ha sido y por qu e se ha parado. Ya que la sintaxis de Prolog es sencilla suele acertar la mayor a de las veces. 2. Error de archivo no encontrado: hay que jarse en el nombre del archivo, la ruta que se ha puesto expl citamente y los directorios por defecto en donde busca, como puede ser el directorio de trabajo. 3. Aviso de variable singleton : una variable singleton es una variable que solamente aparece una vez en una cl ausula. El compilador interpreta que puede haber un error al escribir esa variable pero, por no tratarse de un error, da un aviso. Si la cl ausula est a bien hecha y posee una variable singleton signica que el valor de esa variable no importa en dicha cl ausula ya que va a unicar con cualquier cosa y no tiene relevancia posterior. Para que el programa sea m as claro y no salga el aviso podemos usar, en su lugar, una variable an onima. Las variables an onimas se escriben como un subrayado , unican con cualquier cosa pero no entre ellas. Ej: % multiplica(in, in, out) multiplica(0, _, 0). 4. Aviso de que las cl ausulas de un mismo predicado no est an juntas: este aviso salta cuando se escriben cl ausulas de un predicado entre cl ausulas de otro.
5.3.
Para ver el contenido de la base de cl ausulas usamos el predicado listing/0. Este predicado muestra todas las cl ausulas que tenemos actualmente. Para ver s olo aquellas cl ausulas que pertenecen a un predicado usamos listing(+Pred) donde Pred es el predicado que buscamos mirar. Tambi en podemos escribir listing(+Pred/Arid) donde Arid es la aridad del predicado Pred.
5.4.
Podemos a nadir y eliminar cl ausulas usando la familia de predicados assert y retract. Con asserta/1 insertamos la cl ausula al principio de la lista de cl ausulas de ese predicado. Con assert/1 y assertz/1 hacemos lo mismo pero al nal. Con retract/1 y retractall/1 las eliminamos.
6.
6.1.
Depurador
Depurador en modo texto
El modo depurador comienza cuando escribimos el predicado debug/0. Deber aparecer [debug] antes de la interrogaci on en el shell de Prolog. Para salir de ese modo basta con usar nodebug/0. Para conocer el estado del depurador usamos debugging/0. Podemos establecer puntos de paradas para el depurador, que en Prolog se conocen como puntos esp as. Dichos puntos son establecidos con el predicado spy/1. Con spy(+Pred) establecemos un punto de espionaje en las cl ausulas cuya cabeza sea Pred. Ej: dios_hindu(ganesha). dios_hindu(krishna). dios_hindu(shiva). ?- spy(dios_hindu). 6
Para eliminar un punto esp a usamos nospy/1 o para eliminar todos usamos nospyall/0. Una vez que se ha alcanzado un predicado que lleva asociado un esp a la ejecucin del programa se para en los llamados puertos (ports). Existen 6 y son: Call: pasamos por el cuando se llama a la cl ausula. Unify: cuando se ha unicado la cabeza de la cl ausula con el objetivo actual. Exit: cuando salimos del objetivo. Redo: cuando, por recursi on, probamos otra cl ausula de un mismo predicado. Fail: cuando esa cl ausula falla. Exception: cuando el predicado throw/1 lanza esa excepci on. En el shell de SWI-Prolog veremos el nombre del puerto seguido del objetivo con la unicaci on que lleve hasta ese momento m as una interrogaci on. Eso indica que se espera un gesto del usuario y ser a la escritura de un u nico car acter sin necesidad de seguirlo por enter. Pulsando h obtendremos la lista de comandos. Los m as u tiles son: Enter (o espacio o c): continua hasta el siguiente puerto. h: muestra las opciones disponibles. a: aborta la ejecuci on. L: muestra la cl ausula. +: establece un punto de espionaje. -: elimina un punto de espionaje. El predicado trace/0 hace lo mismo que el predicado debug pero sin necesidad de establecer un punto esp a para pararse en un puerto, sino que lo realiza desde el principio de la ejecuci on. Cuando llamamos a trace/0 aparece [trace] a la izquierda de ?- indicando que hemos pasado a ese modo. Para salir de el simplemente llamamos a notrace/0. Existe muchas secciones del manual que hablan sobre el depurador. Yo recomiendo las secci ones 2.9 y 4.38 por proporcionar una visi on general.
6.2.
Depurador gr aco
Existe tambi en un depurador gr aco. Para que funcione se debe escribir guitracer. y cuando queramos dejar de usarlo escribimos noguitracer.. Funciona de la misma manera que el depurador en modo texto excepto que, cuando la ejecuci on se para en alg un punto, aparece una ventana. La ventana que aparece es esta:
(1) Estos botones nos sirven para avanzar en la ejecuci on del programa. En concreto la echa recta hacia la derecha se usa para avanzar paso a paso. (2) Esta parte muestra las unicaciones que llevamos en este momento en esta cl ausula. En este ejemplo, hemos unicado X con a e Y con b. Todav a falta la Z de c(Z ) porque es el predicado que se va a llamar ahora. (3) Aqu se muestra la pila de objetivos que sirve para la recursi on. En este ejemplo se ve que estamos ejecutando el predicado d/3 y que ahora vamos a llamar a c/1. Tambi en vemos que queda pendiente hechos del predicado b/1, en concreto b(bb). y b(bbb). (4) En esta ventana aparece el programa Prolog. Se indica que cl ausula se esta ejecutando ahora y en color verde a qu e objetivo se va a llamar. En color rojo aparecen las clausulas que fallan.
7.
7.1.
Manejo de t erminos
Jerarqu a
Para facilitar la tarea de la programaci on en SWI-Prolog existe una peque na jerarqu a de t erminos
Debajo de cada categoria de t ermino se ha escrito el predicado metal ogico que lo dene. Ej: ?- var(X). X = _G230 Yes ?- X=a, var(X). No Todos los predicados pueden ser encontrados en la secci on 4.5 del manual. 7.1.1. Atomos
Los t erminos atomos son aquellos que se corresponden con las constantes del vocabulario en l ogica de primer orden. Se comprueban que est an bien denidos mediando el predicado atom/1. Existen dos formas de denir constantes. La primera es escribiendo el nombre de la constante con la primera letra en min usculas. Ej: ?- atom(a). Yes ?- atom(fEdErIcO). Yes La segunda forma es m as exible. Si buscamos que nuestra constante contenga espacios, caracteres raros o la primera letra en may usculas lo escribimos entre comillas simples. Ej: ?- atom(a).
Yes ?- atom(a a). Yes ?- atom(A). Yes ?- atom(2). Yes 7.1.2. N umeros
Es dif cil la denici on de predicados para n umeros en el que sus argumentos sean de entrada y de salida, tal y como se hace en los predicados en programaci on l ogica. Por eso los argumentos de los predicados aritm eticos s olo poseen una direcci on en SWI-Prolog. El m as importante de ellos es el predicado is/2 que se usa de forma inja. En su argumento izquierdo usamos una variable libre (u otro valor con el que queremos que unique) y en el argumento derecho una expresi on aritm etica. Ej: ?- N is 2 + 2. N = 4 ?- N is 5 / 7. N = 0.714286 ?- 4 is 2 + 1. No ?- N is X + 2. ERROR: is/2: Arguments are not sufficiently instantiated Otros predicados de este tipo son las relaciones <, >, =<, >=, =\= y =:= que se usan tambi en en forma inja. Si se busca m as informaci on sobre c omo maneja SWI-Prolog los n umeros hay que consultar la secci on 4.26 del manual.
7.2.
Prolog posee predicados para leer o escribir t erminos por pantalla o desde un archivo. El predicado as sencillos son write/1, m as general para la escritura de terminos es write term/2. Otros predicados m writeln/1 o writeq/1. Ej:
10
?- write(f(a)). f(a) Yes ?- write(a a). a a Yes ?- write(f(a,X)). f(a, _G279) X = _G279 Yes Tambi en ayudan a formatear la salida predicados como nl/0 (que escribe un salto de l nea) y tab/1 (que escribe una cantidad de espacios). Existen versiones de estos predicados con un argumento m as a nadido que corresponde con el stream de un archivo. Su funci on es la misma pero lo hacen en el archivo de texto asociado con el stream. Para la lectura de t erminos existen predicados an alogos: read term/2 y read/1 junto con predicados que llevan como argumento un ujo de un chero. Hay algo importante que decir sobre la lectura de t erminos. Para que Prolog sepa cual es el nal de un t ermino se debe acabar con un punto. Hay que tener cuidado con la escritura de un t ermino en un archivo si queremos volverlo a leer inmediatamente. Hay que escribir el punto expl citamente (write(.) ) porque write/1 no lo hacer. Ej: ?- read(T). | f(a). T = f(a) Yes ?- read(f(T)). | f(a). T = a Yes ?- read(g(T)). | f(a). No M as predicados pueden ser encontrados en la secci on 4.19.
11
8.
Listas
Existe un m odulo que se carga por defecto para el manejo de listas y es el que vamos a tratar ahora. Para manejar listas SWI-Prolog proporciona los dos t erminos constructores de la lista: [ ], la constante lista vaca; y [X |R] el operador (funci on inja) concatenar por la cabeza, donde R debe ser una lista a en se proporciona su vez. Para una denici on m as formal de lista consultar el predicado is list/1. Tambi predicados para el manejo de listas. La lista completa est a en la secci on 4.28 y en el ap endice A.1 (11.1 si usamos el comando help en vez del .pdf) del manual. Nosotros vamos a ver algunos por encima: is list(+Term) : cierto si Term es una lista. length(?List, ?Int) : Int es el n umero de elementos de la lista List. sort(+List, -Sorted) : Sorted es la lista ordenada de los elementos de List sin duplicados. append(?List1, ?List2, ?List3) : List3 es la concatenaci on de List1 y List2 member(?Elem, ?List) : Elem es elemento de List. nextto(?X, ?Y, ?List) : Y est a despu es de X en la lista List. delete(+List1, ?Elem, ?List2) : List2 es la eliminaci on de todos los elementos que unican simult aneamente con Elem de List1. nth0(?Index, ?List, ?Elem) : Elem es el Index - esimo elemento de List, comenzando por el 0. reverse(+List1, -List2) : List2 es List1 pero con el orden de los elementos cambiado.
9.
Conjuntos
SWI-Prolog tambi en posee un m odulo para el manejo de conjuntos. Un conjunto est a implementado como una lista sin repeticiones aunque no es necesario conocer dicha implementaci on ya que podemos usarlo como un Tipo Abstracto de Datos con el predicado list to set/2. Podemos consultar los predicados relativos a conjuntos en el ap endice A.1.1 (u 11.1.1): is set(+Set) : Set es un conjunto list to set(+List, -Set) : Set es el conjunto de elementos de List pero sin duplicados. intersection(+Set1, +Set2, -Set3) : Set3 es la intersecci on de Set1 con Set2. subtract(+Set, +Delete, -Result) : elimina de Set todos los elementos del conjunto Delete. union(+Set1, +Set2, -Set3) : Set3 es la uni on de Set1 y Set2. subset(+Subset, +Set) : todos los elementos de Sebset est an en Set.
10.
Manejo de archivos
Para abrir un chero tenemos el predicado open/3 (tambi en existe open/4 que es igual que open/3 pero con una lista de opciones adicionales). El uso de open/3 es muy parecido al de C ya que se adapta a un est andar de ISO. A open/3 se le pasa el nombre y/o la ruta del archivo escrito entre comillas simples y el modo de escritura. Devuelve en una variable el ujo (stream ) donde podremos escribir. El modo debe ser una de estas constantes: read, write, append y update. append abre el chero para escritura y se posiciona al nal y update hace lo mismo pero se posiciona al principio (sin borrar nada a priori), por lo que cada vez que se escriba sustituir a algo de texto Ej: 12
open(declaracion_amor.txt, write, S). open(c:/novias_secretas/declaracion_amor.txt, write, S). open(declaracion_amor, read, S). Para cerrar el ujo asociado con el chero usamos close/1. Para leer y escribir tenemos la familia de los predicados read/2 y write/2, como se ha visto anteriormente. El primer argumento ser a el ujo y el segundo el t ermino (aunque mandemos texto al archivo, este debe estar escrito como un t ermino). M as informaci on en la secci on 4.16 aunque nos hemos centrado en la 4.16.1.
11.
Existen predicados que no se paran cada vez que llegan a una hoja exito en el arbol de vuelta atr as sino que realizan todo el arbol que est a por debajo de un objetivo dado y guardan las soluciones (unicaciones) en una lista. ndall(+Template, +Goal, -Bag): realiza todo el arbol de backtracking del objetivo Goal. Cada vez que llega a un exito unica las variables con la plantilla Template e introduce el resultado en la lista Bag. 5 ?- listing. dios_egipcio(amon). dios_egipcio(anubis). dios_egipcio(apis). dios_egipcio(ra). Yes 6 ?- findall(X,dios_egipcio(X), L). X = _G362 L = [amon, anubis, apis, ra] yes bagof(+Template, +Goal, -Bag): id entico a ndall/3 excepto que si el objetivo posee variables libres entonces primero probar a la unicaci on con esas variables libres y despu es realizar a el arbol de vuelta atras para cada una de esas unicaciones, parando cada vez. ?- listing. vida(carlos_III, 1716, 1788). vida(carlos_IV, 1748, 1819). vida(fernando_VII, 1784, 1833). yes ?- bagof([A,B], vida(A, B, C),L). A = _G371 B = _G374 13
C = 1788 L = [[carlos_III, 1716]] ; A B C L A B C L No Si no queremos que se pare cada vez que encuentre una unicaci on debemos usar el s mbolo como en el ejemplo: ?- bagof([A,B], C^vida(A, B, C),L). A B C L No setof(+Template, +Goal, -Set): igual que bagof/3 pero la lista Bag es devuelta ordenada y sin duplicados. En las secciones 4.31 y 4.29 existe explicaciones de estos predicados. = = = = _G383 _G386 _G391 [[carlos_III, 1716], [carlos_IV, 1748], [fernando_VII, 1784]] ; = = = = = = = = _G371 _G374 1819 [[carlos_IV, 1748]] ; _G371 _G374 1833 [[fernando_VII, 1784]] ;
14