我必须编写一个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"在最后,我将如何更改我的代码来修复它? 如果有人可以帮助我,我将不胜感激。
答案 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。