В качестве альтернативы, поскольку ваш предикат описывает отношение между двумя списками и элементом сводки, вы можете использовать DCG для этой задачи:
list_pivot_sublist(L,P,S) :-
phrase(sublist_till(L,P),S). % the sublist up to the pivot element
% is described by the DCG sublist_till//2
sublist_till([P|_],P) --> % if the head of the list is P
[P]. % it's the last element in the sublist
sublist_till([X|Xs],P) --> % if the head of the list is any element X
[X], % X is in the sublist and
sublist_till(Xs,P). % the same goes for the tail and P
Теперь посмотрим на некоторые запросы:
Что такое подсписок [1,2,3,4,5] до элемента 3?
?- list_pivot_sublist([1,2,3,4,5],3,S).
S = [1, 2, 3] ;
false.
Какие пары sublist-pivot существуют для [1,2,3,4,5]?
?- list_pivot_sublist([1,2,3,4,5],P,S).
P = 1,
S = [1] ;
P = 2,
S = [1, 2] ;
P = 3,
S = [1, 2, 3] ;
P = 4,
S = [1, 2, 3, 4] ;
P = 5,
S = [1, 2, 3, 4, 5] ;
false.
Как может выглядеть исходный список и подходящий элемент поворота для подсписка [1,2,3]?
?- list_pivot_sublist(L,P,[1,2,3]).
L = [1, 2, 3|_G4751],
P = 3 ;
false.
Или самый общий запрос: Какие есть соответствующие списки, сводные элементы и подсписки?
?- list_pivot_sublist(L,P,S).
L = [P|_G4739],
S = [P] ;
L = [_G4738, P|_G4745],
S = [_G4738, P] ;
L = [_G4738, _G4744, P|_G4751],
S = [_G4738, _G4744, P] ;
L = [_G4738, _G4744, _G4750, P|_G4757],
S = [_G4738, _G4744, _G4750, P] ;
.
.
.
Это те же ответы, которые вы получаете с @ gusbro-версиями bla/3
, за исключением этого запроса ...
?- bla(L,P,[1,2,3]).
L = [1, 2, 3|_G4739],
P = 3 ;
ERROR: Out of global stack
... который зацикливается на первой версии (с двумя append/3
в качестве целей) после предоставления единственного ответа. Причина этого в том, что первая цель дает бесконечное количество кандидатов на решение ...
?- append(NL1, [Ele|_], L).
NL1 = [],
L = [Ele|_G900] ;
NL1 = [_G1000],
L = [_G1000, Ele|_G900] ;
NL1 = [_G1000, _G1006], % this candidate leads to
L = [_G1000, _G1006, Ele|_G900] ; % the only solution
NL1 = [_G1000, _G1006, _G1012],
L = [_G1000, _G1006, _G1012, Ele|_G900] ;
.
.
.
... все из них терпят неудачу, кроме помеченного в запросе выше:
?- append(NL1, [Ele|_], L), append(NL1, [Ele], [1,2,3]).
NL1 = [1, 2], % corresponding answer
Ele = 3, % to the third candidate
L = [1, 2, 3|_G4641] ; % above
ERROR: Out of global stack
Следовательно, версия без append/3
явно предпочтительнее. Со ссылкой на комментарий @lurker, я также хотел бы отметить, что с этими версиями вы получите несколько ответов, если элемент pivot встречается в списке более одного раза:
?- list_pivot_sublist([1,2,3,4,5,3],3,S).
S = [1, 2, 3] ;
S = [1, 2, 3, 4, 5, 3] ;
Если вы хотите получить только первый подсписок, вы можете изменить DCG-версию, добавив ограничение X
, отличающееся от P
, которое препятствует дальнейшим рекурсиям Prolog после первого успеха:
sublist_till([P|_],P) -->
[P].
sublist_till([X|Xs],P) -->
{dif(X,P)}, % <- new constraint
[X],
sublist_till(Xs,P).
Теперь приведенный выше запрос дает только один ответ:
?- list_pivot_sublist([1,2,3,4,5,3],3,S).
S = [1, 2, 3] ;
false.
Самый общий запрос также немного отличается, поскольку теперь он распространяет ограничения dif/2
вплоть до ответа:
?- list_pivot_sublist(L,P,S).
L = [P|_G4739],
S = [P] ;
L = [_G4886, P|_G4890],
S = [_G4886, P],
dif(_G4886, P) ;
L = [_G4942, _G4945, P|_G4949],
S = [_G4942, _G4945, P],
dif(_G4942, P),
dif(_G4945, P) ;
.
.
.
Вы можете изменить вторую версию @ gusbro таким же образом, добавив такое же ограничение к рекурсивному правилу:
bla([Ele|_], Ele, [Ele]).
bla([E|L], Ele, [E|NL]):-
dif(E,Ele), % <- new constraint
bla(L, Ele, NL).