I've a bunch of facts.
f(1, John).
f(2, Peter).
f(3, Gordon).
f(4, Bono).
f(5, Carl).
f(6, Mick).
check([], []) .
check([f(X, Y)|L1] , [f(X, Y)|L2] ) :- f(X, Y), check(L1,L2).
And if I run the check predicate
check([ f(1, John), f(3, Gordon), f(2, Peter), _, f(6, Mick), f(5, Carl)], Group).
Should print.
Group = [ f(1, John), f(3, Gordon), f(2, Peter), f(4, Bono), f(6, Mick), f(5, Carl)].
The black space is filled with the missing fact. But my program is printing.
Group = [ f(1, John), f(3, Gordon), f(2, Peter), f(1, John), f(6, Mick), f(5, Carl)].
It's fetching the first fact. How to resolve this?
You are confusing two things: backtracking and iterating a list (through tail recursion).
Additionally, you have in your "facts" database variables (John
, Peter
etc) when you might be actually going for atoms? (like john
, peter
, or, if you want the capital, 'John'
, 'Peter'
). You should see a bunch of "singleton variable" warnings if you try to compile this. This aside,
The query
?- f(X, Y).
will give you by backtracking
X = 1, Y = john;
X = 2, Y = peter
and so on.
The predicate you have written, check/2
, iterates over the list you have given it, and what is actually does on each step is that it checks whether there is a fact f(X, Y)
that fits the X
and Y
you have supplied. (Again, since your second arguments are variables at the moment, this is also not exactly correct, but not important for this explanation).
Since the fact f(1, John)
is the first one defined, this is the one that is matched. If you backtrack, you should see all other facts in the same spot, too.
But what it is that you are actually trying to achieve is not very clear to me.
EDIT:
What you are trying to achieve is very strange. How do you know how many blanks you have? You must know all your facts to know that. Are you trying to make a permutation of your facts?
This was solved before in the previous form of the question. Here's a simple adaptation of that solution:
f(1,john).
f(2,peter).
f(3,gordon).
f(4,bono).
f(5,carl).
f(6,mick).
check(L, C) :-
check(L, [], C).
check([], _, []).
check([f(X,Name)|T], A, [f(X,Name)|C]) :-
f(X, Name),
\+ member(f(X, Name), A),
check(T, [f(X,Name)|A], C).
The key here is that you have to carry along what you've found so far (A
) because with each new query to check
, the query to f
"starts fresh" and searches from the beginning of the database. It's not a backtrack. But when we check for membership and find that the element is a member, we do backtrack to the f
query to get the next one until we hit one that isn't a member of the list we've accumulated so far.
Test run:
| ?- check([f(1,john), f(3,gordon), f(2,peter), _, f(6,mick), f(5,carl)], Group).
Group = [f(1,john),f(3,gordon),f(2,peter),f(4,bono),f(6,mick),f(5,carl)] ? a
no
| ?-
As shown in the other answer that I linked, this technique will work with more than one blank.
You can also do this without the "resultant" list argument and instantiate the free variables in the original list:
check(L) :-
check(L, []).
check([], _).
check([f(X,Name)|T], A) :-
f(X, Name),
\+ member(f(X, Name), A),
check(T, [f(X,Name)|A]).
| ?- X = [f(1,john), _, f(2,peter), _, f(6,mick), f(5,carl)], check(X).
X = [f(1,john),f(3,gordon),f(2,peter),f(4,bono),f(6,mick),f(5,carl)] ? a
X = [f(1,john),f(4,bono),f(2,peter),f(3,gordon),f(6,mick),f(5,carl)]
(1 ms) no
| ?-
Note that if you'd like to use capitalized names, you can enclose them in single quotes so that they are atoms, not variables. For example, f(1, 'John')
.