A veces queremos obtener todas las soluciones. Esto permite convertir
backtracking en interacción y resuleve el problema de pasar
información de una interación a la otra por medio de backtracking.
findall, bagof, setof
findall(Var,Pred,Lista). clases(juan,prolog,miercoles). clases(juan,cocina,jueves). clases(juan,tenis,viernes). clases(maria,ingles,lunes). clases(maria,tenis,jueves). clases(maria,algebra,miercoles). ?- findall(Dia,clases(_,_,Dia), Dias). Dias = [miercoles,jueves,viernes,lunes,jueves,miercoels] ?- findall(Materia,clases(_,Materia,_), Materias). ?- findall(Nombre/Materia, clases(Nombre,Materia,_),L). ?- findall(Clase,clases(juan,Clase,_),L).
Si queremos simularlo podemos guardar una lista de soluciones
% Asume que X esta dentro de Meta
findall(X,Meta,Sols) :-
( call(Meta),
assertz(lista(X)),
fail
; assertz(lista(fondo)),
colecta(Sols)
).
colecta(Sols) :-
retract(lista(X)), !,
( X == fondo, !, Sols = []
; Sols = [X|Resto],
colecta(Resto)
).
El codigo tiene un pequeño ``error''
?- findall(X,member(X,[alto,ancho,fondo,peso,color,marca]),L). L = [alto,ancho] ?- listing(lista). lista(peso). lista(color). lista(marca). lista(fondo).Posible solución:
findall(X,Meta,Sols) :-
( assertz('todas las sols'([])),
call(Meta),
assertz('todas las sols'({X})),
fail
; \'{e}ncuentra todas'([],Sols)
).
\'{e}ncuentra todas'(Inter,Res) :-
retract('todas las sols'(Sol1),
!,
\'{e}ncuentra todas'(Sol1, Inter, Res).
\'{e}ncuentra todas'([],Res,Res).
\'{e}ncuentra todas'({X},Inter,Res) :-
\'{e}ncuentra todas'([X|Inter],Res).
La otra posibilidad es usar la base de datos interna de Prolog que nos
da un número de referencia único
findall(X,Meta,Sols) :-
( recorda('las sols',[],MarcaRef),
call(Meta),
recorda('las sols',X,_),
fail
; \'{e}ncuentra todas'(MarcaRef,[],L)
).
\'{e}ncuentra todas'(MarcaRef,Inter, Sol) :-
recorded('las sols', X, Ref), !,
erase(Ref),
( Ref = MarcaRef -> Inter = Sol
; \'{e}ncuentra todas'(MarcaRef,[X|Inter],Sol)
).
Todos los predicados con el mismo nombre y argumentos se guardan con
la misma llave. Todos tiene un número de referencia único.
?- bagof(Materia, clases(N, Materia, D), Mats). N=juan, D=jueves, Mats=[cocina]; N=juan, D=miercoles, Mats=[prolog]; ... ?- bagof(Materia,Dia^clases(Nombre,Materia,Dia), Mats). Nombre = juan, Mats = [prolog,cocina,tenis]; Nombre = maria, Mats = [ingles,tenis,algebra] ?- setof(Materia,Dia^Nombre^clases(Nombre,Materia,Dia), Mats). Mats = [algebra,cocina,ingles,prolog,tenis]
setof quita duplicados y ordena
copy(A,B) :- setof(X,A^(A=X),[B]).
Con numera_vars se puede hacer lo siguiente:
variantes(A,B) :-
\+ \+ (numera_vars(A,0,N),
numera_vars(B,0,N),
A = B).
verifica(X) :- \+ \+ X.
var(X) :- \+ \+ X = a, \+ \+ X = b.
(i.e., lo único que instancia a ``a'' y ``b'' al mismo tiempo es una
variable)
ground(Term) :- numera_vars(Term,0,0).