46
Prolog VI 1 VI. Meta- cláusulas Jorge Cabrera Gámez Departamento de Informática y Sistemas Universidad de Las Palmas de Gran Canaria

VI. Meta-cláusulas

  • Upload
    jaimie

  • View
    46

  • Download
    0

Embed Size (px)

DESCRIPTION

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 - PowerPoint PPT Presentation

Citation preview

Page 1: VI. Meta-cláusulas

Prolog VI 1

VI. Meta-cláusulas

Jorge Cabrera GámezDepartamento de Informática y Sistemas

Universidad de Las Palmas de Gran Canaria

Page 2: VI. Meta-cláusulas

Prolog VI 2

Í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

Page 3: VI. Meta-cláusulas

Prolog VI 3

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 delprograma.

Prolog dispone de un conjunto de predicados predefinidos para modificar la base de datos de forma dinámica

Page 4: VI. Meta-cláusulas

Prolog VI 4

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.

Page 5: VI. Meta-cláusulas

Prolog VI 5

Ejemplo:

rápido(ana).lento(juan).más_lento(X,Y):- lento(X), rápido(Y).

?- más_lento(A,B).

A = juanB = ana ;

No

?- assert((rápido(patricia))).Yes

?- listing(rápido).rápido(ana).rápido(patricia).Yes

?- más_lento(A,B).

A = juanB = ana ;

A = juanB = patricia ;

No?- 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

?- más_rápido(A,B).

A = anaB = juan ;

A = patriciaB = juan ;

No?- listing(rápido).rápido(ana).rápido(patricia).Yes

?- retract(rápido(ana)).Yes

?- listing(rápido).rápido(patricia).Yes

?- más_rápido(A,B).A = patriciaB = juan ;

No?- assertz(lento(tomás)).Yes

?- listing(lento).lento(juan).lento(tomás).Yes

?- más_rápido(A,B).

A = patriciaB = juan ;

A = patriciaB = tomás ;

No?- retractall(lento(X)).Yes

?- listing(lento).Yes

?- más_rápido(A,B).

No

?- retract(| (más_lento(X,Y):-| lento(X), rápido(Y))).

X = _G339Y = _G340 Yes

?- más_lento(A,B).[WARNING: Undefined predicate: `más_lento/2']

No

Page 6: VI. Meta-cláusulas

Prolog VI 6

¿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).

moverse(Lugar):- retract(aquí(_)), asserta(aquí(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).

SWI-Prolog

Page 7: VI. Meta-cláusulas

Prolog VI 7

A B C

Torres de Hanoi

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)]

Page 8: VI. Meta-cláusulas

Prolog VI 8

Otro uso interesante: Memorización

hanoi_nm(N,A,B,C,Movimientos)Movimientos es la secuencia de movimientos requeridos para moverN discos del poste A al poste B usando el poste C como intermediariode 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

Page 9: VI. Meta-cláusulas

Prolog VI 9

Otro uso interesante: Memorización

hanoi_nm(N,A,B,C,Movimientos)Movimientos es la secuencia de movimientos requeridos para moverN discos del poste A al poste B usando el poste C como intermediariode 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

Page 10: VI. Meta-cláusulas

Prolog VI 10

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.

Page 11: VI. Meta-cláusulas

Prolog VI 11

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)].

Page 12: VI. Meta-cláusulas

Prolog VI 12

%-------------------------------------------------% 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):- !)).

Page 13: VI. Meta-cláusulas

Prolog VI 13

:- 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).

%----------------------------% 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)).

Otro ejemplo de Memorización

Page 14: VI. Meta-cláusulas

Prolog VI 14

Otros predicados para manipulación de la basede 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, perono son cláusulas del programa

Page 15: VI. Meta-cláusulas

Prolog VI 15

?- 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

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íaY = pedro ;

No

Page 16: VI. Meta-cláusulas

Prolog VI 16

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.

Page 17: VI. Meta-cláusulas

Prolog VI 17

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.

Page 18: VI. Meta-cláusulas

Prolog VI 18

:- 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

Síntesis dinámica de reglas

Page 19: VI. Meta-cláusulas

Prolog VI 19

:- 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 ruleknot(2, X, Body2), % NOT Rule2, because it isn't a ruleassert(( testme :- Body1, Body2 )),listing(testme),testme.

fetch(4).

?- dynrule. testme :-

fetch(A),write(A).

4 Yes

Page 20: VI. Meta-cláusulas

Prolog VI 20

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 lospredicados 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 lospredicados involucra más de un fichero. Estoevita la redefinición un predicado cuando seencuentra una nueva definición en otro fichero.

Page 21: VI. Meta-cláusulas

Prolog VI 21

%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.plp(_) :- 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

Page 22: VI. Meta-cláusulas

Prolog VI 22

Declaración de propiedades de predicados

:- dynamic :- multifile:- index(+Head)

:- 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.

:- index(sub_type(1, 1)).

sub_type(horse, animal). ... ...

Page 23: VI. Meta-cláusulas

Prolog VI 23

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)

Page 24: VI. Meta-cláusulas

Prolog VI 24

?- 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érminoen sus componentes?

¿Por qué nos puede interesar construir un nuevo términoa partir de un functor y sus argumentos?

Page 25: VI. Meta-cláusulas

Prolog VI 25

Ejemplo:

Consideremos un programa que manipula figurasgeométricas como cuadrados, círculos, ... , que serepresentan 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)

Page 26: VI. Meta-cláusulas

Prolog VI 26

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 siel número de figuras es grande.

Page 27: VI. Meta-cláusulas

Prolog VI 27

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.

Page 28: VI. Meta-cláusulas

Prolog VI 28

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).

Page 29: VI. Meta-cláusulas

Prolog VI 29

Ejemplo:

Intentemos definir el predicado

sustituye(Subterm, Term, Subterm1, Term1)

Term1 se obtiene de la sustitución de todas lasocurrencias de Subterm en Term por Subterm1.

?- sustituye(sen(x), 2*sen(x)*f(sen(x)), p, F).F = 2*p*f(p)

Page 30: VI. Meta-cláusulas

Prolog VI 30

Ejemplo:

?- sustituye(a+b, f(a, A+B), v, F).A = aB = bF = f(a, v)

?- sustituye(a+b, A+B, v, F).A = aB = bF = v

Page 31: VI. Meta-cláusulas

Prolog VI 31

Ejemplo:

Si Subterm = Term entonces Term1 = Subterm1en otro caso

Si Term es atómico entonces Term1 = Termen 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))]

sustituye(Subterm, Term, Subterm1, Term1)

Page 32: VI. Meta-cláusulas

Prolog VI 32

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).

?- 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

Page 33: VI. Meta-cláusulas

Prolog VI 33

?- sustituye(sen, sen(x), p, F).F = sen(x)

¿Por qué no funciona sustituye/4 en el este caso?

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).

?- sustituye(sen, sen(x), p, F).F = p(x)

Page 34: VI. Meta-cláusulas

Prolog VI 34

:- 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.

Más ejemplos con univ (=..) ...

Page 35: VI. Meta-cláusulas

Prolog VI 35

Un uso habitual de =.. es el de sintetizar nuevosobjetivos:

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)

Page 36: VI. Meta-cláusulas

Prolog VI 36

Otras veces nos interesará extraer el functorprincipal de un término

Se puede emplear =.., pero suele ser más prácticoy eficiente emplear functor y arg.

functor(Term, F, N)es cierto si F es el functor principal de Termy N es la aridad de F

arg(N, Term, A)es cierto si A es el N-ésimo argumento de Termcuando los argumentos se numeran de izda a dchaempezando por 1.

Page 37: VI. Meta-cláusulas

Prolog VI 37

Ejemplo:

?- functor( t( f(X), X, t), Fun, Arity).Fun = tArity = 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)

Page 38: VI. Meta-cláusulas

Prolog VI 38

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.

Page 39: VI. Meta-cláusulas

Prolog VI 39

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.

Page 40: VI. Meta-cláusulas

Prolog VI 40

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

Page 41: VI. Meta-cláusulas

Prolog VI 41

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,115), L).?- bagof(Verdura, item(Verdura,120), L).Verdura = _G297L = [tomates, cebolla] Yes

?- bagof(Verdura, | item(Verdura,Precio), L).

Verdura = _G315Precio = 300L = [coliflor] ;Verdura = _G315Precio = 275L = [pimiento] ;Verdura = _G315Precio = 115L = [lechuga] ;Verdura = _G315Precio = 120L = [tomates, cebolla] ;

No

Las diferentes solucionesagrupadas por el valor dePrecio

?- bagof(Verdura, | item(Verdura,Precio), L).

Verdura = _G315Precio = 300L = [coliflor] ;Verdura = _G315Precio = 275L = [pimiento] ;Verdura = _G315Precio = 115L = [lechuga] ;Verdura = _G315Precio = 120L = [tomates, cebolla] ;

No

?- bagof(Verdura, Precio ^ item(Verdura, Precio), L).Verdura = _G351Precio = _G352L = [tomates, coliflor, pimiento, lechuga, cebolla]

?- bagof(Precio,Verdura ^ item(Verdura,Precio), L).Precio = _G352Verdura = _G351L = [120, 300, 275, 115, 120]

?- bagof(Precio,Verdura ^ item(Verdura,50),L).

No

Page 42: VI. Meta-cláusulas

Prolog VI 42

Similar a bagof, pero ahora se eliminan los duplicados y los elementos de la lista se ordenan: alfabéticamente y de menor a mayor.

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.

item(tomates, 120). item(coliflor, 300).item(pimiento, 275).item(lechuga, 115).item(cebolla, 120).

?- setof(Verdura,Precio ^ item(Verdura,Precio), L).Verdura = _G351Precio = _G352L = [cebolla, coliflor, lechuga, pimiento, tomates](nótese la ordenación alfabética)

?- setof(Precio,Verdura ^ item(Verdura,Precio), L).Precio = _G352Verdura = _G351L = [115, 120, 275, 300] (nótese la eliminación de duplicados y la ordenación de menor a mayor)

Page 43: VI. Meta-cláusulas

Prolog VI 43

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

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 = [ ]

item(tomates, 120). item(coliflor, 300).item(pimiento, 275).item(lechuga, 115).item(cebolla, 120).

?- findall(Verdura,item(Verdura,_),L).Verdura = _G273L = [tomates, coliflor, pimiento, lechuga, cebolla] Yes

?- findall(Precio,item(_,Precio),L).Precio = _G262L = [120, 300, 275, 115, 120] Yes

?- findall(Verdura,item(Verdura,50),L).Verdura = _G279L = [ ] Yes

Page 44: VI. Meta-cláusulas

Prolog VI 44

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 racioncalorias(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).

Page 45: VI. Meta-cláusulas

Prolog VI 45

%% 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([]).

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

Page 46: VI. Meta-cláusulas

Prolog VI 46

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.