Pure Prolog programs that distinguish between the equality and inequality of terms in a clean manner suffer from execution inefficiencies ; even when all terms of relevance
Here's an even shorter logically-pure implementation of occurrences/3
.
We build it upon the meta-predicate tfilter/3, the
reified term equality predicate (=)/3, and the coroutine allEqual_to__lazy/2
(defined in my previous answer to this question):
occurrences(E,Xs,Es) :-
allEqual_to__lazy(Es,E),
tfilter(=(E),Xs,Es).
Done! To ease the comparison, we re-run exactly the same queries I used in my previous answer:
?- Fs = [1,2], occurrences(E,Es,Fs).
false.
?- occurrences(E,[1,2,3,1,2,3,1],Fs).
Fs = [1,1,1], E=1 ;
Fs = [2,2], E=2 ;
Fs = [3,3], E=3 ;
Fs = [], dif(E,1), dif(E,2), dif(E,3).
?- occurrences(1,[1,2,3,1,2,3,1],Fs).
Fs = [1,1,1].
?- Es = [E1,E2], occurrences(E,Es,Fs).
Es = [E, E ], Fs = [E,E], E1=E , E2=E ;
Es = [E, E2], Fs = [E], E1=E , dif(E2,E) ;
Es = [E1,E ], Fs = [E], dif(E1,E), E2=E ;
Es = [E1,E2], Fs = [], dif(E1,E), dif(E2,E).
?- occurrences(1,[E1,1,2,1,E2],Fs).
E1=1 , E2=1 , Fs = [1,1,1,1] ;
E1=1 , dif(E2,1), Fs = [1,1,1] ;
dif(E1,1), E2=1 , Fs = [1,1,1] ;
dif(E1,1), dif(E2,1), Fs = [1,1].
?- occurrences(1,L,[1,2]).
false.
?- L = [_|_],occurrences(1,L,[1,2]).
false.
?- L = [X|X],occurrences(1,L,[1,2]).
false.
?- L = [L|L],occurrences(1,L,[1,2]).
false.
At last, the most general query:
?- occurrences(E,Es,Fs).
Es = Fs, Fs = [] ;
Es = Fs, Fs = [E] ;
Es = Fs, Fs = [E,E] ;
Es = Fs, Fs = [E,E,E] % ... and so on ad infinitum ...
We get the same answers.