prolog - 我已经定义了多个似乎共享一个共同形式的谓词
问题描述
所有这些谓词的定义方式几乎相同。基本情况是为空列表定义的。对于非空列表,当某个谓词成立时,我们在子句的头部进行统一,但如果该谓词不成立,则不进行统一。这些谓词看起来太相似了,我认为这是巧合。有没有这个的名字,或者一个定义的抽象?
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).
解决方案
“将元素保留在条件成立的列表中”有一个抽象。名称是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 的实现,这里: https ://www.swi-prolog.org/pldoc/doc/_SWI_/library/apply.pl?show=src#include/3
同样在 SWI-Prolog 中,在另一个库中,这些谓词的版本称为intersection/3
, subtract/3
, delete/3
:
- https://www.swi-prolog.org/pldoc/doc/_SWI_/library/lists.pl?show=src#intersection/3
- https://www.swi-prolog.org/pldoc/doc/_SWI_/library/lists.pl?show=src#subtract/3
- https://www.swi-prolog.org/pldoc/doc_for?object=delete/3
这些在精神上与您的解决方案相似。
您的下一个谓词 ,without_duplicates
不能像那样用include/3
or重写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]).
推荐阅读
- python - 如何在 tkinter 画布 GUI 的一侧添加带有值的颜色条?
- java - Java XML 从节点列表中获取节点崩溃程序
- embedded - 如何读取 FreeRTOS 跟踪转储
- android-studio - 为什么 Android Studio 4.1 没有显示任何错误
- azure - 使用 Azure 容器注册表部署 CKan Docker 映像
- python - 在 Chainer 深度学习框架中加载预训练模型
- swift - 计算上下文中绘制的文本大小(核心图形)?
- html - 如何在其上方放置一个带有图像和文本的列表,彼此相邻
- python - 如何在 Tkinter python 中隐藏或删除我的按钮?
- python - 类型声明类型对象不是可下标的列表