首先,您收到了三个关于“单例变量”的明确警告。这是一个非常明确的暗示,表明出了点问题。通常,Prolog 程序员会先解决这个问题。当然,还有其他方法。
所以你的问题是你得到X = [a, b|_17660] 作为答案。这是什么意思? _176660 只是一个必须普遍量化的变量名。换句话说,你得到的答案是:
所有以[a, b|_] 开头的X 都是一个解决方案。像[a, b] 是有意的,但也像[a, b|non_list] 这样丑陋的。甚至是像[a, b, c]这样的误导甚至不正确的。
要了解这个问题的根源,让我们关注一个隐含的地面查询,例如:
?- intersect([a,c,a,b], [d,b,a,b], [a,b|non_list]).
ERROR: Undefined procedure: remove_all/3
啊,你没有显示remove_all/3 的定义。在传统的编程语言中,我们现在必须停下来。但是在 Prolog 中,我们仍然可以继续。无需查看该定义。我将改为使用不再包含remove_all/3 的specialization。所以从某种意义上说,这只是你程序的一部分,但我们仍然可以从中得出结论。这是我使用的:
相交([],Y,Z):-
Z = non_list。
intersect([H|T1], Y, [H|T2]) :- false,
成员(H, Y),
remove_all(H, T1, P),
相交(T1,Y,T2)。
intersect([H|T1], Y, T2) :-
T2 = non_list,
相交(T1,Y,T2)。
这个程序几乎是你的。除了我添加了额外的目标。在另一种语言中,这是不可能的。但是在 Prolog 中,我们可以利用(纯的、单调的)Prolog 程序的一个非常好的特性:您可以随机添加额外的目标,并且仍然可以预测结果是什么:新程序描述了您的目标的 子集原程序做到了。当然,我有一些怀疑,所以我的添加是有一定指导意义的。但是你可以总是对你的错误程序做同样的事情!
仍然不相信?现在使用该新程序查看您实际描述的内容:
?- intersect(Xs, Ys, Zs).
Xs = [],
Zs = non_list ...
?- intersect([], any, non_list).
true.
显然,这不是您想要的。要了解它的来源,我们可以让您的程序更加专业化:
相交([],Y,Z):-
Z = non_list。
intersect([H|T1], Y, [H|T2]) :- false,
成员(H, Y),
remove_all(H, T1, P),
相交(T1,Y,T2)。
intersect([H|T1], Y, T2) :- false,
相交(T1,Y,T2)。
现在应该很明显,事实必须是专门的,否则这些荒谬的解决方案是可能的。这是一个这样的专业:
相交([],_Y,Z):-
Z = []。
intersect([H|T1], Y, [H|T2]) :- false,
成员(H, Y),
remove_all(H, T1, P),
相交(T1,Y,T2)。
相交([H| T1],Y,T2):-
相交(T1,Y,T2)。
事实是:空列表和任何东西的交集就是空列表。让我们保持这种状态,即使 Y = non_list 现在也是可能的。
您的规则仍然被删除,因为我没有看到您的定义。不要紧!我会继续在剩下的程序中发现问题。目前,我不知道在哪里寻找问题。但是我可以通过询问 最一般的查询 来让 Prolog 为我执行此操作,该查询的内容类似于
Prolog,告诉我你能描述的所有解决方案。
(记住这个技巧,你可以随时问这个问题——根本不知道谓词是关于什么的。)
?- intersect(Xs, Ys, Zs).
Xs = Zs, Zs = []
; Xs = [_99922],
Zs = [] ...
第一个答案是完美的,但第二个答案不是。请注意Ys 不会出现在任何地方,因此答案适用于所有Ys。甚至:
?- intersect([a], [a], []).
true.
这个问题和你的规则直接相关,没有任何条件...
请参阅this 以获得干净的解决方案。