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