我有一堆的事实。
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
| ?-
正如在其他的答案,我挂出,这一技术将多张空白的工作。
你也可以这样做没有“结果”列表参数和实例原始列表自由变量:
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')