我想在Prolog中创建一个谓词,它将检查列表A是否是列表B的子列表。此外,我不希望我的程序将空列表视为另一个列表的子集。
E.g。 included_list([1,4],[1,2,3,4,5])。 真正。 included_list([2,3],[1,2,3,4,5])。 真正。 included_list([1,6],[1,2,3,4,5])。 假。 included_list([],[1,2,3,4,5])。 假。 等等...
所以,到目前为止,我已经编写了以下代码:
member(X,[X|Tail]).
member(X,[Head|Tail]):- member(X,Tail).
included_list([X],_).
included_list([Head|Tail],List):- member(Head,List), included_list(Tail,List).
但是上面的代码似乎是错误的,因为在一个特定情况下它会抛出真实,而不是抛出错误。我希望我已经明确表示以下屏幕截图:
你可能已经注意到第五句(第五句)给出了真实,而不是错误。也就是说,当我写一个表格的句子时:
included_list([ X 下,Y],[W, X 下,V,Z])。
虽然只有x包含在第二个列表中(而不是y),但程序给出的是真的(这是错误的)。
一般来说,如果第一个列表的第一个参数包含在第二个列表中,那么无论前者的其余部分是否包含在后者中,该程序都会给我真实的。
在任何其他情况下,程序会给我正确的结果(真或假)。
我做错了什么?
我会等你的答案!
提前谢谢!
答案 0 :(得分:3)
您的问题是included_list/2
的第一个条款。这样:
included_list([X], _).
这是什么意思?这意味着,"如果第一个参数是包含一个元素的列表,则成功,忽略第二个参数。"
简而言之:如果你不忽略编译器警告,你就会抓住这个错误。你应该得到一个响亮而清晰的" Singleton变量"警告,暗示你写的代码不符合你的想法。
你的意思更多的是:
subset_list([X|Xs], Ys) :-
subset_list_1(Xs, X, Ys).
subset_list_1([], X, Ys) :-
member(X, Ys).
subset_list_1([X|Xs], X0, Ys) :-
member(X0, Ys),
subset_list_1(Xs, X, Ys).
但我不知道你为什么不简单地使用可用的subset/2
,只是添加一个要求该子集不是空列表的要求:
subset_list(Subset, List) :-
Subset = [_|_], % a list with at least one element
subset(Subset, List).
尽管文档声称,subset/2
的第二个参数不一定是真正的" set",但它确实期望两个列表都是基础的(不包含任何自由变量) )。您可以看到源代码here。
答案 1 :(得分:3)
在这个答案中,我们让meta-predicate maplist/2
处理递归并定义:
all_included(Sub, Es) :- same_length(Es, Xs), Sub = [_|_], % minimum length: 1 append(_, Sub, Xs), % maximum length: as long as `Es` maplist(list_member(Es), Sub).
让我们运行OP给出的查询! 首先,我们期望成功的用例:
?- member(Xs, [[1,4],[2,3],[2,3,5],[3,4]]), all_included(Xs, [1,2,3,4,5]).
Xs = [1,4]
; Xs = [2,3]
; Xs = [2,3,5]
; Xs = [3,4]
; false.
接下来,我们期望失败的一些用例:
?- member(Xs, [[],[2,6],[1,6]]), all_included(Xs, [1,2,3,4,5]).
false.
?- all_included([3,5], [1,2,5]).
false.