在prolog中查找2个列表中的所有匹配元素

时间:2017-09-09 16:26:31

标签: list prolog

我必须编写一个Prolog程序,找到2个单独列表之间的所有匹配元素。在实践中,它必须如下所示:

?- intersect([a,c,a,b], [d,b,a,b], X).

X = [a,b]

到目前为止我所拥有的是:

intersect([], Y, Z).
intersect([H| T1], Y, [H| T2]) :-
   member(H, Y),
   remove_all(H, T1, P),
   intersect(T1, Y, T2).
intersect([H| T1], Y, T2) :-
   intersect(T1, Y, T2).

(我必须在上一个练习中创建一个remove_all函数。这会删除列表中与你给出的匹配的所有元素)

除了一件事,这是有效的,我的回答是这样的:

X = [a, b|_17660]

我是Prolog的新手并且对此知之甚少。为什么会出现" | _17660"在最后,我将如何更改我的代码来修复它? 如果有人可以帮助我,我将不胜感激。

1 个答案:

答案 0 :(得分:4)

首先,你有三个关于"单身变量"的清晰警告。这是一个非常明确的暗示,出了问题。通常,Prolog程序员会首先解决这个问题。但当然,还有其他方法。

所以你的问题是你得到X = [a, b|_17660]作为答案。这是什么意思? _176660只是一个变量名,必须通用量化。换句话说,你得到的答案是:

  

X开头的所有[a, b|_]都是解决方案。与预期的[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专精。所以从某种意义上说,这只是你的计划的一部分,但我们仍然可以从中得出结论。这就是我使用的:

intersect([], Y, Z) :- Z = non_list.
intersect([H| T1], Y, [H| T2]) :- false,
   member(H, Y),
   remove_all(H, T1, P),
   intersect(T1, Y, T2).
intersect([H| T1], Y, T2) :- T2 = non_list,
   intersect(T1, Y, T2).

这个程序几乎是你的。除了我已经添加了额外的目标。在另一种语言中,这是不可能的。但是在Prolog中我们可以利用(纯粹的,单调的)Prolog程序的一个非常好的属性:你可以随机添加额外的目标并仍然预测结果将是什么:新程序描述了你的子集原计划做了。当然,我有一些怀疑,所以我的添加有点引导。但你可以总是对你的错误程序做同样的事情!

还是不相信?现在使用该新程序来查看您实际描述的内容:

?- intersect(Xs, Ys, Zs).
   Xs = [],
   Zs = non_list ...

?- intersect([], any, non_list).
   true.
显然,这不是你想要的。要了解它的来源,我们可以更加专注于您的计划:

intersect([], Y, Z) :- Z = non_list.
intersect([H| T1], Y, [H| T2]) :- false,
   member(H, Y),
   remove_all(H, T1, P),
   intersect(T1, Y, T2).
intersect([H| T1], Y, T2) :- false,
   intersect(T1, Y, T2).

现在应该很明显,事实必须是专门的,否则这些无意义的解决方案是可能的。这是一个专业化:

intersect([], _Y, Z) :-
   Z = [].
intersect([H| T1], Y, [H| T2]) :- false,
   member(H, Y),
   remove_all(H, T1, P),
   intersect(T1, Y, T2).
intersect([H| T1], Y, T2) :-
   intersect(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