谓词选择列表中的元素两次而不是更多

whd*_*whd 7 prolog

我试图写一个谓词twice(El,L)将返回true.El是名单正是两次.这是我有的:

twice(El,L) :- select(El,L,L1), member(El,L1), \+ twice(El,L1).
Run Code Online (Sandbox Code Playgroud)

它的效果很好twice(2,[1,2,2,3,4]) 但是twice(X,[1,1,2,2,3,3])它为每个数字加倍X = 1 ; X = 1 ; X = 2...我怎么能避免这种情况而不使用任何累加器呢?

fal*_*lse 5

您想要描述一系列元素.为此,Prolog中有一种称为Definite Clause Grammars的特殊形式.在使用形式主义之前,让我们试着弄清楚E恰好发生两次的序列如何:

  1. 首先,是一个可能没有的空序列 E
  2. 然后,有一次发生 E
  3. 然后再一个可能空的序列没有 E
  4. 然后,有第二次出现 E
  5. 然后再一个可能空的序列没有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).
Run Code Online (Sandbox Code Playgroud)

或者,通过使用所有// 1并避免辅助定义更紧凑:

twice(E, L) :-
    phrase(( all(dif(E)), [E], all(dif(E)), [E], all(dif(E)) ), L).
Run Code Online (Sandbox Code Playgroud)

这些定义基本上只有一个缺点:在当前系统中,它们没有得到最佳实现.如果您想了解更多,请参阅内容.