VI. Meta-cláusulas

Preview:

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

Prolog VI 1

VI. Meta-cláusulas

Jorge Cabrera GámezDepartamento de Informática y Sistemas

Universidad de Las Palmas de Gran Canaria

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

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

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.

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

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

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

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

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

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.

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

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

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

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

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

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.

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.

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

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

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.

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

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

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)

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?

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)

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.

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.

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

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)

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

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)

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

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)

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

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)

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.

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)

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.

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.

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

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

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)

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

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

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

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.

Recommended