适当的子集 - Prolog

Shr*_*p91 6 prolog subset

我正在尝试编写一个程序,它将两个列表作为输入并检查正确的子集.我开始时:

proper([A],[]).
proper([],[A]).
proper([A|T1],[A|T2]) :- proper(T1,T2).
Run Code Online (Sandbox Code Playgroud)

这完全适用于完全相同顺序的输入.例如:

?- proper([a,b,c],[a,b,c,d]).
Yes
Run Code Online (Sandbox Code Playgroud)

但不适用于以下输入:

?- proper([a,b,c],[b,d,a,c]).
No
Run Code Online (Sandbox Code Playgroud)

浏览网站后,我发现了之前提出的问题:

prolog中的子集功能

这导致我修改我的代码:

proper([A],[]).
proper([],[A]).
proper([A|T1],[A|T2) :- member(A,T2), proper(T1,T2).
proper([H1|T1], [H2|T2]) :- \+ member(H1, T2).
Run Code Online (Sandbox Code Playgroud)

这适用于子集,但不适用于正确的子集.我认为我的问题来自于我对正确/ 4的第二个句子如何工作的理解.非常感谢任何和所有的帮助.

编辑:

意识到我是试图确定是否第一列表是第二次的真子集第二个是第一个的子集.清理代码更精确.

proper([],_).
proper([A|T1],[A|T2) :- member(A,T2), proper(T1,T2).
proper([H1|T1], [H2|T2]) :- \+ member(H1, T2).
Run Code Online (Sandbox Code Playgroud)

Sho*_*hon 2

如果我理解正确,您上次尝试中的前两个声明意味着,具有1 个元素的列表是空列表 (false) 的真子集,并且空列表是具有一个元素的列表的真子集(真的); 第一个应该是有问题的,因为proper([1], [])也会成功proper([],[1]),但真子集关系是不对称的。

我相信您第二次尝试没有过滤掉相同子集的原因是您没有声明要求 A 小于 B。

以下是我提出的一些可能的解决方案。我使用了smaller_set/2几次以提高清晰度和简洁性。

smaller_set(A, B) :-
    length(A, LA),
    length(B, LB),
    LA < LB.
Run Code Online (Sandbox Code Playgroud)

def_proper_subset/2尝试捕获子集的标准定义。

def_proper_subset(A, B) :-
    smaller_set(A, B),                    % if A < B then there's some _e in B that isn't in A.
    forall(member(_e, A), member(_e, B)).
Run Code Online (Sandbox Code Playgroud)

一个递归定义的示例,基于删除 A 和 B 的每个匹配元素。只有当 A 用完 B 之前的元素时,它才能成功,从而确保 A < B。

rec_proper_subset1([], [_|_]).
rec_proper_subset1([_e|A], B) :-
    select(_e, B, C),            % C is B with _e removed. Only true if _e is in B.
    rec_proper_subset1(A, C).
Run Code Online (Sandbox Code Playgroud)

一旦主谓词已经确保 A < B,此谓词就使用辅助谓词来检查成员资格。

rec_proper_subset2(A, B) :-
    smaller_set(A, B),
    rec_proper_subset2_(A, B).

rec_proper_subset2_([], _).
rec_proper_subset2_([_e|A], B) :-
    member(_e, B),
    rec_proper_subset2_(A, B).
Run Code Online (Sandbox Code Playgroud)

编辑:

  • 如果您想确保列表没有任何重复元素,则需要使用list_to_set/2、或类似的内容。sort/2但这些类型的解决方案也适用于查找子列表。
  • 我认为def_proper_subset/2这是一种蹩脚的解决方案,因为它只能检查 A 是 B 的子集,但无法在 A 中生成 B 的子集。另外两个能够思考。

(我搞砸了,忘记包含 的基本定义rec_proper_subset2/2,但我现在已经修复了它)。