我有很多事实。
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)].
它取得了第一个事实。如何解决这个问题?
答案 0 :(得分:2)
你混淆了两件事:回溯和迭代列表(通过尾递归)。
此外,您有"事实"数据库变量(John
,Peter
等)当你真正想要原子时? (例如john
,peter
,或者,如果您想要首都,'John'
,'Peter'
)。你应该看到一堆"单例变量"如果您尝试编译此警告。除此之外,
查询
?- f(X, Y).
会通过回溯
给你X = 1, Y = john;
X = 2, Y = peter
等等。
您编写的谓词check/2
遍历您给出的谓词,每一步实际上做的是检查是否存在符合f(X, Y)
的事实X
您提供的{1}}和Y
。 (同样,由于你的第二个参数目前是变量,这也不完全正确,但对于这个解释并不重要。)
由于f(1, John)
是第一个定义的事实,因此这是匹配的事实。如果你回溯,你应该在同一地点看到所有其他事实。
但是你实际上想要达到的目标对我来说并不是很清楚。
编辑:
你想要达到的目标非常奇怪。你怎么知道你有多少空白?你必须知道所有事实才能知道。你是想对你的事实进行排列吗?
答案 1 :(得分:0)
这是在previous form of the question之前解决的。以下是该解决方案的简单改编:
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
| ?-
如我链接的其他答案所示,此技术可以使用多个空白。
您也可以在没有“结果”列表参数的情况下执行此操作,并在原始列表中实例化自由变量:
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')
。