首页 > 解决方案 > 我已经定义了多个似乎共享一个共同形式的谓词

问题描述

所有这些谓词的定义方式几乎相同。基本情况是为空列表定义的。对于非空列表,当某个谓词成立时,我们在子句的头部进行统一,但如果该谓词不成立,则不进行统一。这些谓词看起来太相似了,我认为这是巧合。有没有这个的名字,或者一个定义的抽象?

intersect([],_,[]).
intersect(_,[],[]).
intersect([X|Xs],Ys,[X|Acc]) :-
    member(X,Ys),
    intersect(Xs,Ys,Acc).
intersect([X|Xs],Ys,Acc) :-
    \+ member(X,Ys),
    intersect(Xs,Ys,Acc).
without_duplicates([],[]).
without_duplicates([X|Xs],[X|Acc]) :- 
    \+ member(X,Acc),
    without_duplicates(Xs,Acc).
without_duplicates([X|Xs],Acc) :-
    member(X,Acc),
    without_duplicates(Xs,Acc).
difference([],_,[]).
difference([X|Xs],Ys,[X|Acc]) :-
    \+ member(X,Ys),
    difference(Xs,Ys,Acc).
difference([X|Xs],Ys,Acc) :-
    member(X,Ys),
    difference(Xs,Ys,Acc).
delete(_,[],[]).
delete(E,[X|Xs],[X|Ans]) :-
    E \= X,
    delete(E,Xs,Ans).
delete(E,[X|Xs],Ans) :-
    E = X,
    delete(E,Xs,Ans).

标签: prolog

解决方案


“将元素保留在条件成立的列表中”有一个抽象。名称是inclide, exclude。SWI-Prolog 中有一个库供您使用或复制。您的谓词intersect/3,difference/3delete/3看起来像这样:

:- use_module(library(apply)).

intersect(L1, L2, L) :-
    include(member_in(L1), L2, L).

difference(L1, L2, L) :-
    exclude(member_in(L2), L1, L).

member_in(List, Member) :-
    memberchk(Member, List).

delete(E, L1, L) :-
    exclude(=(E), L1, L).

但是请看一下 include/3 和 exclude/3 的实现,这里: https ://www.swi-prolog.org/pldoc/doc/_SWI_/library/apply.pl?show=src#include/3

同样在 SWI-Prolog 中,在另一个库中,这些谓词的版本称为intersection/3, subtract/3, delete/3

这些在精神上与您的解决方案相似。

您的下一个谓词 ,without_duplicates不能像那样用include/3or重写exclude/3。您的实现也不起作用。尝试一些简单的事情,例如:

?- without_duplicates([a,b], L).

怎么了?

但是,是的,它与其他人不一样。要正确实施它,取决于您是否需要原始订单。

如果不需要保留初始顺序,可以简单排序;这将删除重复项。像这样:

?- sort(List_with_duplicates, No_duplicates).

如果你想保持原来的顺序,你需要将累积的列表传递给递归调用。

without_duplicates([], []).
without_duplicates([H|T], [H|Result]) :-
    without_duplicates_1(T, [H], Result).

without_duplicates_1([], _, []).
without_duplicates_1([H|T], Seen0, Result) :-
    (   memberchk(H, Seen0)
    ->  Seen =    Seen0 , Result =    Result0
    ;   Seen = [H|Seen0], Result = [H|Result0]
    ),
    without_duplicates_1(T, Seen, Result0).

如果你使用 DCG,你可以摆脱一个论点:

without_duplicates([], []).
without_duplicates([H|T], [H|No_duplicates]) :-
    phrase(no_dups(T, [H]), No_duplicates).

no_dups([], _) --> [].
no_dups([H|T], Seen) -->
    { memberchk(H, Seen) },
    !,
    no_dups(T, Seen).
no_dups([H|T], Seen) -->
    [H],
    no_dups(T, [H|Seen]).

推荐阅读