Пролог: в списке, находящем элемент после заданного элемента

Недавно я начал программировать в Prolog, и в настоящее время я пытаюсь создать правила, которые найдут элемент после определенного элемента в списке. Например, я хочу find(2,X,[1,2,3,4]). привести к 3.

Моя попытка:

find(X,Y,[X,Y|Tail]):-
   !.
find(X,Y,[_|Tail]):-
   find(X,Y,Tail).

Ответ 1

Используйте if_/3 и (=)/3 (a.k.a. equal_truth/3), как определено @false в этом ответе!

Итак, вот новый, логически чистый 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(a,X,[a,a,b]).
X = a.                      % succeeds deterministically
?- find(a,X,[a,Y,b]).
X = Y.                      % succeeds deterministically
?- find(a,b,[a,a,b]).
false.                      % fails

?- find(a,X,[a,a,b,c]).
X = a.                      % succeeds deterministically
?- find(b,X,[a,a,b,c]).
X = c.                      % succeeds deterministically

Теперь что-то a little более общее:

?- find(X,Y,[a,a,b,c]).
X = a, Y = a ;
X = b, Y = c ;
false.

Как насчет наиболее общего запроса? Поскольку код чистый, мы получаем логически звук:

?- 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) ...

Редактировать 2015-05-06

Здесь более краткий вариант, который невообразимо называется findB/3:

findB(E0,E1,[X0,X1|Xs]) :-
   if_(X0=E0, X1=E1, findB(E0,E1,[X1|Xs])).

Подобно find/3, findB/3 эффективен в том смысле, что не оставляет ненужных точек выбора позади, но имеет более высокую память.

findC/3 пытается уменьшить использование памяти, подняв общее выражение [X1|Xs]:

findC(E0,E1,[X0|XXs]) :-
   XXs = [X1|_],
   if_(X0=E0, X1=E1, findC(E0,E1,XXs)).

Ответ 2

Здесь версия без разреза:

find(X,Y,[X,Y|_]).
find(X,Y,[Z|Tail]) :- 
    X\=Z, find(X,Y,Tail).

Ответ 3

Вот чистая версия:

find(X,Y, [X,Y|_]).
find(X,Y, [X0,Y0|Xs]) :-
   dif(X+X0,Y+Y0),
   find(X,Y, [Y0|Xs]).

Я бы предпочел иметь детерминированную версию, а также чистую версию DCG будет классно!