我有一堆事实。
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).
如果我运行检查谓词
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)].
黑色的空间填满了缺失的事实。但是我的程序正在打印。
Group = [ f(1, John), f(3, Gordon), f(2, Peter), f(1, John), f(6, Mick), f(5, Carl)].
它正在获取第一个事实。如何解决这个问题?
你混淆了两件事:回溯和迭代列表(通过尾部递归)。
此外,你有在你的"事实"数据库变量(John
, Peter
等),当你可能实际上去原子?(如john
, peter
,或者,如果你想大写,'John'
, 'Peter'
)。如果你试图编译它,你应该会看到一堆"单例变量"警告。这一边,
?- f(X, Y).
将通过回溯
给你X = 1, Y = john;
X = 2, Y = peter
等等
你写的谓词,check/2
,迭代你给它的列表,它在每一步实际做的是检查是否有一个事实f(X, Y)
适合你提供的X
和Y
。(同样,由于您的第二个参数目前是变量,因此这也不完全正确,但对于此解释并不重要)。
由于f(1, John)
是第一个定义的事实,因此这是匹配的事实。如果你回溯,你也应该在同一个地方看到所有其他的事实。
但我不太清楚你到底想要达到什么目的。
编辑:你想达到的目的很奇怪。你怎么知道你有多少空包弹?你必须了解所有的事实才能知道这一点。你是在整理你的事实吗?
这在之前的问题形式中已经解决了。下面是对该解决方案的一个简单改编:
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).
这里的关键是,您必须携带到目前为止发现的内容(A
),因为对于每个对check
的新查询,对f
的查询"重新开始"并从数据库的开头进行搜索。这不是回头路。但是,当我们检查成员关系并发现元素是成员时,我们返回到f
查询以获得下一个成员,直到我们遇到一个不属于我们迄今为止积累的列表的成员。
测试运行:
| ?- 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
| ?-
正如我链接的另一个答案所示,该技术将适用于多个空白。
你也可以不带"result "列表参数,在原始列表中实例化自由变量:
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
| ?-
注意,如果您想使用大写的名称,可以将它们括在单引号中,这样它们就是原子,而不是变量。例如:f(1, 'John')
.