460 likes | 562 Views
VI. Meta-cláusulas. Jorge Cabrera Gámez Departamento de Informática y Sistemas Universidad de Las Palmas de Gran Canaria. Índice. Manipulación de la base de datos Declaración de propiedades de predicados Construcción y descomposición de términos
E N D
VI. Meta-cláusulas Jorge Cabrera Gámez Departamento de Informática y Sistemas Universidad de Las Palmas de Gran Canaria Prolog VI
Índice. • Manipulación de la base de datos • Declaración de propiedades de predicados • Construcción y descomposición de términos • Como obtener todas las respuestas sin • backtracking: bagof, setof y findall Prolog VI
Manipulación de la base de datos Programa Prolog <----> Base de datos Base de datos: Conjunto de cláusulas que hemos ensamblado antes de iniciar la ejecución del programa. Prolog dispone de un conjunto de predicados predefinidos para modificar la base de datos de forma dinámica Prolog VI
asserta(X) Añade la cláusula X como la primera cláusula de este predicado. Como otros predicados de E/S siempre falla en el backtracking y no deshace sus propios cambios. assertz(X) Como asserta/1, sólo que añade la cláusula X como la última cláusula del predicado. retract(X) Borra la cláusula X de la base de datos. Como en los casos anteriores no es posible deshacer los cambios debidos a este predicado en el backtraking. Prolog VI
Ejemplo: ?- más_lento(A,B). A = juan B = ana ; No ?- más_lento(A,B). A = juan B = ana ; A = juan B = patricia ; No ?- más_rápido(A,B). A = ana B = juan ; A = patricia B = juan ; No ?- listing(rápido). rápido(patricia). Yes ?- más_rápido(A,B). A = patricia B = juan ; No ?- más_rápido(A,B). A = patricia B = juan ; A = patricia B = tomás ; No ?- más_rápido(A,B). No ?- más_lento(A,B). [WARNING: Undefined predicate: `más_lento/2'] No rápido(ana). lento(juan). más_lento(X,Y):- lento(X), rápido(Y). ?- assertz(lento(tomás)). Yes ?- listing(lento). lento(juan). lento(tomás). Yes ?- retract( | (más_lento(X,Y):- | lento(X), rápido(Y))). X = _G339 Y = _G340 Yes ?- assert((rápido(patricia))). Yes ?- listing(rápido). rápido(ana). rápido(patricia). Yes ?- assert( | (más_rápido(X,Y):- | rápido(X),lento(Y))). ?- listing(más_rápido). más_rápido(A, B) :- rápido(A), lento(B). Yes ?- listing(rápido). rápido(ana). rápido(patricia). Yes ?- retract(rápido(ana)). Yes ?- retractall(lento(X)). Yes ?- listing(lento). Yes Prolog VI
¿Es posible definir variables globales en Prolog? Ejemplo adaptado del tutorial de Amzi Prolog :-dynamic aquí/1. ir(Lugar):- puedo_ir(Lugar), moverse(Lugar). puedo_ir(Lugar):- aquí(X), conectado(X, Lugar). conectado(cocina, recibidor). conectado(recibidor, cocina). conectado(cocina, despensa). conectado(despensa, cocina). conectado(cocina, comedor). conectado(comedor, cocina). conectado(comedor, estar). conectado(estar, comedor). aquí(cocina). moverse(Lugar):- retract(aquí(_)), asserta(aquí(Lugar)). SWI-Prolog Prolog VI
M = [ (a to b), (a to c), (b to c), (a to b), (c to a), (c to b), (a to b)] M = [ (a to b), (a to c), (b to c), (a to b), (c to a), (c to b), (a to b)] M = [ (a to b), (a to c), (b to c), (a to b), (c to a), (c to b), (a to b)] M = [ (a to b), (a to c), (b to c), (a to b), (c to a), (c to b), (a to b)] M = [ (a to b), (a to c), (b to c), (a to b), (c to a), (c to b), (a to b)] M = [ (a to b), (a to c), (b to c), (a to b), (c to a), (c to b), (a to b)] M = [ (a to b), (a to c), (b to c), (a to b), (c to a), (c to b), (a to b)] A B C Torres de Hanoi Prolog VI
Otro uso interesante: Memorización hanoi_nm(N,A,B,C,Movimientos) Movimientos es la secuencia de movimientos requeridos para mover N discos del poste A al poste B usando el poste C como intermediario de acuerdo con las reglas del puzzle de las Torres de Hanoi /* Sin memorización */ :- op(1000, xfx, to). hanoi_nm(1,A,B,C,[A to B]). hanoi_nm(N,A,B,C,Movimientos) :- N > 1, N1 is N-1, hanoi_nm(N1,A,C,B,Ms1), hanoi_nm(N1,C,B,A,Ms2), append(Ms1,[A to B|Ms2], Movimientos). SWI-Prolog Prolog VI
Otro uso interesante: Memorización hanoi_nm(N,A,B,C,Movimientos) Movimientos es la secuencia de movimientos requeridos para mover N discos del poste A al poste B usando el poste C como intermediario de acuerdo con las reglas del puzzle de las Torres de Hanoi /* Con memorización */ :- dynamic hanoi/5. :- op(1000, xfx, to). hanoi(1,A,B,C,[A to B]). hanoi(N,A,B,C,Moves) :- N > 1, N1 is N-1, hanoi(N1,A,C,B,Ms1), hanoi(N1,C,B,A,Ms2), append(Ms1,[A to B|Ms2], Moves), lema(hanoi(N,A,B,C,Moves)). lema(P) :- asserta((P :- !)). SWI-Prolog Prolog VI
Aún con la memorización, la solución no es perfecta, pues las soluciones que se memorizan son soluciones de N discos y una secuencia determinada de postes. Por ejemplo, la solución de hanoi_ng(3,a,b,c,Moves) generará las siguientes definiciones: hanoi_ng(3, a, b, c, [ (a to b), (a to c), (b to c), (a to b), (c to a), (c to b), (a to b)]) :- !. hanoi_ng(2, c, b, a, [ (c to a), (c to b), (a to b)]) :- !. hanoi_ng(2, a, c, b, [ (a to b), (a to c), (b to c)]) :- !. Es fácil advertir que cuando se tenga que resolver el problema con 4 discos, hanoi_ng(4,a,b,c,Moves), no será posible utilizar el problema de orden 3 ya resuelto porque las identidades de los postes no coinciden. Concretamente, Sería necesario tener resueltos estos dos problemas: hanoi_ng(3,a,c,b,Ms) y hanoi_ng(3,c,b,a,Ms) Nótese como el programa memoriza dos soluciones diferentes para el problema de dos discos. Prolog VI
Para resolver este problema debemos “generalizar” la solución descubierta para un problema concreto (cierta secuencia de postes): % Sustituye en la secuencia de movimientos (solución) % el nombre de un poste por una variable equivalente. subsWithVariable([],_,[]):-!. subsWithVariable([(X to Y)|Ms],Assocs,[(VX to VY)|VMs]):- find_assoc(X,Assocs,VX), find_assoc(Y,Assocs,VY), subsWithVariable(Ms,Assocs,VMs). find_assoc(A,[(A,VA)|_],VA):-!. find_assoc(A,[_|Assocs],VA):- find_assoc(A,Assocs,VA). Por ejemplo: 6 ?- hanoi_nm(2,a,b,c,M1s), | subsWithVariable(M1s,[(a,A),(b,B),(c,C)],Moves). M1s = [ (a to c), (a to b), (c to b)], Moves = [ (A to C), (A to B), (C to B)]. Prolog VI
%------------------------------------------------- % Con memorización y generalización %------------------------------------------------- hanoi(1,A,B,_,[A to B]):- !. hanoi(N,A,B,C,Moves) :- N > 1, N1 is N-1, hanoi(N1,A,C,B,Ms1), hanoi(N1,C,B,A,Ms2), append(Ms1,[A to B|Ms2], Moves), lema(hanoi(N,A,B,C,Moves)). lema(hanoi(N,P1,P2,P3,Moves)) :- subsWithVariable(Moves,[(P1,A),(P2,B),(P3,C)],VMoves), asserta((hanoi(N,A,B,C,VMoves):- !)). Prolog VI
Otro ejemplo de Memorización %---------------------------- % Computes the next prime % number and updates the % list of prime numbers %---------------------------- find_next_prime(P,NP):- primes(Ps), NP is P+1, \+is_div(NP,Ps), !, append(Ps,[NP],EPs), update_primes(EPs). find_next_prime(P,NP):- NC is P+1, find_next_prime(NC,NP). %---------------------------- % Updates (memoizes) a new % list of prime numbers %---------------------------- update_primes(Ps):- ignore(retract(primes(_))), assert(primes(Ps)). :- dynamic primes/1. %---------------------------- % An initial list of prime % numbers. It grows as needed %---------------------------- primes([2,3,5,7,11,13,17,19]). %---------------------------- % next_prime(P,NP) returns % in NP the first prime % number that is greater than % P %---------------------------- next_prime(P,NP):- primes(Ps), append(_,[P,NP|_],Ps), !. next_prime(P,NP):- find_next_prime(P,NP). Prolog VI
Otros predicados para manipulación de la base de datos (SWI-Prolog) retract/assert: modificar la base de datos de cláusulas. compilan el término que se les pasa como argumento. son costosas. recorda/erase: permiten grabar/borrar una base de datos de términos. mecanismo más rápido que assert/retract, pero no son cláusulas del programa Prolog VI
recorda(+Key, +Term) recorded(+Key, -Valor, -Referencia) ?- progenitor(A,B). [WARNING: Undefined predicate: `progenitor/2'] No ?- listing(progenitor). [WARNING: No predicates for `progenitor'] No ?- recorded(prg,V,R), V=progenitor(luis,_),erase(R). V = progenitor(luis, pedro) R = 1733389 ; No ?- recorded(prg,V,R). V = progenitor(maría, pedro) R = 1734589 ; No ?- recorded(prg,V,R), assert(V). V = progenitor(maría, pedro) R = 1734589 ; No ?- progenitor(X,Y). X = maría Y = pedro ; No ?- recorda(prg,(progenitor(maría,pedro))). Yes ?- recorda(prg,(progenitor(luis,pedro))). Yes ?- recorded(prg,Valor,Referencia). Valor = progenitor(maría, pedro) Referencia = 1734589 ; Valor = progenitor(luis, pedro) Referencia = 1733389 No Prolog VI
erase(+Referencia) • Puede emplearse tanto con términos, como con cláusulas. • abolish(:PredicateIndicator) • Elimina todas las cláusulas de un predicado de functor Functor y aridad Aridad de la base de datos. Todos los atributos de predicado (dynamic, multifile, index, etc.) toman su valor por defecto. “Abolir” un predicado importado sólo elimina el enlace importado; el predicado mantendrá su antigua definición en el módulo donde se define. • De acuerdo con el estándar ISO, abolish/1 sólo puede emplearse sobre predicados dinámicos. Esto es extraño, ya que para manejar este tipo de predicados ya se dispone de retract/1 y retractall/1. El predicado abolish/1 se introdujo en el DEC-10 Prolog precisamente para operar con definiciones estáticas. En SWI-Prolog, abolish/1 funciona sobre procedimientos estáticos, a menos el “flag” iso se fije a true. • Se aconseja emplear retractall/1 para borrar todas las cláusulas de un predicado dinámico. Prolog VI
flag(+Key, -Old, +New) Key is an atom, integer or term. As with the recorded database, if Key is a term, only the name and arity are used to locate the flag. Unify Old with the old value associated with Key. If the key is used for the first time Old is unified with the integer 0. Then store the value of New, which should be an integer, float, atom or arithmetic expression, under Key. flag/3 is a fast mechanism for storing simple facts in the database. The flag database is shared between threads and updates are atomic, making it suitable for generating unique integer counters. clause(?Head, ?Body) Succeeds when Head can be unified with a clause head and Body with the corresponding clause body. Gives alternative clauses on backtracking. For facts Body is unified with the atom true. Normally clause/2 is used to find clause definitions for a predicate, but it can also be used to find clause heads for some body template. clause(?Head, ?Body, ?Reference) Equivalent to clause/2, but unifies Reference with a unique reference to the clause (see also assert/2, erase/1). If Reference is instantiated to a reference the clause's head and body will be unified with Head and Body. Prolog VI
Síntesis dinámica de reglas :- dynamic testme/0. knot(1, fetch(Variable)). knot(2, write(Variable)). dynrule :- knot(1, Rule1), knot(2, Rule2), assert(( testme :- Rule1, Rule2 )), listing(testme), testme. fetch(A) :- A = 4. ?- dynrule. testme :- fetch(A), write(B). _L114 Yes Prolog VI
:- dynamic testme/0. knot(1, X, fetch(X)). knot(2, X, write(X)). dynrule :- knot(1, X, Body1), % NOT Rule1, because it isn't a rule knot(2, X, Body2), % NOT Rule2, because it isn't a rule assert(( testme :- Body1, Body2 )), listing(testme), testme. fetch(4). ?- dynrule. testme :- fetch(A), write(A). 4 Yes Prolog VI
Declaración de propiedades de predicados :- dynamic :- multifile :- index(+Head) • :- dynamic • aquí/0, • baz/2. • dynamic +Functor/+Arity, \ldots • Informa al intérprete que la definición de los • predicados puede cambiar durante la ejecución • (mediante assert/retract) • :- multifile • antepasados/2. • multifile +Functor/+Arity, \ldots • Informa al intérprete que la definición de los • predicados involucra más de un fichero. Esto • evita la redefinición un predicado cuando se • encuentra una nueva definición en otro fichero. Prolog VI
%Fichero uno.pl :- multifile p/1. :-ensure_loaded(’dos.pl'). p(a). p(b). p(X) :- q(X), b(_). q(a). b(c). %Fichero dos.pl p(_) :- b(d). b(d). ?- [uno]. dos.pl compiled, 0.05 sec, 620 bytes. [WARNING: (c:/uno.pl:9) Redefined: b/1] c:/uno.pl compiled, 0.05 sec, 1,296 bytes. ?- listing(p). p(A) :- b(d). p(a). p(b). p(A) :- q(A), b(B) Yes ?- listing(b). b(c). Yes Prolog VI
Declaración de propiedades de predicados :- dynamic :- multifile :- index(+Head) :- index(sub_type(1, 1)). sub_type(horse, animal). ... ... • :- index(+Head) • Indiza las cláusulas del predicado con el mismo nombre y aridad que el argumento utilizando los valores de los argumentos. • Permite especificar sobre qué argumentos se indiza este predicado (de los 32 primeros, máx. 4). • Útil en predicados definidos mediante numerosos hechos. Prolog VI
Construcción y descomposición de términos Existen tres predicados predefinidos para descomponer términos o construir nuevos términos: Term =.. L functor(Term, F, N) arg(N, Term, A) Prolog VI
?- f(a,b) =.. L. L = [f, a, b] ?- T =.. [progenitor, miguel, maría ] T = progenitor(miguel, maría) ?- Z =.. [p, X, g(X,Y) ]. Z = p(X, g(X,Y)) ¿Por qué nos puede interesar descomponer un término en sus componentes? ¿Por qué nos puede interesar construir un nuevo término a partir de un functor y sus argumentos? Prolog VI
Ejemplo: • Consideremos un programa que manipula figuras • geométricas como cuadrados, círculos, ... , que se • representan por un functor que indica el tipo de • figura y unos argumentos que la definen: • cuadrado(Lado) • triángulo(Lado1, Lado2, Lado3) • círculo(Radio) • Una de las operaciones a realizar sobre las figuras • aumenta(Fig, Factor, Fig1) Prolog VI
Ejemplo: (Cont.) Una posibilidad: aumenta(cuadrado(A), F, cuadrado(A1)) :- A1 is A*F. aumenta(círculo(R), F, circulo(R1)) :- R1 is R*F. aumenta(rectángulo(A,B), F, rectángulo(A1,B1)) :- A1 is A*F, B1 is B*F. ... Funcionaría, pero no es elegante. Especialmente si el número de figuras es grande. Prolog VI
Ejemplo: (Cont.) Un intento para agrupar todas figuras que estén parametrizadas por un único parámetro: aumenta(Tipo(Par), F, Tipo(Par1)) :- Par1 is Par*F. No está permitido en Prolog ya que el functor debe ser un átomo y no una variable. Prolog VI
Ejemplo: (Cont.) La solución: aumenta(Fig, F, Fig1) :- Fig =.. [Tipo | Parámetros], multiplica_lista(Parámetros, F, Parámetros1), Fig1 =.. [Tipo | Parámetros1]. multiplica_lista([ ],_, [ ]). multiplica_lista([ X | L], F, [ X1 | L1]) :- X1 is F*X, multiplica_lista( L, F, L1). Prolog VI
Ejemplo: Intentemos definir el predicado sustituye(Subterm, Term, Subterm1, Term1) Term1 se obtiene de la sustitución de todas las ocurrencias de Subterm en Term por Subterm1. ?- sustituye(sen(x), 2*sen(x)*f(sen(x)), p, F). F = 2*p*f(p) Prolog VI
Ejemplo: ?- sustituye(a+b, f(a, A+B), v, F). A = a B = b F = f(a, v) ?- sustituye(a+b, A+B, v, F). A = a B = b F = v Prolog VI
Ejemplo: sustituye(Subterm, Term, Subterm1, Term1) Si Subterm = Term entonces Term1 = Subterm1 en otro caso Si Term es atómico entonces Term1 = Term en otro caso la sustitución debe realizarse en los argumentos de Term ?- 2*sen(x)*f(sen(x)) =.. [F | Args]. F = * Args = [2*sen(x), f(sen(x))] Prolog VI
?- 2*sen(x)*f(sen(x)) =.. [F | Args]. F = * Args = [2*sen(x), f(sen(x))] ?- sustituye(mi, [mi,perro, [en,mi,casa]], tu, F). F = [tu, perro, [en, tu, casa]] Yes Ejemplo: sustituye(Term, Term, Term1, Term1):- !. sustituye(_, Term, _, Term):- atomic(Term),!. sustituye(Sub, Term, Sub1, Term1):- Term =.. [F | Args], sust_lista(Sub, Args, Sub1, Args1), Term1 =.. [F | Args1]. sust_lista(_,[ ],_,[ ]). sust_lista(Sub,[Term|Terms], Sub1, [Term1|Terms1]) :- sustituye(Sub, Term, Sub1, Term1), sust_lista(Sub, Terms, Sub1, Terms1). Prolog VI
¿Por qué no funciona sustituye/4 en el este caso? ?- sustituye(sen, sen(x), p, F). F = sen(x) ?- sustituye(sen, sen(x), p, F). F = p(x) sustituye(Term, Term, Term1, Term1):- !. sustituye(_, Term, _, Term):- atomic(Term),!. sustituye(Sub, Term, Sub1, Term1):- Term =.. [F | Args], sustituye(Sub, F, Sub1, F1), sust_lista(Sub, Args, Sub1, Args1), Term1 =.. [F1 | Args1]. sust_lista(_,[ ],_,[ ]). sust_lista(Sub,[Term|Terms], Sub1, [Term1|Terms1]) :- sustituye(Sub, Term, Sub1, Term1), sust_lista(Sub, Terms, Sub1, Terms1). Prolog VI
Más ejemplos con univ (=..) ... :- op(100, xfx, isf). R isf OPs :- ( OPs =.. [F, A, C/D], integer(A) -> OPs1 =.. [F, A/1,C/D] ; OPs =.. [F, A/B, C], integer(C) -> OPs1 =.. [F, A/B,C/1] ), !, R isf OPs1. R isf OPs :- OPs =.. [_, A, B], integer(A), integer(B), !, R is OPs. R isf OPs:- OPs =..[F,A,B], R1 isf A, R2 isf B, OPs1 =..[F,R1,R2], R isf OPs1. Prolog VI
Un uso habitual de =.. es el de sintetizar nuevos objetivos: obtener(Functor), calcular(ArgList), Objetivo =.. [Functor | ArgList] Objetivo o alternativamente, si sintácticamente se requiere que el functor principal de un objetivo sea un átomo, call(Objetivo) Prolog VI
Otras veces nos interesará extraer el functor principal de un término Se puede emplear =.., pero suele ser más práctico y eficiente emplear functor y arg. functor(Term, F, N) es cierto si F es el functor principal de Term y N es la aridad de F arg(N, Term, A) es cierto si A es el N-ésimo argumento de Term cuando los argumentos se numeran de izda a dcha empezando por 1. Prolog VI
Ejemplo: ?- functor( t( f(X), X, t), Fun, Arity). Fun = t Arity = 3 ?- arg( 2, f( X, t(a), t(b)), Y). Y = t(a) ?- functor( D, fecha, 3), | arg(1,D,29), arg(2,D, junio), arg(3,D,1998). D = fecha(29, junio, 1998) Prolog VI
Cómo cambiar un argumento (I) setarg/3: deshace las asignaciones en el backtraking ?- F = f( X, t(a), t(b)), setarg(2,F,t(c)). F = f(X, t(c), t(b)) Yes setarg(+Arg, +Term, +Value) Extra-logical predicate. Assigns the Arg-th argument of the compound term Term with the given Value. The assignment is undone if backtracking brings the state back into a position before the setarg/3 call. See also nb_setarg/3. This predicate may be used for destructive assignment to terms, using them as an extra-logical storage bin. Always try hard to avoid the use of setarg/3 as it is not supported by many Prolog systems and one has to be very careful about unexpected copying as well as unexpected not copying of terms. Prolog VI
Cómo cambiar un argumento (II) nb_setarg/3: NO deshace las asignaciones en el backtraking ?- F = f( X, t(a), t(b)), nb_setarg(2,F,t(c)). F = f(X, t(c), t(b)) Yes nb_setarg(+Arg, +Term, +Value) Assigns the Arg-th argument of the compound term Term with the given Value as setarg/3, but on backtracking the assignment is not reversed. If Term is not atomic, it is duplicated using duplicate_term/2. This predicate uses the same technique as nb_setval/2. We therefore refer to the description of nb_setval/2 for details on non-backtrackable assignment of terms. This predicate is compatible to GNU-Prolog setarg(A,T,V,false), removing the type-restriction on Value. See also nb_linkarg/3. Below is an example for counting the number of solutions of a goal. Note that this implementation is thread-safe, reentrant and capable of handling exceptions. Realising these features with a traditional implementation based on assert/retract or flag/3 is much more complicated. Prolog VI
Como obtener todas las respuestas sin backtracking Una forma de obtener “todas las respuestas”: * Agotar las posibilidades de vuelta-atrás Otra: * Emplear los predicados bagof, setof y findall Prolog VI
?- bagof(Verdura, | item(Verdura,Precio), L). Verdura = _G315 Precio = 300 L = [coliflor] ; Verdura = _G315 Precio = 275 L = [pimiento] ; Verdura = _G315 Precio = 115 L = [lechuga] ; Verdura = _G315 Precio = 120 L = [tomates, cebolla] ; No ?- bagof(Verdura, | item(Verdura,Precio), L). Verdura = _G315 Precio = 300 L = [coliflor] ; Verdura = _G315 Precio = 275 L = [pimiento] ; Verdura = _G315 Precio = 115 L = [lechuga] ; Verdura = _G315 Precio = 120 L = [tomates, cebolla] ; No Las diferentes soluciones agrupadas por el valor de Precio • bagof(X, P, L) • Produce la lista L de todos los objetos X que satisfacen el objetivo P. Normalmente X es una variable en P. item(tomates, 120). item(coliflor, 300). item(pimiento, 275). item(lechuga, 115). item(cebolla, 120). ?- bagof(Verdura, item(Verdura,120), L). Verdura = _G297 L = [tomates, cebolla] Yes ?- bagof(Verdura, Precio ^ item(Verdura, Precio), L). Verdura = _G351 Precio = _G352 L = [tomates, coliflor, pimiento, lechuga, cebolla] ?- bagof(Precio,Verdura ^ item(Verdura,Precio), L). Precio = _G352 Verdura = _G351 L = [120, 300, 275, 115, 120] ?- bagof(Precio,Verdura ^ item(Verdura,50),L). No bagof(Verdura, item(Verdura,115), L). Prolog VI
?- setof(Precio,Verdura ^ item(Verdura,Precio), L). Precio = _G352 Verdura = _G351 L = [115, 120, 275, 300] (nótese la eliminación de duplicados y la ordenación de menor a mayor) ?- setof(Verdura,Precio ^ item(Verdura,Precio), L). Verdura = _G351 Precio = _G352 L = [cebolla, coliflor, lechuga, pimiento, tomates] (nótese la ordenación alfabética) • setof(X, P, L) • Produce la lista L de todos los objetos X que satisfacen el objetivo P. Normalmente X es una variable en P. Similar a bagof, pero ahora se eliminan los duplicados y los elementos de la lista se ordenan: alfabéticamente y de menor a mayor. item(tomates, 120). item(coliflor, 300). item(pimiento, 275). item(lechuga, 115). item(cebolla, 120). Prolog VI
?- findall(Verdura,item(Verdura,_),L). Verdura = _G273 L = [tomates, coliflor, pimiento, lechuga, cebolla] Yes ?- findall(Verdura,item(Verdura,50),L). Verdura = _G279 L = [ ] Yes • findall(X, P, L) • Produce la lista L de todos los objetos X que satisfacen el objetivo P. Si el objeto X no verifica P, findall se verifica con L = [ ] ?- findall(Precio,item(_,Precio),L). Precio = _G262 L = [120, 300, 275, 115, 120] Yes Similar a bagof y setof, pero ahora se incluyen en la lista todos los elementos, incluso aquellas soluciones que difieren en otras variables de P item(tomates, 120). item(coliflor, 300). item(pimiento, 275). item(lechuga, 115). item(cebolla, 120). Prolog VI
Otro ejemplo inspirado en el ejemplo del restaurante Problema: Definir el predicado calorias_conocidas/0 que indique todos los platos que no disponen de la correspondiente definición de calorias % menu entrada(paella). entrada(gazpacho). entrada(langostinos). entrada(consome). entrada('sopa de fideos'). carne(filete_de_cerdo). carne(solomillo). carne(pollo_asado). pescado(trucha). pescado(bacalao). postre(flan). postre(natilla). postre(nueces_con_miel). postre(naranja). % Valor calorico de una racion calorias(paella, 200). calorias(gazpacho, 150). calorias(consome, 300). calorias(filete_de_cerdo, 400). calorias(pollo_asado, 280). calorias(trucha, 160). calorias(bacalao, 300). calorias(flan, 200). calorias(nueces_con_miel, 500). calorias(naranja, 50). Prolog VI
7 ?- | calorias_conocidas. No hay definición de calorias para "langostinos". No hay definición de calorias para "sopa de fideos". No hay definición de calorias para "solomillo". No hay definición de calorias para "natilla". Yes % % Verificación de que todos los platos % disponen de la correspondiente definición % de calorías % calorias_conocidas :- verifica_plato(entrada), verifica_plato(carne), verifica_plato(pescado), verifica_plato(postre). verifica_plato(Plato):- P =..[Plato, E], setof(E,P,Es), verifica_cal(Es). verifica_cal([E|Es]):- ( calorias(E,_) -> true ; format('No hay definición de calorias para \”~w\”.~n',[E]) ), verifica_cal(Es). verifica_cal([]). Prolog VI
Sumario. • Las implementaciones de Prolog proporcionan un • conjunto de predicados metalógicos sumamente útiles. • Que permiten construir o descomponer términos • utilizando el operador =.., functor o arg. • Que permiten modificar la base de datos clausal • utilizando assert, retract y sus variantes. • Que proporcionan listas de objetos que satisfacen una • cierta condición empleando bagof, setof o findall. Prolog VI