如何正确地用prolog写出暗示?

时间:2016-11-21 14:34:40

标签: prolog

我正在尝试编写一个谓词,当且仅当列表D包含列表A中的元素时,这将是真的,这些元素在列表A中的次数。例如 -

  

D [1,5,5,3]; A [4,6,1,0,5,3,5]

将是真的

  

D [1,5,5,3]; A [4,6,1,0,5,3,5,5]

将是假的,因为D只有5次,但A有5次3次。我试图这样做有意义。我的代码片段是休闲 -

sub_third(_, []) :-
    true.

sub_third(D, [H|T]) :-
    member(H, D) -> 
        select(H, D, D_new), sub_third(D_new, T) ; 
        false.

third(_, [], _) :-
    true.

third(D, [H|T], A) :-   
    (\+member(H, D) -> 
        select(H, A, A_new), third(D, T, A_new) ; 
        third(D, T, A)) -> 
            (sub_third(D, A_new);
            false).

基本上我在这里做的是通过第三个'谓词列表D和两次列表A.第一个实现我试图删除第二个A列表中的所有元素,这些元素在第一个A列表中找不到(如果H元素存在于列表D中,则用下一个T递归调用该调用元素并且不做任何更改,但是如果在D列表中找不到H,则将其从第二个A列表中删除并再次调用递归,但是使用修改后的A列表)。当没有更多T元素时,列表A应该只包含与列表D相同的元素,然后使用sub_third谓词找出,如果所有元素都是相同的计数。 Sub_third工作正常,所以我认为错误应该在影响范围内,因为我不熟悉它们。

P.S。成员函数检查元素是否是列表的成员,并且select函数接受元素和列表,然后从第一个列表中删除给定元素的第三个列表。 (这就是我在这里使用它的方式)

1 个答案:

答案 0 :(得分:1)

您应该尝试为谓词找到更清晰的名称。即使你知道sub_third应该是什么意思,我们也不知道。这使得理解和调整代码变得更加困难。

您使用select/3的基本想法很好,但您没有正确分解问题。首先尝试计算列表之间的差异,然后检查它不包含任何不需要的元素的额外属性:

% list_subtract(Xs, Ys, Zs) is true if Zs is a list obtained by removing one
% occurrence of each element of Ys from Zs. False if there are elements in
% Ys that have no corresponding occurrence in Xs.
list_subtract(Xs, [], Xs).
list_subtract(Xs, [Y|Ys], Zs) :-
    select(Y, Xs, Xs1),
    list_subtract(Xs1, Ys, Zs).

% tests
:- list_subtract([4, 6, 1, 0, 5, 3, 5], [1, 5, 5, 3], Zs), Zs = [4, 6, 0].
:- list_subtract([4, 6, 1, 0, 5, 3, 5, 5], [1, 5, 5, 3], Zs), Zs = [4, 6, 0, 5].

% list_subtract_without_rest(Xs, Ys, Zs) is true if Ys can be subtracted
% from Xs in the sense of the list_subtract/3 predicate, and the remaining
% difference Zs does not contain any elements of Ys.
list_subtract_without_rest(Xs, Ys, Zs) :-
    list_subtract(Xs, Ys, Zs),
    \+ (member(Z, Zs), member(Z, Ys)).

% tests
:- list_subtract_without_rest([4, 6, 1, 0, 5, 3, 5], [1, 5, 5, 3], _).
:- \+ list_subtract_without_rest([4, 6, 1, 0, 5, 3, 5, 5], [1, 5, 5, 3], _).