/* bagof1(O,P,L) construit la liste L des objets O verifiant la 
   propriete P. O est un terme qui contient des variables liees
   a celles de P */

bagof1(O,P,L):-
	P,
	once(add_fact(O)),
	fail.

bagof1(_,_,L) :- !,
	retract(fact(L)).

add_fact(O) :-
	not(fact(X)),
	assert(fact([O])).

add_fact(O) :- 
	retract(fact(L)),
	conc(L,[O],L1),   /* [O|L] construit la liste inverse ! */
	assert(fact(L1)).
	
once(P):- P,!.

conc([],L,L).
conc([X|R],Y,[X|Z]):-
	conc(R,Y,Z).

/* tests */

a([b,[c,d1],e]).
a([b1,[c,d2],e]).
a([b2,[c,d2],e]).
a([b,[c,d4],e]).

t1(L):-
	bagof1(O,a(O),L).
t2(L):-
	bagof1(O,a([_,[_,O],_]),L).
