Prolog 检查一个集合是否是另一个集合的子集合的谓词检查正确,但只生成空集合

Prolog 检查一个集合是否是另一个集合的子集合的谓词检查正确,但只生成空集合,prolog,Prolog,我对Prolog非常陌生,我正在尝试实现一个函数来生成给定集合的所有子部分(这似乎是一个经典练习) 我把这个编码了: %evaluate if the list PH|PT is part of the list EH|ET partof([],[_|_]). partof([PH|PT],[EH|ET]):- \+(member(PH,PT)),%no duplicated element to limit results member(PH,[EH|ET]),%check i

我对Prolog非常陌生,我正在尝试实现一个函数来生成给定集合的所有子部分(这似乎是一个经典练习)

我把这个编码了:

%evaluate if the list PH|PT is part of the list EH|ET
partof([],[_|_]).
partof([PH|PT],[EH|ET]):-
    \+(member(PH,PT)),%no duplicated element to limit results
    member(PH,[EH|ET]),%check if head element is in E
    partof(PT,[EH|ET]).%check the rest of the list
当输入“具体”变量时,我的谓词正确指示第一个列表是否是第二个列表的子部分:

?- partof([b,c],[a,b,c]).
true .

?- partof([a,c],[a,b,c]).
true .

?- partof([a,a,c],[a,b,c]).
false.

?- partof([a,u,c],[a,b,c]).
false.
我的问题是,当使用unlinked变量输入时,它只返回无效列表,而不是所有子部分:

%Expecting [a],[a,b],[a,b,c],[b],[b,c]... etc
9 ?- partof(P,[a,b,c]). 
P = [] ;
false.
我非常希望不仅能对prolog谓词进行更正,而且能对prolog谓词在输入未链接变量时的工作方式进行解释,因为我假设prolog的本质意味着“检查器”等同于“生成器”


提前谢谢

您的
partof/2
规则的第一部分成功地给出了答案
p=[]
,第二部分对您来说失败了。让我们来看看为什么:

partof([PH|PT],[EH|ET]):-
    \+(member(PH,PT)),%no duplicated element to limit results
    member(PH,[EH|ET]),%check if head element is in E
    partof(PT,[EH|ET]).%check the rest of the list
如果你追踪它,你会看到当你到达行
\+(成员(PH,PT)
,如果
[PH,PT]
是一个变量,那么
PT
仍然是一个变量。因此
成员(PH,PT)
成功地统一
PT=[PH,PT]
。Prolog的下一个检查是
\+
,并被视为
成员(PH,PT)
为true,
\+true
解析为false并失败

这就是逻辑上的“不”和Prolog的
\+
之间的区别。
\+
必然带有一些程序意义,更类似于“如果你现在不能证明这个目标,那么就失败。Prolog的程序意义可能会让你在从检查器到生成器的过程中绊倒。”

在测试之前知道你需要具备这一基础,这意味着你可以重新安排目标,以获得(几乎)期望的结果:

partof([],[_|_]).
partof([PH|PT],[EH|ET]):-
    partof(PT,[EH|ET]),
    member(PH,[EH|ET]),%check if head element is in E
    \+ (member(PH,PT)).%no duplicated element to limit results
现在,这将找到正确答案,但它也将无法终止,因为您对生成的子集列表的长度没有任何限制。您可以通过将生成(如果参数为零,则为保护)放入一个谓词,然后使用另一个谓词将生成的列表放入一个合适的集合来实现这一点:

partof(Sub, Set) :-
    length(Set, L),  % measure length if Set is a list
    length(Sub, SL),  % generate list of vars of increasing length if Sub is a var
    ( SL > L, !, fail  % We've generated a Sub longer than Set, quit the search
    ; SL =< L,  % We've got an appropriate length Sub
    partof_(Set, Sub)  % Hand off to helper predicate
    ).

% This is practically the same as the re-ordering of yours
% But with the generative aspect removed. It'll unify any variables
% in the arguments subject to the constraints placed on them.
partof_(Set, []).
partof_(Set, [H|T]) :-
    partof_(Set, T),
    member(H, Set), 
    \+ member(H, T).
此外,没有检查
Set
是否实际上是一个集合,尽管如果输入了不适当的信息,例如:

?- partof(Sub, [a, b, c, a]).
如果您查询以下内容,将得到奇怪的结果:

?- partof([a, c], [a, B, c]).
B = a ;
true ;
B = c.

为了避免这些问题,您只想在
未接地时进行切割,如果它接地且
SL>L
则在没有切割的情况下失败,以无限次生成子可作为其子集的集合。然后结束
部分/2
,并使用防护装置检查
集合
实际上是在所有集合之前设置的由于谓词成功了。

非常感谢,我真的不明白\+的意思,尽管每个序言文档都警告过我
?- partof([a, c], [a, B, c]).
B = a ;
true ;
B = c.