<div class="notebook open-fullscreen"> <div class="nb-cell html" name="htm2"> <h2 align="center"> Universidad Nacional de Colombia </h2> <h2 align="center"> Lenguajes de programacion 2021 - II </h2> <h2 align="center"> Tutorial Prolog </h2> <p align="center"> <img src="https://avatars2.githubusercontent.com/u/6884283?v=3&s=200"> </p> <h4> Realizado por: <br> María Fernanda Carbonell Santos <br> Juan David González <br> Ivan Alejandro Cruz Tole <br> Yuli Beltran Rozo </h4> <hr> </div> <div class="nb-cell html" name="htm1"> <h3> Contenido </h3> <ol> <li>Sintaxis <ul> <li>Terminos</li> <li>Programas</li> </ul> </li> <li>Hechos <ul> <li>Propiedades</li> <li>Relaciones</li> </ul> </li> <li>Reglas</li> <li>Consultas</li> <li>Backtracking</li> <li>Expresiones</li> <li>Predicados predefinidos</li> <li>Listas</li> <li>Arboles</li> <li>Ejemplos</li> </ol> </div> <div class="nb-cell markdown" name="md1"> # 1. Sintaxis ## 1.1 Terminos Los términos son el único elemento del lenguaje, todos los datos están representados por términos; un término se compone de un functor seguido de cero a N argumentos entre paréntesis y separados por comas. Corresponden a un valor en PROLOG y pueden ser: ### Constantes *Numeros:* Representan enteros y reales que pueden ser operados aritméticamente entre si, pueden ser escritos en notación decimal o exponencial </div> <div class="nb-cell program" name="p1"> isnumber(-0.324). isnumber(3e-3). </div> <div class="nb-cell markdown" name="md2"> *Átomos o functores:* Nombres de propósito general, utilizados para nombrar objetos, propiedades o relaciones. Siempre comienzan en minuscula, si el átomo tiene espacios o cierto tipo de caracteres especiales, el átomo se debe poner entre comillas sencillas. </div> <div class="nb-cell program" name="p2"> isatom(atomo). isatom('valor atomico'). </div> <div class="nb-cell markdown" name="md3"> ### Variables Se indican mediante una cadena de caracteres que puede constar de letras, números y guión bajo. Deben comenzar con una letra mayúscula o con guión bajo. Existe una variable especial que solo consta de un guión bajo (_), a esta variable se le llama variable anónima. Esta se usan cuando no es importante el nombre de la variable o cuando la variable no puede unificar con otra, dentro de la misma cláusula. El alcance de una variable es la cláusula donde aparece, y el alcance de una constante es todo el programa PROLOG. (ejemplo X, Y, Resultado, _nombre, _). </div> <div class="nb-cell program" name="p3"> isvariable(Variable). isvariable(_temperatura). isvariable(_). </div> <div class="nb-cell markdown" name="md4"> ### Estructuras Término compuesto por otros términos. Una estructura se construye mediante un átomo de función llamado "functor", seguido entre paréntesis, por una conjunto de términos separados por comas, denominados argumentos. Al escribir una estructura, no puede haber ningún espacio entre el functor y el paréntesis abierto antes de los argumentos. Por ejemplo, un punto (X,Y) no es una estructura compuesta correcta y generará un error de compilación. </div> <div class="nb-cell program" name="p4"> fecha(17,enero,2022). punto(X,Y). recta(punto(5,7),punto(6,4)). name (Manuel,Garcia) </div> <div class="nb-cell markdown" name="md5"> ## 1.2 Programas Son de tipo lógico definidos, basados en un conocimiento base que soluciona consultas e infiere información, el conocimiento lo representamos mediante cláusulas de Horn positivas. Las cláusulas son hechos o reglas compuestas usualmente de predicados. La mayoría de los programas Prolog están organizados en cuatro secciones principales: *Dominio:* donde se declaran los argumentos que utilizarán los predicados. *Predicados:* donde se declaran todos los predicados no predefinidos que se utilizarán en las siguientes secciones. *Objetivos:* esta sección permite ejecutar los programas de forma no interactiva, y por tanto, buscará la solución deseada tan pronto como se ejecute el programa. Como también es habitual usar Prolog de forma interactiva es frecuente ejecutar un programa y luego esperar a que se nos pregunte por los objetivos. *Clausulas:* donde se escriben los hechos y las reglas que conocemos del dominio. </div> <div class="nb-cell markdown" name="md6"> # 2. Hechos Cláusulas sin cuerpo que muestra una relación explícita entre objetos y propiedades que estos objetos puedan tener. Son el tipo de sentencia más sencillo y declaran los valores que son verdaderos para un predicado. No tienen que reflejar el mundo real necesariamente, pero será lo que Prolog tomará como verdadero. Están conformados por un predicado y un argumento u objetos. Reglas para definir un predicado: * Los nombres de los hechos (predicado) deben iniciar con minúscula. * Los argumentos se escriben separados por comas, en minúscula y encerrados entre paréntesis. * Todos los hechos deben terminar en punto. </div> <div class="nb-cell markdown" name="md7"> ### 2.1 Propiedades Están compuestos por un único argumento (monádicos) </div> <div class="nb-cell program" name="p5"> capital(bogotá). %Bogotá es una capital color(negro). %Negro es un color animal(perro). %Perro es un animal </div> <div class="nb-cell markdown" name="md8"> ### 2.2 Relaciones Formadas con dos o más argumentos (poliádicos) </div> <div class="nb-cell program" name="p6"> pertenecea(teusaquillo, bogotá). %Teusaquillo pertenece a Bogotá pertencea(bogotá, cundinamarca). pertenecea(cundinamarca, colombia). es(perro, mamífero). %El perro es un mamífero es(mamífero, vertebrado). </div> <div class="nb-cell markdown" name="md10"> # 3. Reglas Cuando la verdad de un hecho depende de la verdad de otro hecho o de un grupo de hechos se usa una regla. Declaran las condiciones para que un predicado sea cierto, con una implicación que pueden relacionar hechos para dar los valores de verdad a un predicado (la cabeza se cumple si el cuerpo se cumple). Funcionan como las fórmulas condicionales habituales en lógica. Una regla está compuesta por una cabeza y un cuerpo. El cuerpo puede estar formado por varios hechos y objetivos. </div> <div class="nb-cell program" name="p7"> amigos(x,y):- leagrada(x,y),leagrada(y,x). </div> <div class="nb-cell markdown" name="md12"> ### 3.1 Conjunciones Emplea el operador lógico AND que es representado por una coma </div> <div class="nb-cell program" name="p8"> primo(x,y):-padre(z,x),padre(w,y),hermano(z,w). </div> <div class="nb-cell markdown" name="md13"> ### 3.2 Disyunciones Emplea el operador lógico OR que es representado por un punto y coma </div> <div class="nb-cell program" name="p9"> hijo(x,y):-padre(y,x);madre(y,x). </div> <div class="nb-cell markdown" name="md14"> ### 3.3 Reglas recursivas Consecución de reglas que se ejecutan de manera iterativa, dandole un grado alto de flexibilidad a la herramienta </div> <div class="nb-cell program" name="p10"> predecesor(x,y):-progenitor(x,y). %Padre predecesor(x,y):-progenitor(x,z),progenitor(z,y). %Abuelo predecesor(x,y):-progenitor(x,z),progenitor(z,w),progenitor(w,y). %Bisabuelo </div> <div class="nb-cell markdown" name="md15"> Para hacer uso de reglas recursivas se debe considerar 2 casos: * Caso básico: Define cuándo se detiene el cálculo. * Caso recursivo: Suponiendo que ya se ha solucionado un caso más simple, define cómo descomponer el caso actual hasta llegar al caso básico </div> <div class="nb-cell program" name="p11"> predecesor(x,y):-progenitor(x,y). predecesor(x,y):-progenitor(x,z),predecesor(z,y). </div> <div class="nb-cell markdown" name="md9"> # 4. Consultas Todos los hechos y reglas definidas se almacenarán en un archivo llamado base de datos o base de conocimientos, sobre ese archivo se pueden realizar una serie de preguntas para extraer conocimiento de la base de datos generada por los hechos. Comienzan con un signo de interrogación seguido de un guión ?- y terminan en punto. Ante una consulta, Prolog intenta hacer un matching sobre la base de conocimiento. Cuando en una consulta se tiene más de una alternativa Prolog devuelve la primera ocurrencia, se obtienen las demás insertando el token punto y coma. Las respuestas a una consulta puede ser true, false o los elementos que pueden tomar una variable definida. </div> <div class="nb-cell markdown" name="md16"> Hechos y reglas: </div> <div class="nb-cell program" name="p12"> es(perro, mamífero). es(mamífero, vertebrado). es(perro,vertebrado):-es(perro, mamífero),es(mamífero, vertebrado). </div> <div class="nb-cell markdown" name="md17"> Consulta: </div> <div class="nb-cell query" name="q1"> es(perro,vertebrado). </div> <div class="nb-cell markdown" name="md11"> # 5. Backtracking En problemas de recursión, prolog se devuelve hasta que encuentra que un hecho base es verdadero y de ahí construye la respuesta. Si un predicado ofrece múltiples reglas para resolver un objetivo, se intentan una por una hasta que una tiene éxito. Si una alternativa no satisface la consulta, se rechaza la regla elegida previamente y se prueba la siguiente. </div> <div class="nb-cell markdown" name="md18"> # 6. Expresiones </div> <div class="nb-cell markdown" name="md19"> Prolog tiene predefinidos los operadores aritméticos más habituales, mediante los que se pueden formar expresiones aritméticas. Como el + para la suma, el asterisco para multiplicación, el doble asterisco para potencia, la palabra mod para el módulo, etc. </div> <div class="nb-cell program" data-singleline="true" name="p13"> 2**5= 32 </div> <div class="nb-cell markdown" name="md35"> La anterior expresión será falsa al correrla ya que es necesario el uso de los predicados aritméticos, cpo ejemplo: </div> <div class="nb-cell program" name="p15"> X is 2**5 </div> <div class="nb-cell markdown" name="md41"> Sí nos mostrará que el valor de X es 32. </div> <div class="nb-cell program" name="p14"> Y is 10 mod 4 </div> <div class="nb-cell program" name="p16"> X@>Y </div> <div class="nb-cell markdown" name="md42"> Si comparamos los valores anteriores solo con los operadores de comparación, dará un error, ya que esta expresión es compleja y se debe usar el @ antes del operador para que sea correcto. Sin embargo, Prolog solo compara las expresiones sin evaluarlas. </div> <div class="nb-cell program" name="p17"> 2 < 6 </div> <div class="nb-cell markdown" name="md43"> A diferencia del anterior ejemplo, éste sí será True, debido a que compara expresiones sencillas. </div> <div class="nb-cell markdown" name="md20"> # 8. Predicados predefinidos </div> <div class="nb-cell markdown" name="md21"> Los predicados predefinidos son aquellos que ya están definidos en PROLOG, es decir, no necesitamos especificarlos mediante cláusulas. Estos predicados se utilizan cuando estamos interesados en tener una interacción entre el programa y el usuario, aceptando por ejemplo que el usuario de entradas y presentando las salidas. </div> <div class="nb-cell markdown" name="md22"> write = escribe el término X en la consola de salida </div> <div class="nb-cell markdown" name="md23"> read = lee el siguiente término en la consola de entrada </div> <div class="nb-cell program" name="p18"> saludo:-write('Ingresa tu nombre: '), read(N), write('Hola, cómo estás '), write(N). </div> <div class="nb-cell program" name="p19"> promedio:-write('Ingresa el primer número: '), read(A), write('Ingresa el segundo número: '), read(B), write('Ingresa el tercer número: '), read(C), write('El promedio es: '), Prom is (A+B+C)/3, write(Prom). </div> <div class="nb-cell markdown" name="md24"> # 9. Listas </div> <div class="nb-cell markdown" name="md25"> Es una secuencia ordenada de elementos que puede tener cualquier longitud, las listas están formadas por cabeza y cola. Se representan como una serie de elementos separados por comas y encerrados entre corchetes. </div> <div class="nb-cell markdown" name="md27"> Su notación es la siguiente: </div> <div class="nb-cell program" name="p21"> L = [1,2,3,4,5] </div> <div class="nb-cell program" name="p20"> K = [manzana, pera, banana] </div> <div class="nb-cell markdown" name="md28"> Y para una lista vacía, simplmete basta con []. </div> <div class="nb-cell markdown" name="md29"> Se pueden utilizar como elementos de la lista cualquier tipo de dato de prolog, incluyendo listas: </div> <div class="nb-cell program" name="p22"> [[m,n,o], [p,q,r]] </div> <div class="nb-cell markdown" name="md26"> </div> <div class="nb-cell markdown" name="md30"> En su forma más básica, una lista se puede ver como un predicado que tiene 2 partes: Cabeza y cola, donde la cabea es el primer elemento y la cola son los demás elementos de la lista. Por ejemplo: </div> <div class="nb-cell program" name="p23"> [Cabeza|Cola]=[1,2,3]. Cabeza = 1. Cola[2,3]. </div> <div class="nb-cell markdown" name="md31"> Prolog provee operadores para computar la unificación entre dos términos. El operador = verifica si la unificación es satisfactoria y el operador \= se satisface cuando no es el caso. </div> <div class="nb-cell markdown" name="md32"> f(X, X) = f(a, Y). X = a. Y = a. f(X, X) \= f(a, Y). </div> <div class="nb-cell markdown" name="md33"> # 10. Árboles </div> <div class="nb-cell markdown" name="md34"> Un árbol binario es una estructura que contiene un nodo padre y dos nodos hijos; uno izquierdo y uno derecho. Se puede decir que un árbol es una estructura con una definición puramente recursiva, ya que se puede definir como el elemento raíz cuyos hijos son a su vez árboles. </div> <div class="nb-cell markdown" name="md36"> Se necesitan 3 elementos para definir un árbol: la raíz, el subárbol izquierdo y el subárbol derecho. </div> <div class="nb-cell program" name="p24"> tree1(t(6, t(4, t(2, nil, nil), t(5, nil, nil)), t(9, t(7, nil, nil), nil))). </div> <div class="nb-cell markdown" name="md37"> Es importante mencionar 3 reglas para realizar los posibles recorridos en el árbol: </div> <div class="nb-cell markdown" name="md38"> ### Inorder: </div> <div class="nb-cell program" name="p26"> inorder(nil, []). inorder(t(K,L,R), List):-inorder(L,LL), inorder(R, LR), append(LL, [K|LR],List). </div> <div class="nb-cell markdown" name="md40"> ### Preorder: </div> <div class="nb-cell program" name="p25"> preorder(nil, []). preorder(t(K,L,R), List):-preorder(L,LL), preorder(R, LR), append([K|LL], LR, List). </div> <div class="nb-cell markdown" name="md39"> ### Postorder: </div> <div class="nb-cell program" data-singleline="true" name="p27"> postorder(nil, []). postorder(t(K,L,R), List):-postorder(L,LL), postorder(R, LR), append(LL, LR,R1), append(R1, [K], List). </div> <div class="nb-cell markdown" name="md44"> # 11. Ejemplos </div> <div class="nb-cell markdown" name="md47"> ### Doomie de analizador sintáctico del inglés </div> <div class="nb-cell markdown" name="md45"> El modelo del lenguaje inglés consta de siete categorías o tipos de lexema : * Sustantivo * Verbo * Adjetivo * Adverbio * Artículo * Conjunción * Preposición </div> <div class="nb-cell markdown" name="md46"> La gramática es sensible al contexto en tanto que obliga que haya coherencia cuantitativa entre sustantivos y verbos, así como entre sustantivos y artículos — e.g., _a man likes a dog_ (es coherente) ; _a man likes a dogs_ (no es coherente). </div> <div class="nb-cell markdown" name="md48"> **Axiomas** </div> <div class="nb-cell markdown" name="md49"> Las reglas sintácticas del inglés están pensadas en términos de los tipos de lexema propios del lenguaje, que en la práctica deben ser reemplazados por lexemas particulares. Por esa razón se construye la estructura axiomática del sistema formal que modela la gramática del inglés con un arbol que progresa desde las categorías más generales hasta los lexemas particulares — en términos formales, se progresa desde los símbolos de la gramática hasta los valores terminales. En la siguiente celda de código, el conjunto de instancias del predicado isa(X, Y) implementa esta estructura arbórea : * **Primer nivel** * word → noun | verb | article * **Segundo nivel** * noun → singular_noun | plural_noun * verb → singular_verb | plural_verb * article → singular_article | plural_article | neutral_article * **Tercer nivel** * singular_noun → _man_ | _dog_ | _woman_ | _leg_ * plural_noun → _men_ | _dogs_ | _women_ | _legs_ * singular_verb → _bites_ | _likes_ * plural_verb → _bite_ | _like_ * singular_article → _a_ * neutral_article → _the_ </div> <div class="nb-cell program" name="p28"> isa(noun, word). isa(verb, word). isa(article, word). isa(singular_noun, noun). isa(plural_noun, noun). isa(sigular_verb, verb). isa(plural_verb, verb). isa(plural_article, article). isa(singular_article, article). isa(neutral_article, article). isa(man, sinular_noun). isa(men, plural_noun). isa(dog, singular_noun). isa(dogs, plural_noun). isa(woman, singular_noun). isa(women, plural_noun). isa(leg, singular_noun). isa(legs, plural_noun). isa(bite, plural_verb). isa(bites, singular_verb). isa(like, plural_verb). isa(likes, singular_verb). isa(a, singular_article). isa(the, neutral_article). </div> <div class="nb-cell markdown" name="md50"> La siguiente celda termina de definir el carácter de los lexemas del lenguaje : </div> <div class="nb-cell program" name="p29"> adjective(big). adjective(small). adverb(strongly). adverb_adj(very). ad_adverb(quite). conjunction(and). conjunction(but). preposition(on). </div> <div class="nb-cell markdown" name="md51"> ¿Por qué no se les implementó, deberá preguntarse el lector, de manera afín a como se implementó a sus predecesores, los sustantivos, verbos y artículos? Porque, como se verá en breve, mientras que conviene a la implementación del analizador sintáctico abstraer tipos de lexema en ciertos casos, en otros casos es del todo innecesario. Para el caso de los terminales de la penúltima celda es esencial no solamente poder atribuirles su carácter como sustantivo, verbo o artículo, sino también como singular o plural. En esta implementación se optó, con fines educativos, por implementar dichas atribuciones por medio de la herencia : se entiende que si un nodo padre, en la estructur arbórea antes descrita, posee ciertas propiedades, los nodos que se desprendan de él también las tendrán. Esto es algo del todo innecesario en la consideración de otras clases de lexema, los adjetivos, adverbios, etc. – de ahí que no se les implemente con el predicado isa(X, Y), y sí con predicados más simples : al no ser de interés atribuirles más propiedad que la que su mismo predicado les atribuye, tampoco es de interés implementar para ellos ninguna forma de herencia. Las atribuciones hechas a los terminales de la penúltima celda están implementadas en esta : </div> <div class="nb-cell program" name="p30"> hasprop(noun, type, noun). hasprop(verb, type, verb). hasprop(article, type, article). hasprop(singular_noun, quant, singular). hasprop(plural_noun, quant, plural). hasprop(singular_verb, quant, singular). hasprop(plural_verb, quant, plural). hasprop(singular_article, quant, singular). hasprop(plural_article, quant, plural). hasprop(neutral_article, quant, singular). hasprop(neutral_article, quant, plural). </div> <div class="nb-cell markdown" name="md52"> Y la herencia de dichas atribuciones está implementada en esta : </div> <div class="nb-cell program" name="p31"> hasproperty(Object, Property, Value):- hasprop(Object, Property, Value). hasproperty(Object, Property, Value):- isa(Object, Parent), hasproperty(Parent, Property, Value). </div> <div class="nb-cell markdown" name="md53"> **Reglas de inferencia** </div> <div class="nb-cell markdown" name="md54"> La anterior celda de código ya definía ambas cláusulas de la regla hasproperty(Object, Property, Value). En lo que sigue se presentará otras reglas de inferencia, a partir de las que se construirá incrementalmente el analizador sintáctico. </div> <div class="nb-cell markdown" name="md55"> La primera regla, para la **verificación de frases nominales**, es nounphrase(...), y cuenta con varias cláusulas : * La primera cláusula estipula que un sustantivo es una frase nominal. * La segunda cláusula estipula que un artículo seguido por un sustantivo es una frase nominal. * La tercera cláusula estipula que un sustantivo seguido por un adjetivo es una frase nominal. * La cuarta cláusula estipula que un artículo, seguido por un adjetivo, seguido por un sustantivo, es una frase nominal. * La quinta cláusula estipula que un adverbio adjetival, seguido por un adjetivo, seguido por un sustantivo, es una frase nominal. * La sexta cláusula estipula que un artículo, seguido por un adverbio adjetival, seguido por un adjetivo, seguido por un sustantivo, es una frase nominal. * La séptima cláusula estipula que una preposición seguida por una frase nominal es una frase nominal. Nótese que las cláusulas 2, 4 y 6, al contener sustantivos y artículos, obligan que ambos sean singulares o plurales (puesto que ambos deben tener el mismo valor de ``Number``) : </div> <div class="nb-cell program" name="p32"> % Primera cláusula nounphrase([Word | End], End, Number):- hasproperty(Word, type, noun), hasproperty(Word, quant, Number). % Segunda cláusula nounphrase([Word1, Word2 | End], End, Number):- hasproperty(Word1, type, article), hasproperty(Word1, quant, Number), hasproperty(Word2, type, noun), hasproperty(Word2, quant, Number). % Tercera cláusula nounphrase([Adjective, Word | End], End, Number):- hasproperty(Word, type, noun), hasproperty(Word, quant, Number), adjective(Adjective). % Cuarta cláusula nounphrase([Word1, Adjective, Word2 | End], End, Number):- hasproperty(Word1, type, article), hasproperty(Word1, quant, Number), adjective(Adjective), hasproperty(Word2, type, noun), hasproperty(Word2, quant, Number). % Quinta cláusula nounphrase([Adverb_Adj, Adjective, Word | End], End, Number):- hasproperty(Word, type, noun), hasproperty(Word, quant, Number), adjective(Adjective), adverb_adj(Adverb_Adj). % Sexta cláusula nounphrase([Word1, Adverb_Adj, Adjective, Word2 | End], End, Number):- hasproperty(Word1, type, article), hasproperty(Word1, quant, Number), hasproperty(Word2, type, noun), hasproperty(Word2, quant, Number), adjective(Adjective), adverb_adj(Adverb_Adj). % Séptima cláusula nounphrase([Preposition | Rest], End, Number):- preposition(Preposition), nounphrase(Rest,End,Number). </div> <div class="nb-cell markdown" name="md56"> La segunda regla, para la **verificación de frases verbales**, es verbphrase(...), y cuenta con varias cláusulas: * La primera cláusula estipula que un verbo es una frase verbal. * La segunda cláusula estipula que un verbo seguido por una frase nominal es una frase verbal. * La tercera cláusula estipula que un adverbio seguido por un verbo, seguido por una frase nominal, es una frase verbal. * La cuarta cláusula estipula que un adverbio seguido por otro adverbio, seguido por un verbo, seguido por una frase nominal, es una frase verbal. Nótese que, por un lado, si el verbo y la frase nominal que le sigue tienen ambos el mismo número gramatical es irrelevante, por lo que el valor de ``Number`` en nounphrase(..., Number) es ``_``, y que, por otro lado, el axioma anteriormente declarado ``ad_adverb(quite).`` significa que la palabra inglesa 'quite' es un adverbio que puede modificar a otro adverbio. El código que implementa esta segunda regla : </div> <div class="nb-cell program" name="p33"> % Primera cláusula verbphrase([Word | End], End, Number):- hasproperty(Word, type, verb), hasproperty(Word, quant, Number). % Segunda cláusula verbphrase([Word | Rest], End, Number):- hasproperty(Word, type, verb), hasproperty(Word, quant, Number), nounphrase(Rest, End, _). % Tercera cláusula verbphrase([Adverb, Word | Rest], End, Number):- adverb(Adverb), hasproperty(Word, type, verb), hasproperty(Word, quant, Number), nounphrase(Rest, End, _). % Cuarta cláusula verbphrase([Ad_adverb, Adverb, Word | Rest], End, Number):- ad_adverb(Ad_adverb), adverb(Adverb), hasproperty(Word, type, verb), hasproperty(Word, quant, Number), nounphrase(Rest, End, _). </div> <div class="nb-cell markdown" name="md57"> La tercera regla, para la **verificación de frases preposicionales**, es prepphrase(...), y estipula que una preposición seguida por una frase nominal es una frase preposicional : </div> <div class="nb-cell program" name="p34"> prepphrase([Preposition | Rest], End):- preposition(Preposition), nounphrase(Rest, End, _). </div> <div class="nb-cell markdown" name="md58"> La cuarta regla, para la **detección de conectores**, es connector(...), y retorna si el primer lexema de una secuencia de lexemas dada es un conector o no : </div> <div class="nb-cell program" name="p35"> connector([X | Rest], Rest):- conjunction(X). </div> <div class="nb-cell markdown" name="md59"> La quinta regla, para la **verificación de oraciones**, es sentence(...), y tiene varias cláusulas : * La primera estipula que una frase nominal seguida por una frase verbal es una oración. * La segunda estipula que una frase nominal seguida por una frase verbal, seguida por una frase preposicional, es una oración. Nótese que el número gramatical de la frase nominal debe ser el mismo de la frase verbal que la sigue : </div> <div class="nb-cell program" name="p36"> sentence(Start, End):- % Primera cláusula (nounphrase(Start, Rest, Number), verbphrase(Rest, End, Number)) ; % Segunda cláusula (nounphrase(Start, Rest, Number), verbphrase(Rest, LastBit, Number), prepphrase(LastBit, End)). % Obsérvese que en ocasiones es posible incluir las cláusulas en el cuerpo de una sola regla, % de manera que no se tenga que dar varias formas a una misma regla (como en los casos anteriores). </div> <div class="nb-cell markdown" name="md60"> La sexta y última regla, para la **verificación de articulaciones** (las estructuras sintácticas más generales, análogas a lo que sería el programa si se tratara d eun lenguaje de programación), es utterance(...), y tiene varias cláusulas : * La primera estipula que una oración es una articulación. * La segunda estipula que una oración seguida por un conector, seguido por una frase preposicional, es una articulación. * La tercera estipula que una oración seguida por un conector, seguido por una articulación, es una articulación. El código que implementa la regla : </div> <div class="nb-cell program" name="p37"> utterance(X):- % Primera cláusula sentence(X,[]) ; % Segunda cláusula (sentence(X,Next_phrase), connector(Next_phrase, Rest), prepphrase(Rest, [])) ; % Tercera cláusula (sentence(X,Next_phrase), connector(Next_phrase, Rest), utterance(Rest)). </div> <div class="nb-cell markdown" name="md61"> Una anotación final es pertinente : la variable ``Rest`` actúa como una variable de retorno, y adquiere su valor cuando, en la cabecera de distintas reglas de inferencia, se designa la cola de una lista como ``Rest`` (véase las reglas nounphrase(...), por ejemplo). En ocasiones la variable ``End`` actúa de forma similar, solo que mientras que ``Rest`` denota lo que falta por procesar de la lista de lexemas, ``End`` denota lo último que se va a procesar. ``LastBit`` en la regla de inferencia sentence(...) representa lo que sería un punto intermedio entre ``Rest`` y ``End``, y ``Next_phrase`` en la regla de inferencia utterance(...) representa lo que sería ``Rest`` antes de ``Rest`` mismo. </div> </div>