Проблема с разделением Пролога на два списка

У меня есть задание на прологе.

Мне нужно посмотреть на первый элемент в списке, посмотреть, совпадают ли его следующие элементы, пока они не совпадают, и разделить списки на первый элемент и его дубликаты. например, если бы мой список был a,a,a,b,c, он сначала разделил бы его на: a,a,a. второй: б, в.

Мое текущее решение работает, за исключением того, что окончательный соответствующий элемент попадает во второй список, а не в первый. Кажется, я не могу придумать способ, чтобы он отображался в первом списке.

grab([],[],[]).
grab([A,A|L],[A|L2],Rest) :- grab([A|L],L2,Rest).
grab([A|L],Init,[A|L2]) :- grab(L,Init,L2).

person Cyassin    schedule 07.06.2014    source источник
comment
Ваша формулировка проблемы плохо определена. С одной стороны, вы подразумеваете, что grab([],Xs,Ys) должно быть истинным, с другой стороны, вы заявляете, что вам нужно посмотреть на первый элемент в списке, что подразумевает, что grab/3 будет успешным только со списком, содержащим хотя бы один элемент.   -  person false    schedule 08.06.2014
comment
Вчера вы задали аналогичный вопрос - получили ответ - и тут же удалили свой вопрос. Обратите внимание, что таким образом вы рискуете быть заблокированным от вопросов.   -  person false    schedule 08.06.2014
comment
На другой вопрос, который я задал, был удален ответ, затем не было ответов, а затем я понял, что мой вопрос даже не имеет смысла, поэтому повторно отправил его с изменениями по сравнению с тем, что я разработал.   -  person Cyassin    schedule 09.06.2014
comment
Я ответил на него и никогда не удаляю свои ответы. Но, похоже, ваша группа удалила еще много вопросов, на которые ответили другие. Это действительно нехорошо.   -  person false    schedule 09.06.2014
comment
Я не знаю, что произошло, но когда я впервые посмотрел, был ответ, когда я перезагрузил, ответа не было. Вопрос, который я задал, в любом случае не имел смысла, ответ, который вы мне дали, был просто прямым ответом на решение, которого я не искал. Я не знаю, что вы имеете в виду о моей группе? Я не удаляю вопросы или ответы, которые я публикую? У меня здоровая репутация, которую я медленно создавал из вопросов и ответов, если вы посмотрите на мой профиль.   -  person Cyassin    schedule 11.06.2014
comment
Под группой я подразумевал тех других постеров, которые задают те же самые вопросы и также помогают прояснить ваш вопрос. См. stackoverflow.com/questions/24106515/   -  person false    schedule 11.06.2014


Ответы (4)


Когда первые два элемента различны, вам не нужна рекурсивная цель.

grab([], [], []).
grab([A,A|Rest], [A|As], L2):- !, grab([A|Rest], As, L2).
grab([A|Tail], [A], Tail).
person Tudor Berariu    schedule 07.06.2014
comment
Спасибо, это имеет смысл! - person Cyassin; 07.06.2014
comment
@Ник: grab([a],Ys, Zs). преуспевает с Ys = [a], Zs = []. - person false; 07.06.2014

grab(Xs, Ys, Zs) :-
   eqprefix(Xs, Ys, Zs).

eqprefix([],[],[]).
eqprefix([X],[],[X]).
eqprefix([X,Y|Xs], [], [X,Y|Xs]) :-
    dif(X,Y).
eqprefix([X,X|Xs], [X|Ys], Zs) :-
   eqprefix2([X|Xs], Ys, Zs).

eqprefix2([X], [X], []).
eqprefix2([X,Y|Xs], [X], [Y|Xs]) :-
    dif(X,Y).
eqprefix2([X,X|Xs], [X|Ys], Zs) :-
    eqprefix2([X|Xs], Ys, Zs).

?- eqprefix([a,a,a,b,c],Ys,Zs).
Ys = [a, a, a],
Zs = [b, c] ;
false.

?- eqprefix(Xs,[a,a,a],[b,c]).
Xs = [a, a, a, b, c] ;
false.

?- eqprefix([A,B,C,D,E],[a|Ys],[b,c]).
A = B, B = C, C = a,
D = b,
E = c,
Ys = [a, a] ;
false.

В определении, которое вы дали, вы получаете много разных ответов:

?- grab([a,a,a,b,c],Ys,Zs).
  Ys = [a, a], Zs = [a, b, c]
; Ys = [a],    Zs = [a, a, b, c]
; Ys = [a],    Zs = [a, a, b, c]
; Ys = [],     Zs = [a, a, a, b, c].
person false    schedule 07.06.2014

Вот решение с использованием dcg. Наиболее интересно здесь использование нетерминала, который не является контекстно-свободным. Я начну с попытки, которая является слишком общей:

grab_tentative(Xs, Ys, Zs) :-
   phrase((seq(Ys),seq(Zs)), Xs).

seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).

grab_tentative/3 гарантирует, что Xs состоит из Ys, связанных с Zs. Это слишком общее, но все предполагаемые решения уже включены.

?- Xs = [A,B,C], grab_tentative(Xs,Ys,Zs).
   Xs = Zs, Zs = [A, B, C], Ys = []
;  Xs = [A, B, C], Ys = [A], Zs = [B, C]
;  Xs = [A, B, C], Ys = [A, B], Zs = [C]
;  Xs = Ys, Ys = [A, B, C], Zs = []
;  false.

В первом ответе говорится, что Ys = [], но (как было уточнено @Sarah), Ys всегда должен быть непустым списком, поэтому мы можем ограничить ответы непустыми списками:

grab_tentative(Xs, Ys, Zs) :-
   Ys = [_|_],
   phrase((seq(Ys),seq(Zs)), Xs).

Ответы Xs = [A, B, C], Ys = [A, B], Zs = [C] и Xs = Ys, Ys = [A, B, C], Zs = [] оба допускают, что A и B различны. Поэтому мы должны добавить, что они одинаковы:

grab_tentative(Xs, Ys, Zs) :-
   Ys = [A|_],
   phrase((all_seq(=(A),Ys),seq(Zs)), Xs).

all_seq(_, []) --> [].
all_seq(C_1, [C|Cs]) -->
   [C],
   {call(C_1,C)},
   all_seq(C_1, Cs).

Теперь ответы уже немного лучше:

?- Xs = [A,B,C], grab_tentative(Xs,Ys,Zs).
   Xs = [A, B, C], Ys = [A], Zs = [B, C]
;  Xs = [B, B, C], A = B, Ys = [B, B], Zs = [C]
;  Xs = Ys, Ys = [C, C, C], A = B, B = C, Zs = []
;  false.

Первый ответ включает в себя, что A = B. Итак, он действительно должен содержать dif(A,B). Для этого нам нужно ввести такой контекст. Вот способ сделать это. Обратите внимание, что or_end//1 похоже на []//0, за исключением того, что оно обеспечивает некоторые дополнительные условия.

grab_final(Xs, Ys, Zs) :-
   Ys = [A|_],
   phrase((all_seq(=(A),Ys), or_end(dif(A)), seq(Zs)), Xs).

or_end(C_1) -->
  call(cond_or_end(C_1)). % interface to predicates

cond_or_end(_C_1, [], []).
cond_or_end(C_1, [E|Es], [E|Es]) :-

Теперь ответы ожидаемые:

?- Xs = [A,B,C], grab_final(Xs, Ys, Zs).
   Xs = [A, B, C], Ys = [A], Zs = [B, C], dif(A, B)
;  Xs = [B, B, C], A = B, Ys = [B, B], Zs = [C], dif(B, C)
;  Xs = Ys, Ys = [C, C, C], A = B, B = C, Zs = []
;  false.
person false    schedule 08.06.2014

Вот еще одно решение, которое учитывает то, что написала @Sarah. При таком использовании grab/3 никогда не должно быть успешным для пустого списка для первого или второго аргумента.

grab([A], [A], []).
grab([A,B|Bs], [A], [B|Bs]) :-
   dif(A,B).
grab([A,A|Xs], [A|As], Bs) :-
   grab([A|Xs], As, Bs).

?- Xs = [A,B], grab(Xs,Ys,Zs).
  Xs = [A, B], Ys = [A],    Zs = [B], dif(A, B)
; Xs = Ys,     Ys = [B, B], Zs = [],  A = B
; false.
person false    schedule 08.06.2014