Is there a easy way to make a query in prolog only return each result once?
for instance I'm trying something like:
deadly(Xn) :- scary(X), Xn is X - 1, Xp is X + 1, not(safe(Xn)), safe(Xp).
deadly(Xp) :- scary(X), Xn is X - 1, Xp is X + 1, not(safe(Xp)), safe(Xn).
deadly(X).
and getting
X = 5
X = 5
X = 5
X = 5
....
Not to usefull for me.
One thing that you can do is to apply setof/3
to the predicate that generates the solutions. But note that setof/3
is implemented by applying sort/2
to the result delivered by bagof/3
(at least this is the case in SWI-Prolog). So, if your solution generator goes on forever, then setof/3
will never be applied...
So I would say that try to program so that duplicates are not generated, i.e. by using the cut (!) where it makes sense.
If I remember correctly there is a predicate solutions (or similar, it's been a while since I programmed Prolog) which collects unique solutions in a list.
Edit: setof/3
is the one I was thinking of. Thanks, Kaarel.
Another approach is to memoize solutions.
:- dynamic seen/1.
% Call this always before calling deadly_wrapper/1
clear_seen :-
retractall(seen(_)).
% This wrapper calls deadly/1 but remembers
% the solution using assert/1, and fails
% if the solution has been "seen" before.
deadly_wrapper(X) :-
deadly(X),
(
seen(X)
->
fail
;
assert(seen(X))
).
% This is for testing.
deadly(1).
deadly(1).
deadly(1).
deadly(5).
deadly(1).
deadly(1).
In case your Prolog supports tabling, then it gets even simpler.
Example file:
:- table deadly/1.
deadly(1).
deadly(1).
deadly(5).
deadly(1).
deadly(5).
Example execution with XSB:
$ xsb
[xsb_configuration loaded]
[sysinitrc loaded]
XSB Version 3.2 (Kopi Lewak) of March 15, 2009
[x86_64-unknown-linux-gnu; mode: optimal; engine: slg-wam;
scheduling: local; word size: 64]
| ?- [deadly_tab].
[Compiling ./deadly_tab]
[deadly_tab compiled, cpu time used: 0.0100 seconds]
[deadly_tab loaded]
yes
| ?- deadly(X).
X = 5;
X = 1;
no
| ?-
It's hard to say without more of your code, but you're probably looking for the cut operator (!
). If you want to post the definition of foo
, I (or someone else who follows) may be able to give a detailed/specific answer.