Todas las soluciones

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



emorales 2012-05-03