Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rotating a list to the right (Prolog)

Tags:

list

prolog

I have an assignment where I need to rotate a list once to the right. I also have a constraint where I can only use one predicate. It seems that shifting to the left is very easy:

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

Though, it seems to be harder to rotate right AND keep the constraint. This is my attempt:

rotate([H], H).
rotate([H|T], F) :- rotate(T,F1), append(F1,T,F).

In my head, it works perfectly, though I only get false as an output. Any help solving this would be much appreciated!

like image 396
user2796815 Avatar asked Nov 19 '13 20:11

user2796815


People also ask

How do you split a list into head and tail in Prolog?

In Prolog list elements are enclosed by brackets and separated by commas. Another way to represent a list is to use the head/tail notation [H|T]. Here the head of the list, H, is separated from the tail of the list, T, by a vertical bar.

What does [] mean in Prolog?

[] is an empty list. Note that [x|y] is different than both of these. Also, since x and y start with lower case, they ate atoms, not variables. [X|Y] is a list of one or more elements. So a single element list will match this and match [_] , but a two element list will only match the former.

How do I edit a list in Prolog?

Although lists in Prolog cannot be modified, it is possible to add elements to the end of a list with an unspecified length. In this way, items can be "appended" to a list without creating another list: :- initialization(main). append_to_list(List,Item) :- append_to_list(List,Item,0).

How do you select an element in a list in Prolog?

This predicate can be used to select an element from a list, delete an element or insert it. The definition of this Prolog library predicate is: select(A, [A|B], B). select(A, [B, C|D], [B|E]) :- select(A, [C|D], E).


2 Answers

If you have already a predicate, say rotl(L, Rotated) that rotates one to the left, you can use that very same predicate to rotate to the right. Simply put the list into the second argument and keep the first a variable!

That is the deep idea of relations: You can use them in more than one manner!

So to summarize:

rotleft([E|T], R) :-
   append(T,[E],R).

rotright(L, R) :-
   rotleft(R, L).

And here is the most general query that shows you all answers that contain all possible solutions:

| ?- rotright(L,R).
L = [_A],
R = [_A] ? ;
L = [_A,_B],
R = [_B,_A] ? ;
L = [_A,_B,_C],
R = [_C,_A,_B] ? ;
L = [_A,_B,_C,_D],
R = [_D,_A,_B,_C] ? ;
L = [_A,_B,_C,_D,_E],
R = [_E,_A,_B,_C,_D] ? ;
L = [_A,_B,_C,_D,_E,_F],
R = [_F,_A,_B,_C,_D,_E] ? ;
L = [_A,_B,_C,_D,_E,_F,_G],
R = [_G,_A,_B,_C,_D,_E,_F] ? ;
L = [_A,_B,_C,_D,_E,_F,_G,_H],
R = [_H,_A,_B,_C,_D,_E,_F,_G] ? 

Do you see the pattern? For each length of a list (except for the empty list), there is one answer that contains all possible solutions. Look how in one answer the variables are the same. I will take one answer to illustrate this:

L = [_A,_B,_C,_D,_E,_F,_G],
      \  \  \  \  \  \  \____
  ___  \  \  \  \  \  \
     \  \  \  \  \  \  \
R = [_G,_A,_B,_C,_D,_E,_F] ? ;

And here is the most interesting question:

How do lists look like that are the same as the list rotated to the left/right?

Try to formulate that query and look at the answers in detail.

like image 75
false Avatar answered Sep 24 '22 19:09

false


It's important to note that append/3 is rather flexible.

Left rotations are, as you found, easy. You want to get from

[a,b,c]

to

[b,c,a]

By observation, doing that just requires getting the first item from the list (the head) and appending that to the remainder of the list (the tail). In prolog, that's easy:

rotate_left( []     , [] ) .        % rotating an empty list yields the empty list
rotate_left( [L|Ls] , Rotated ) :-  % a left rotation of a non-empty list consist of decomposing it into its head and tail, and
  append( Ls , [L] , Rotated )      % - appending the head to the tail.
  .

A right rotation isn't much more difficult. Again, by observation, you want to get from

[a,b,c]

to

[c,a,b]

You need to get the last item from the list and prepend it to the remainder of the list. Again, you don't need anything more than you did for a left rotation:

rotate_right( []     , []      ) .         % rotating an empty list yields the empty list.
rotate_right( [L|Ls] , Rotated ) :-        % a right rotation of a non-empty list consists of
  append( LeftPrefix , [Last] , [L|Ls] ) , % - deconstructing it into the last item and everything to its left
  Rotated = [Last|LeftPrefix]              % - reconstructing it with the righmost item first
  .

append/3 is very powerful since it can decompose a list into all possible prefixes and suffixes. Feed [a,b,c] into its 3rd argument:

append( Prefix , Suffix , [a,b,c] ).

and, with backtracking, you get the full set of possible ways to create the list [a,b,c]:

Prefix = []      Suffix = [a,b,c]
Prefix = [a]     Suffix = [b,c]
Prefix = [a,b]   Suffix = [c]
Prefix = [a,b,c] Suffix = []
like image 44
Nicholas Carey Avatar answered Sep 20 '22 19:09

Nicholas Carey