Prolog 我定义了多个谓词,它们似乎共享一个共同的形式

Prolog 我定义了多个谓词,它们似乎共享一个共同的形式,prolog,Prolog,所有这些谓词的定义方式基本相同。基本情况是为空列表定义的。对于非空列表,当某个谓词成立时,我们在子句的开头统一,但如果该谓词不成立,则不统一。这些谓词看起来太相似了,我不认为这是巧合。是否有一个名称,或一个定义的抽象 intersect([],_,[]). intersect(_,[],[]). intersect([X|Xs],Ys,[X|Acc]) :- member(X,Ys), intersect(Xs,Ys,Acc). intersect([X|Xs],Ys,Acc)

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

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).
一方面,这些是Prolog的“while循环”,另一方面是数理逻辑的归纳定义(另见:,Lawrence C.Paulson,Andrew W.Smith,2001),因此在一个程序中多次发现它们并不奇怪——语法相似,略有偏差

在本例中,您只有一个二元决策——不管事情是否如此——并且您在该决策上“分支”(或者更确切地说,决定不使主体失败并继续使用所选子句)。“保护”(补充头部统一的测试),在这种情况下
成员(X,Ys)
\+成员(X,Ys)
是一个二元决策(它也是详尽的,即覆盖了可能
X
的整个空间)

其他应用程序可能需要与此处的多判决开关语句等效的语句,因此可能必须编写N>2子句,而不是2

foo(X) :-
   member(X,Set1),
    (...action...).

foo(X) :-
   member(X,Set2),
    (...action...).

foo(X) :-
   member(X,Set3),
    (...action...).

% inefficient pseudocode for the case where Set1, Set2, Set3
% do not cover the whole range of X. Such a predicate may or
% may not be necessary; the default behaviour would be "failure"
% of foo/1 if this clause does not exist:

foo(X) :-
   \+ (member(X,Set1);member(X,Set2);member(X,Set3)),
    (...action...).
注:

  • 使用
    memberchk/2
    (失败或成功一次)代替
    member/2
    (失败或成功,然后在集合的其余部分再次尝试成功),使程序在决定是否为
    成员(X,L)
    时具有确定性
  • 类似地,在子句保护后加上“cut”,告诉Prolog如果一个子句的保护成功,那么尝试其他子句是没有意义的,因为它们都会变成false:
    member(X,Ys)
  • 最后,使用术语比较
    =
    \=
    代替统一
    =
    或统一失败
    \=
    来删除/3

有一个“将元素保留在条件保持的列表中”的抽象。 名称为
inclide
exclude
。SWI Prolog中有一个库,您可以使用或复制它。谓词
intersect/3
difference/3
delete/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的实现,这里:

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

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

您的下一个谓词,
没有重复项
,不能像
include/3
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]).

我猜想您知道什么是递归,因为使用了
基本情况
。如果您不知道这称为递归,那么
recursion
就是您要寻找的词。如果您知道这是递归,那么您应该在问题中注意到这一点。您开始创建的是。如果这是你所寻求的,那么请让我知道,我会让它成为一个asnwer。
?- 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).
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]).