Фактическая причина получения более одного ответа - цель member(A,As)
.Он выдает несколько ответов для дубликатов в As
.
?- member(a, [a,a]).
true
; true.
. Есть несколько выходов.
memberchk/2
или once/1
memberchk/2
определяетсяas
memberchk(X, Xs) :-
once(member(X, Xs)).
Это удаляет альтернативные ответы.Но тогда это может удалить и другие действительные решения тоже.Подумайте:
?- memberchk(X, [a,b]), b = X.
false.
?- b = X, memberchk(X, [a,b]), b = X.
b = X.
Так что memberchk/2
чувствителен к точному воплощению, что делает его очень хрупким, нечистым предикатом.
Но у него есть один хороший момент: он придерживается только одногоответ за
?- memberchk(a, [a,a]).
true.
Итак, что было бы идеально, так это определение, которое является одновременно чистым и соответствует первому элементу.Введите
memberd/2
memberd(X, [X|_Ys]).
memberd(X, [Y|Ys]) :-
dif(X, Y),
memberd(X, Ys).
В этом определении рекурсивное правило имеет значение только в том случае, если элемент списка отличается.Таким образом, это правило никогда не будет применяться к memberd(a, [a,a,a])
.
Еще одна проблема в вашем определении - not(member(A,B))
, которая ведет себя только так, как задумано, если A
и B
достаточно созданы.Ваше определение не подходит для: duplicate([a,X],[a,b]).
, хотя есть решение: X = b
.
Вместо этого замените его на non_member/2
.
В качестве альтернативы, если вызаинтересованы в наиболее эффективном решении, рассмотрим library(reif)
для SICStus и SWI , что приводит к:
list_nub([], []).
list_nub([X|Xs], Ys0) :-
if_(memberd_t(X, Xs), Ys0 = Ys1, Ys0 = [X|Ys1]),
list_nub(Xs, Ys1).