我尝试编写一个谓词twice(El,L)
,当true.
列表中的El
时,它会返回twice(El,L) :- select(El,L,L1), member(El,L1), \+ twice(El,L1).
两次。这就是我所拥有的:
twice(2,[1,2,2,3,4])
适用于twice(X,[1,1,2,2,3,3])
但对于X = 1 ; X = 1 ; X = 2...
,它会使每个数字加倍{{1}}如果不使用任何累加器,我怎么能避免这种情况?
答案 0 :(得分:5)
您想要描述一系列元素。为此,Prolog中有一种称为Definite Clause Grammars的特殊形式。在使用形式主义之前,让我们试着弄清楚E
恰好出现两次的序列如何:
E
E
E
E
E
的空序列。现在,将其纳入DCG形式主义
twice(E, L) :-
phrase(twice_occurring(E), L). % Interface
twice_occurring(E) -->
seq_without(E), % 1.
[E], % 2.
seq_without(E), % 3.
[E], % 4.
seq_without(E). % 5.
seq_without(_E) -->
[].
seq_without(E) -->
[X],
{dif(X,E)},
seq_without(E).
或者,通过使用all//1并避免辅助定义更紧凑:
twice(E, L) :-
phrase(( all(dif(E)), [E], all(dif(E)), [E], all(dif(E)) ), L).
这些定义基本上只有一个缺点:在当前系统中,它们没有得到最佳实现。如果您想了解更多信息,请参阅this。
答案 1 :(得分:4)
使用if_/3
和保持逻辑上纯粹且高效
(=)/3
来自@false。它是这样的:
list_member1x([X|Xs],E) :-
if_(X=E, maplist(dif(E),Xs), list_member1x(Xs,E)).
list_member2x([X|Xs],E) :-
if_(X=E, list_member1x(Xs,E), list_member2x(Xs,E)).
twice(E,Xs) :-
list_member2x(Xs,E).
那就是它。让我们进行一些查询!
?- twice(E,[1,2,3,4,5,2,3,4]).
E = 2 ;
E = 3 ;
E = 4 ;
false.
现在更普遍一些:
?- twice(X,[A,B,C,D]).
A=X , B=X , dif(C,X), dif(D,X) ;
A=X , dif(B,X), C=X , dif(D,X) ;
A=X , dif(B,X), dif(C,X), D=X ;
dif(A,X), B=X , C=X , dif(D,X) ;
dif(A,X), B=X , dif(C,X), D=X ;
dif(A,X), dif(B,X), C=X , D=X ;
false.
以下是OP提供的查询:
?- twice(2,[1,2,2,3,4]).
true.
?- twice(E,[1,1,2,2,3,3]).
E = 1 ;
E = 2 ;
E = 3 ;
false.
作为替代方案,请将meta-predicate tcount/3
与(=)/3
结合使用,如下所示:
twice(E,Xs) :- tcount(=(E),Xs,2).
答案 2 :(得分:2)
尝试:
twice(E,L) :-
append(B1,[E|A1],L),
\+ member(E,B1),
append(B2,[E|A2],A1),
\+ member(E,B2),
\+ member(E,A2).
<强>附录强>
如果数字列表可以(部分)未绑定,则以下变体解决了问题。它使用“dif”而不是“\ =”,“+”。此外,它是一些优化(“附加”和“成员”已加入一个“appendchk”):
appendchk(L,L).
appendchk([E|Q2],[H|R]) :-
dif(H,E),
appendchk([E|Q2],R).
notmember(_,[]).
notmember(X,[H|Q]) :-
dif(X,H),
notmember(X,Q).
twice(E,L) :-
appendchk([E|A1],L),
appendchk([E|A2],A1),
notmember(E,A2).
示例:
twice(1,[1,2,3,4,2,3,2]).
false
twice(2,[1,2,3,4,2,3,2]).
false
twice(3,[1,2,3,4,2,3,2]).
true
twice(X,[1,2,3,4,2,3,2]).
X = 3
false
twice(X,[A,B]).
A = B, B = X
twice(X,[A,B,C]).
A = B, B = X,
dif(X, C)
A = C, C = X,
dif(B, X)
B = C, C = X,
dif(A, X)
答案 3 :(得分:1)
以下是我们如何声明礼貌图书馆(aggregate)所需的约束条件:
twice(El, L) :-
aggregate(count, P^nth1(P,L,El), 2).
列表&#39;元素仅限于整数,library(clpfd) reification hint提供另一种解决方案:
twice(El, L) :- vs_n_num(L,El,2).
% aggregate(count, P^nth1(P,L,El), 2).