Вот решение с использованием 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
grab([],Xs,Ys)
должно быть истинным, с другой стороны, вы заявляете, что вам нужно посмотреть на первый элемент в списке, что подразумевает, чтоgrab/3
будет успешным только со списком, содержащим хотя бы один элемент. - person false   schedule 08.06.2014