Prolog中的子列表(未识别空列表)

时间:2015-12-11 00:05:12

标签: list prolog

我想在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).

但是上面的代码似乎是错误的,因为在一个特定情况下它会抛出真实,而不是抛出错误。我希望我已经明确表示以下屏幕截图:

some sample results

你可能已经注意到第五句(第五句)给出了真实,而不是错误。也就是说,当我写一个表格的句子时:

included_list([ X 下,Y],[W, X 下,V,Z])。

虽然只有x包含在第二个列表中(而不是y),但程序给出的是真的(这是错误的)。

一般来说,如果第一个列表的第一个参数包含在第二个列表中,那么无论前者的其余部分是否包含在后者中,该程序都会给我真实的。

在任何其他情况下,程序会给我正确的结果(真或假)。

我做错了什么?

我会等你的答案!

提前谢谢!

2 个答案:

答案 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)

在这个答案中,我们让 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.