在Prolog中创建带圆圈的列表

时间:2014-06-10 13:53:20

标签: list prolog failure-slice

我正在尝试在Prolog中创建此功能:

% 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 个答案:

答案 0 :(得分:3)

你的谓词需要另一个参数。一种选择是使用列表中的元素,直到您留下[]

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

答案 1 :(得分: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).

所以这基本上是你的程序,有一个额外的参数用于限制递归的数量。以这种方式限制递归通常用于实现所谓的迭代深化算法。然而,在这种情况下,我们只有一个深度限制。不需要额外的迭代。

答案 2 :(得分:2)

这是一个更简单的解决方案,具有更弱的终止属性。另一方面,你说第一个参数是"完全实例化"。你能否迅速地为一个论证做一个测试,以便完全实例化#34 ;?我假设没有。正是由于这个原因,这种假设导致了很多错误。首先,程序员只是假设参数将被"完全实例化"后来他们忘记了他们的假设...

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

此版本现在不再针对circleList3(Xs, [])终止。要了解为何如此,我将使用,即我将在程序中添加 false 。如果剩下的部分仍未终止,则可见部分存在一个问题。

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

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

此故障片不会终止,因为第一个目标是使用3个未实例化的参数调用的。终止的唯一帮助是Ys,但没有人对此感兴趣!

我们现在可以交换两个目标append/3,使这个片段终止,但是,其他查询不会终止......