Если вы измените определение delete_first/3
...
delete_first([X|Y], X, Y).
delete_first([X|Y], E, [X|L]) :-
X \= E,
delete_first(Y, E, L).
... вам больше не нужно использовать member/2
...
compress([], []).
compress([friends(P,C)|R], S) :-
delete_first(R, friends(P,X), E),
N is C + X,
compress([friends(P,N)|E], S).
compress([friends(P,C)|R], [friends(P,C)|S]) :-
\+ delete_first(R, friends(P,_), _),
compress(R, S).
... и дубликаты ответов в вашем примере запроса исчезают:
?- compress([friends(mike,4), friends(joe,3),
friends(mike,1), friends(mike,2),
friends(joe,4), friends(mike,3)], Xs).
Xs = [friends(mike, 10), friends(joe, 7)] ;
false.
Однако при использовании без достаточного количества экземпляров compress/2
может дать ложный ответ (ы):
?- compress([friends(mike,4), friends(joe,3), friends(<b>Any</b>,10)], Xs).
Any = mike, Xs = [friends(mike,14),friends(joe,3)] ;
false. % what?! how about Any = joe?
Чтобы защититься от этого, мы можем использовать iwhen/2
примерно так:
list_compressed(Es, Xs) :-
iwhen(ground(Es), compress(Es,Xs)).
Примеры запросов:
?- list_compressed([friends(mike,4), friends(joe,3), friends(Any,10)], Xs).
<b>ERROR: Arguments are not sufficiently instantiated</b>
?- list_compressed([friends(mike,4), friends(joe,3),
friends(mike,1), friends(mike,2),
friends(joe,4), friends(mike,3)], Xs).
Xs = [friends(mike, 10), friends(joe, 7)] ;
false.