我必须定义一个谓词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).
答案 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) ).