Давайте использовать if_/3
и (=)/3
(он же equal_truth/3
), как определено @false в этот ответ !
Итак, вот новое, логическиpure find/3
:
find(E0,E1,[X|Xs]) :-
member_next_prev_list(E0,E1,X,Xs).
member_next_prev_list(E0,E1,X0,[X1|Xs]) :-
if_(X0=E0, X1=E1, member_next_prev_list(E0,E1,X1,Xs)).
Давайте запустим запросы, упомянутые OP / другими ответами / некоторыми комментариями:
?- find(<b>a</b>,<i>X</i>,[<b>a</b>,<i>a</i>,b]).
<i>X</i> = <i>a</i>. % <b>succeeds deterministically</b>
?- find(<b>a</b>,<i>X</i>,[<b>a</b>,<i>Y</i>,b]).
<i>X</i> = <i>Y</i>. % <b>succeeds deterministically</b>
?- find(<b>a</b>,<i>b</i>,[<b>a</b>,<i>a</i>,b]).
false. % <b>fails</b>
?- find(<b>a</b>,<i>X</i>,[<b>a</b>,<i>a</i>,b,c]).
<i>X</i> = <i>a</i>. % <b>succeeds deterministically</b>
?- find(<b>b</b>,<i>X</i>,[a,a,<b>b</b>,<i>c</i>]).
<i>X</i> = <i>c</i>. % <b>succeeds deterministically</b>
Теперь к чему-то немного более общий:
?- find(<b>X</b>,<i>Y</i>,[<b>a</b>,<i>a</i>,<b>b</b>,<i>c</i>]).
<b>X</b> = <b>a</b>, <i>Y</i> = <i>a</i> ;
<b>X</b> = <b>b</b>, <i>Y</i> = <i>c</i> ;
false.
А как насчет самого общего запроса ?Поскольку код pure , мы получаем логически обоснованных ответов:
?- find(X,Y,List).
List = [ X,Y|_Z] ;
List = [_A, X,Y|_Z], dif(_A,X) ;
List = [_A,_B, X,Y|_Z], dif(_A,X), dif(_B,X) ;
List = [_A,_B,_C, X,Y|_Z], dif(_A,X), dif(_B,X), dif(_C,X) ;
List = [_A,_B,_C,_D,X,Y|_Z], dif(_A,X), dif(_B,X), dif(_C,X), dif(_D,X) ...
Edit 2015-05-06
Вотболее краткий вариант, не имеющий обозначения findB/3
:
findB(E0,E1,[X0,<b>X1|Xs</b>]) :-
if_(X0=E0, X1=E1, findB(E0,E1,[<b>X1|Xs</b>])).
Подобно find/3
, findB/3
эффективен в том смысле, что не оставляет позади бесполезные точки выбора, но имеет более высокое использование памяти.
findC/3
пытается уменьшить использование памяти, поднимая общее выражение [X1|Xs]
:
findC(E0,E1,[X0|<b>XXs</b>]) :-
XXs = [X1|_],
if_(X0=E0, X1=E1, findC(E0,E1,<b>XXs</b>)).