Создать обведенный список в прологе

Я пытаюсь создать эту функцию в Прологе:

% Signature: circleList(L1, L2)/2
% Purpose: L2 is a "circled" L1 list.
% Precondition: L1 is fully instantiated.
% Examples:
% ?- circleList([2, 3, 4, 5], X).
% X = [2, 3, 4, 5];
% X = [3, 4, 5, 2];
% X = [4, 5, 2, 3];
% X = [5, 2, 3, 4];
% false.

так что я сделал это:

circleList([],[]).
circleList(X,X).
circleList([H|T],R):- append(T,[H],S), circleList(S,R).

но вывод таков:

X = [2, 3, 4, 5] ;
X = [3, 4, 5, 2] ;
X = [4, 5, 2, 3] ;
X = [5, 2, 3, 4] ;
X = [2, 3, 4, 5] ;
X = [3, 4, 5, 2] ;
X = [4, 5, 2, 3] ;
X = [5, 2, 3, 4] ;
X = [2, 3, 4, 5] ;
X = [3, 4, 5, 2] 
and so on...

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

Что я могу сделать?

3 ответа

Вы можете просто сформулировать проблему по-другому:

rotatelist([], []).
rotatelist(Xs, Ys) :-
   Xs = [_|_],
   Ys = [_|_],
   same_length(Xs, Ys), % avoid non-termination
   Bs = [_|_],          % avoid redundant answers
   append(As,Bs,Xs),
   append(Bs,As,Ys).

same_length([], []).
same_length([_E|Es], [_F|Fs]) :-
   same_length(Es, Fs).

Но если ваша цель явно прекратить; хорошо, это может легко оказаться неправильным. На самом деле, я не вижу естественного способа, как можно использовать разрез.

Однако вы можете ограничить количество рекурсий следующим образом:

circleList2(Xs, Ys) :-
   same_length(Xs, Ys),
   circleList2(Xs, Ys, Xs).

circleList2(X,X, _).
circleList2([H|T],R, [_|L]):-
   L = [_|_],
   append(T,[H],S),
   circleList2(S,R, L).

Так что это, по сути, ваша программа с одним дополнительным аргументом, используемым для ограничения количества рекурсий. Ограничение рекурсии таким способом обычно используется для реализации так называемых итеративных алгоритмов углубления. В этом случае, однако, у нас была одна граница глубины. Никакой дополнительной итерации не было необходимости.

Вам нужен еще один аргумент для вашего предиката. Одним из вариантов является использование элементов в вашем списке, пока вы не останетесь с [],

circleList([Head|Tail],CL):-
    circleList(Tail,[Head],CL).

circleList([],L,L).
circleList([Head|Tail], Rest, CL):-
    append(Rest, [Head], NewRest),
    circleList(Tail, NewRest, CL).
circleList([Head|Tail], Rest, CL):-
    append([Head|Tail], Rest,CL).

Другой вариант, который я вижу, - это ограничение глубины до размера списка с помощью length/2,

circleList([],[]).
circleList(List,CL):-
    length(List, N),
    circleList(List,N,CL).

circleList(_,0,_):-!, fail.
circleList(List,_,List).
circleList([Head|Tail], N, CL):-
    append(Tail, [Head], NewList),
    N1 is N - 1,
    circleList(NewList, N1, CL).

Вот более простое решение с гораздо более слабыми свойствами завершения. С другой стороны, вы заявили, что первый аргумент "полностью создан". Можете ли вы быстро создать тест для аргумента, который будет "полностью создан"? Я предполагаю, что нет. И именно по этой причине такие предположения приводят к такому количеству ошибок. Сначала программисты просто предполагают, что аргумент будет "полностью создан", а позже они забывают, что они предполагали...

circleList3(Xs, Ys) :-
   append(As, Bs, Xs),
   append(Bs, As, Ys),
   ( As = [] ; As = [_|_], Bs = [_|_] ).

Эта версия больше не заканчивается для circleList3(Xs, []), Чтобы понять, почему это так, я буду использовать срез-срез, то есть добавлю false в программе. Если оставшаяся часть все еще не заканчивается, то одна проблема заключается в видимой части.

? - circleList3 (Xs, []), false.
/ * LOOPS * /

circleList3 (Xs, Ys): -
   добавить (как, Bs, Xs), ложь,
   добавить (Bs, As, Ys),
   (As = []; As = [_ | _], Bs = [_ | _]).

Этот фрагмент ошибки не заканчивается, потому что первая цель вызывается с 3 необоснованными аргументами. Единственная помощь, чтобы получить это прекращение будет Ys Но никто не заинтересован в этом!

Теперь мы могли бы обменяться двумя целями append/3 заставить этот фрагмент завершиться, но тогда другие запросы не будут прекращены...

Другие вопросы по тегам