Я интерпретировал предполагаемую семантику предиката two_members/3
несколько иначе:
- Мы хотим извлечь элементов
X
и Y
из данного списка Ls
.
Ls
должен иметь как минимум два элемента списка, чтобы two_members/3
мог добиться успеха.
X
и Y
могут быть равны, если Ls
содержит X
хотя бы дважды.
На основе встроенных предикатов select/3
и member/2
мы определяем:
two_members(X,Y,Ls) :-
select(X,Ls,Ls0),
member(Y,Ls0).
Давайте запустим несколько запросов! Сначала запрос ОП предложил в вопросе:
?- two_members(X,Y,[a,b,c,d]).
X = a, Y = b ;
X = a, Y = c ;
X = a, Y = d ;
X = b, Y = a ;
X = b, Y = c ;
X = b, Y = d ;
X = c, Y = a ;
X = c, Y = b ;
X = c, Y = d ;
X = d, Y = a ;
X = d, Y = b ;
X = d, Y = c ;
false.
Что если какой-то предмет встречается более одного раза в Ls
?
?- two_members(X,Y,[a,a,b]).
X = a, Y = a ;
X = a, Y = b ;
X = a, Y = a ; % redundant answer
X = a, Y = b ; % redundant answer
X = b, Y = a ;
X = b, Y = a ; % redundant answer
false.
А как насчет вышеуказанных избыточных ответов? Откуда они берутся и можем ли мы их избежать?
Избыточные ответы приходят от select/3
и member/3
:
?- select(X,[a,a,b],Xs).
X = a, Xs = [a,b] ;
X = a, Xs = [a,b] ; % redundant answer
X = b, Xs = [a,a] ;
false.
?- member(X,[a,a,b]).
X = a ;
X = a ; % redundant answer
X = b.
Чтобы избавиться от этих избыточностей, мы можем использовать
memberd/2
вместо member/2
и
selectd/3
вместо select/3
. Давайте снова запустим вышеуказанные запросы:
?- select<b>d</b>(X,[a,a,b],Xs).
X = a, Xs = [a,b] ;
X = b, Xs = [a,a] ;
false.
?- member<b>d</b>(X,[a,a,b]).
X = a ;
X = b ;
false.
Избыточные ответы исчезли! Итак, давайте переопределим two_members/3
соответственно:
two_members(X,Y,Ls) :-
select<b>d</b>(X,Ls,Ls0),
member<b>d</b>(Y,Ls0).
Приведенный выше запрос two_members/3
, который использовал для , дает следующие избыточные ответы:
?- two_members(X,Y,[a,a,b]).
X = a, Y = a ;
X = a, Y = b ;
X = b, Y = a ;
false. % all of above redundant answers have gone!