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]).