使用length / 2和ord_subset / 2生成子集

时间:2015-06-25 10:28:55

标签: prolog swi-prolog

我是prolog的初学者。我在swipl解释器中试过这个:

?- length(Lists, 3), ord_subset(Lists, [1, 2, 3, 4]).
false.

期望得到[1,2,3,4]子集的所有长度为3的列表,如[1,2,3]或[1,2,4]。为什么我会弄错?

注意:长度和ord_subset都是SWI-Prolog中的内置函数(或者它们被调用的任何函数)。

1 个答案:

答案 0 :(得分:1)

您没有得到解决方案,因为ord_subset/2谓词只有检查,如果列表是另一个列表的子集;它不会生成子集。

这是一种简单的方法来定义一个谓词,它可以完成你的目标:

subset_set([], _).
subset_set([X|Xs], S) :-
    append(_, [X|S1], S),
    subset_set(Xs, S1).

这假定这些是“ordsets”,即没有重复的排序列表。

您会注意到该子集恰好也是一个子序列。我们本来可以写:

subset_set(Sub, Set) :-
    % precondition( ground(Set) ),
    % precondition( is_list(Set) ),
    % precondition( sort(Set, Set) ),
    subseq_list(Sub, Set).

subseq_list([], []).
subseq_list([H|T], L) :-
    append(_, [H|L1], L),
    subseq_list(T, L1).

无论使用哪种定义,您都会得到:

?- length(Sub, 3), subset_set(Sub, [1,2,3,4]).
Sub = [1, 2, 3] ;
Sub = [1, 2, 4] ;
Sub = [1, 3, 4] ;
Sub = [2, 3, 4] ;
false.

您甚至可以在示例查询中切换两个子目标的顺序,但这可能是编写它的更好方法。

然而,第二个参数必须基础;如果不是:

?- subset_set([A,B], [a,B]), B = a.
A = B, B = a ; Not a real set, is it?
false.