Prolog: Rotate list n times right

2019-02-24 22:44发布

问题:

Working on a predicate, rotate(L,M,N), where L is a new list formed by rotating M to the right N times.

My approach was to just append the tail of M to its head N times.

rotate(L, M, N) :- 
   (  N > 0,
      rotate2(L, M, N)
   ;  L = M
   ).

rotate2(L, [H|T], Ct) :- 
   append(T, [H], L), 
   Ct2 is Ct - 1, 
   rotate2(L, T, Ct2).

Currently, my code returns L equal to the original M, no matter what N is set to. Seems like when I'm recursing, the tail isn't properly moved to the head.

回答1:

You can use append to split lists, and length to create lists:

% rotate(+List, +N, -RotatedList)
% True when RotatedList is List rotated N positions to the right
rotate(List, N, RotatedList) :-
    length(Back, N),           % create a list of variables of length N
    append(Front, Back, List), % split L
    append(Back, Front, RotatedList).

Note: this only works for N <= length(L). You can use arithmetic to fix that.

Edit for clarity This predicate is defined for List and N arguments that are not variables when the predicate is called. I inadvertently reordered the arguments from your original question, because in Prolog, the convention is that strictly input arguments should come before output arguments. So, List and N and input arguments, RotatedList is an output argument. So these are correct queries:

?- rotate([a,b,c], 2, R).
?- rotate([a,b,c], 1, [c,a,b]).

but this:

?- rotate(L, 2, [a,b,c]).

will go into infinite recursion after finding one answer.

When reading the SWI-Prolog documentation, look out for predicate arguments marked with a "?", as in length. They can be used as shown in this example.



标签: prolog