predicate to fetch missing fact

夙愿已清 提交于 2019-12-25 02:58:37

问题


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?


回答1:


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?




回答2:


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



来源:https://stackoverflow.com/questions/23630505/predicate-to-fetch-missing-fact

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!