Prolog按任意方式移动n次列表功能

时间:2015-11-29 19:16:23

标签: prolog

我必须定义一个谓词nshift / 3,它将列表移动N次。 示例:

?- nshift(3,[a,b,c,d,e,f,g,h],Shifted). 
  Shifted = [d,e,f,g,h,a,b,c]   
?-­nshift(1,[1,2,3,4,5],Shifted).   
  Shifted = [2,3,4,5,1]
?-­nshift(-2,[a,b,c,d,e,f,g,h],Shifted).    
  Shifted = [g,h,a,b,c,d,e,f]

我创建了一个代码来处理前两个例子,但我遇到了N时间为-2的最后一个例子的问题。有人可以帮助我。 我的代码:

my_shift([], []).
my_shift([H|T], L) :-
   append(T, [H], L).

nshift(0, L, L) :- !.
nshift(N, L1, L2) :-
   N1 is N-1,
   my_shift(L1, L),
   nshift(N1, L, L2).

2 个答案:

答案 0 :(得分:1)

我有这个旧代码

rotate(right, L, [T|H]) :- append(H, [T], L).
rotate(left, [H|T], L) :- append(T, [H], L).

然后,我认为你可以调整你的nshift / 3测试,如果第一个参数是< 0,类似

nshift(0, L, L) :- !.
nshift(N, L1, L2) :-
  N < 0, rotate(right, L1, L), N1 is N+1, nshift(N1, L, L2).
nshift(N, L1, L2) :-
  N > 0, rotate(left, L1, L), N1 is N-1, nshift(N1, L, L2).

答案 1 :(得分:1)

正如另一个答案中暗示的那样, shift 的类型通常称为 rotate 。带有非负N的旋转可以用很好的声明方式写成

naive_rotate(N, Xs, Ys) :-
    length(Bs, N),
    append(As, Bs, Xs),
    append(Bs, As, Ys).

虽然这有效,但人们会很快指出其终止属性很差:当你回溯到rotate/3时,即要求更多解决方案时,它不会终止。这可以通过在列表长度上添加冗余条件来解决,即

rotate(N, Xs, Ys) :-
    same_length(Xs, Ys),
    leq_length(Bs, Xs),
    length(Bs, N),
    append(As, Bs, Xs),
    append(Bs, As, Ys).

  same_length([], []).
  same_length([_|Xs], [_|Ys]) :- same_length(Xs, Ys).

  leq_length([], _).
  leq_length([_|Xs], [_|Ys]) :- leq_length(Xs, Ys).

现在可以很好地处理各种查询模式,例如

?- rotate(2, [a,b,c,d,e], Ys).   % gives Ys = [d,e,a,b,c]
?- rotate(2, Xs, [a,b,c,d,e]).   % gives Xs = [c,d,e,a,b]
?- rotate(N, [a,b,c,d,e], Ys).   % 5 solutions
?- rotate(N, Xs, [a,b,c,d,e]).   % 5 solutions
?- rotate(N, Xs, Ys).            % many solutions

然后,您可以将原始nshift/3写为

nshift(N, Xs, Ys) :-
    ( N>=0 -> rotate(N, Xs, Ys) ; M is -N, rotate(M, Ys, Xs) ).