List_subset_of_list 有选择点的谓词?

List_subset_of_list predicate with choice points?

所以这是我的子集谓词:

subset([],[_|_]).
subset([X|Ts],L) :-
    member(X,L),
    subset(Ts,L).

这是我遇到的问题:

?- subset([1,2], [3,2,1]).
true ;
false.

为什么 prolog 已经找到了解决方案却还要继续寻找?我试着在第一个子句前面加了一个删减,但是没有用!

编辑:格式错误导致第一个子句没有出现。

因为如果有不止一种解决方案会发生什么:

member(4, [4, 0, 0, 4, 4])
           ^        ^  ^

前 4 个答案为真,如果您要求它重试,则接下来的 4 个答案为真,依此类推直到结束。在你的情况下,没有更多的解决方案,当被要求更多时它 returns false。

这似乎是 member/2 的行为。阅读那里的评论包括:

"deterministic" means that the predicate succeeds exactly once (but may leave a choicepoint that, however, yields no further solution on backtracking) whereas

"well-behaved deterministic" means that the predicate succeeds exactly once and leaves no choicepoint.

还有一个建议:

Use memberchk/2 if you are hunting for efficiency and a single solution is sufficient (but watch out for unexpected failures with memberchk/2)

在您的代码中将 memberchk 换成 member,它会在不留下选择点的情况下回答。

一种防止多个解决方案的通用方法是:

subset(Elems, Lst) :-
    subset_(Elems, Lst),
    % Don't want multiple solutions
    !.

subset_([], [_|_]).
subset_([H|T], L) :-
    selectchk(H, L, L0),
    subset_(T, L0).

此外,您可能想使用 selectchk(如上所述)而不是 member 来生成:

?- subset([1, 2, 2], [3, 2, 1]).
false.  % Correct because 2 only occurs once in the 2nd list, rather than a minimum of twice