prolog: move element between lists - prolog

I just start learning Prolog and find it's hard to handle list related problem.
If I have a list. Inside this list, I have three inner lists.
[[a,b,c], [d,e,f],[h,g]]
I need to write a predicate called "move(L, X, From, To, R)" where X is the character I want to move (this character has to be the last element in the inner list), From is the index of list I want to move from, To is the index of list I want to move to. e.g.
move([[a,b,c], [d,e,f],[h,g]], f, 2, 3, R).
returns
R = [[a,b,c], [d,e],[h,g,f]]
One more example:
move([[a,b,c], [d,e,f],[h,g]], f, 2, 1, R).
returns
R = [[a,b,c,f], [d,e],[h,g]]
I wrote a helper predicates to determine if a character is the last element in the list:
last([A], C):- A == C.
last([_|T], C):- last_one(T, C).
I spent a few hours thinking about it, but no working solutions. Any help please?

I think you must prove the following:
move(L, X, From, To, R) is the predicate you want run, so the #1 argument is a list of list (in the sample: L = [[a,b,c], [d,e,f],[h,g]] ); the #3 and #4 arguments are members of L, so you can use the predicate nth1(N, L, E), where N is the order of the element, L is the list and E the Element; each element is another list, and now you must delete the X from the list From and add it to the list To.
For it, first you can use the predicate 'select/3'; for the second, you can use 'append/3'.
I tried the folowwing rules, but it give me a different order of the main list:
move(L, X, F, T, R) :-
nth1(F, L, Lf),
nth1(T, L, Lt),
select(X, Lf, Rf),
append(Lt, [X], Rt),
select(Lf, L, Ra),
select(Lt, Ra, Rb),
append(Rb, [Rf], Rc),
append(Rc, [Rt], R).
with this code, you obtain the following:
move([[a,b,c], [d,e,f],[h,g]], f, 2, 3, R).
R = [[a,b,c], [d,e],[h,g,f]]
but:
move([[a,b,c], [d,e,f],[h,g]], f, 2, 1, R).
R = [[h,g], [d,e], [a,b,c,f]]

Related

Rotate a list in prolog recursively

I'm trying to rotate a list in prolog recursively but it does not work as expected.
Code:
rot([],[]).
rot([H|T1], [T2|H]):-rot(T1,T2).
Output:
?- rot([1,2,3], V).
V = [[[[]|3]|2]|1]
Expected output:
?- rot([1,2,3], V).
V = [3,2,1]
Could anyone explain me why my code does not work?
Since Prolog is untyped, you can indeed write something like [List|Element], but if you want a list to make sense, the only way you can construct lists is like [Element|List]. So [T2|H] does not make sense at all. In that case T2 should be an element, and H a list (or the empty list []).
You will need to define two predicates:
the main predicate (rot/2) that simply pops the head from the given list and calls the recursive predicate; and
the recursive predicate (here rot/3) that simply passes all elements of the given list and emits the original head as tail element.
Together this works like:
%main predicate rot/2
rot([],[]).
rot([H|T1],T2) :-
rot(T1,H,T2).
%recursive predicate rot/3
rot([],Last,[Last]).
rot([H|T1],Last,[H|T2]) :-
rot(T1,Last,T2).
Your code doesn't work because in an expression like [H|T], H is an element of the list and T is the tail of the list--also a list. For instance:
?- [H|T] = [1,2,3].
H = 1,
T = [2, 3].
So what happens when you switch that around?
?- [H|T] = [1,2,3], X = [T|H].
H = 1,
T = [2, 3],
X = [[2, 3]|1].
See the problem?
The problem is with the second clause. What I do is to rotate the tail of the first list inside L1 and then call append with L1 and the first element and assign the result to L (the second argument)
my-append([], L, L).
my-append([H|T], L, [H|R]) :- my-append(T, L, R).
rot([], []).
rot([H|T], L) :- rot(T, L1), my-append(L1, H, L).

Find all positions of a value in a list in Prolog

My assignment is this: Write a program that reads an integer x and a list of integers L; then locate the list of all positions of x into L, and return the resulting list. For example, for x=2 and L=[1,2,3,4,2,5,2,6] the program should return the list R=[2,5,7].
So far, I've been able to write an indexOf predicate:
indexOf([E|_], E, 1).
indexOf([_|T], E, I) :- indexOf(T, E, I2), I is I2 + 1.
However, this doesn't "return" a list. So:
indexOf([a,b,c,a,d], a, R).
R = 1;
R = 4
I'd like to do something like this:
findAll([a,b,c,a,d], a, R).
R = [1, 4]
But I'm not sure how to collect the values into a list.
This is a school assignment, so I'd appreciate just a nudge in the right direction.
A nudge: you find the indices, but you don't collect them.
indices(List, E, Is) :-
indices_1(List, E, Is, 1).
For an empty list, the list of indices is empty,
and the element doesn't matter
indices_1([], _, [], _).
If the element is like the head, collect the index.
indices_1([E|Xs], E, [I|Is], I) :-
I1 is I + 1,
indices_1(Xs, E, Is, I1).
This needs another clause to work properly.
EDIT:
One way to do it would be:
indices_1([X|Xs], E, Is, I) :- dif(X, E),
I1 is I + 1,
indices_1(Xs, E, Is, I1).
In the previous clause, the head of the list and the Element are unified. In this clause, they are explicitly different. This means that only one of the two clauses can be true for an element of the list in the first arguemnt.
EDIT:
Another way to do that is to use findall and nth1:
indices(List, E, Is) :-
findall(N, nth1(N, List, E), Is).

How to take the head of one list in a list of lists and put it in another list?

I have a list of lists, which looks something like this:
[[b,c],[],[a]]
I want to write a predicate that will take a specific letter from the top of one of the lists, and put it in another list. The letter to be moved is specified beforehand. It can be placed on top of a list which is either empty, or contains a letter that is larger (b can be placed on c, but not otherwise). The letter should be removed from the original list after it has been moved.
I am having trouble telling Prolog to look for a list which starts with the specified letter, and also how to tell Prolog to put this in another list.
here is my solution, based no [nth1][1]/4 (well, you should read documentation for nth0/4, really)
/* takes a specific letter from the top of one of the lists, and puts it in another list.
The letter to be moved is specified beforehand.
It can be placed on top of a list which is either empty, or contains a letter that is larger (b can be placed on c, but not otherwise).
The letter should be removed from the original list after it has been moved.
*/
move_letter(Letter, Lists, Result) :-
% search Letter, Temp0 miss amended list [Letter|Rest]
nth1(I, Lists, [Letter|Rest], Temp0),
% reinsert Rest, Temp1 just miss Letter
nth1(I, Temp1, Rest, Temp0),
% search an appropriate place to insert Letter
nth1(J, Temp1, Candidate, Temp2),
% insertion constraints
J \= I, (Candidate = [] ; Candidate = [C|_], C #> Letter),
% update Result
nth1(J, Result, [Letter|Candidate], Temp2).
Usage examples:
?- move_letter(a,[[b,c],[],[a]],R).
R = [[a, b, c], [], []] ;
R = [[b, c], [a], []] ;
false.
?- move_letter(b,[[b,c],[],[a]],R).
R = [[c], [b], [a]] ;
false.
I followed this 'not idiomatic' route to ease the check that the insertion occurs at different place than deletion.
Below are some rules to find lists that starts with some element.
starts_with([H|T], H).
find_starts_with([],C,[]).
find_starts_with([H|T],C,[H|Y]) :- starts_with(H,C),find_starts_with(T,C,Y).
find_starts_with([H|T],C,L) :- \+ starts_with(H,C), find_starts_with(T,C,L).
Example:
| ?- find_starts_with([[1,2],[3,4],[1,5]],1,X).
X = [[1,2],[1,5]] ? ;
I like #CapelliC's concise solution. Here's an alternative solution that doesn't use the nth1 built-in. Apologies for the sucky variable names.
% move_letter : Result is L with the letter C removed from the beginning
% of one sublist and re-inserted at the beginning of another sublist
% such that the new letter is less than the original beginning letter
% of that sublist
%
move_letter(C, L, Result) :-
removed_letter(C, L, R, N), % Find & remove letter from a sublist
insert_letter(C, R, 0, N, Result). % Result is R with the letter inserted
% removed_letter : R is L with the letter C removed from the beginning of a
% sublist. The value N is the position within L that the sublist occurs
%
removed_letter(C, L, R, N) :-
removed_letter(C, L, R, 0, N).
removed_letter(C, [[C|T]|TT], [T|TT], A, A).
removed_letter(C, [L|TT], [L|TTR], A, N) :-
A1 is A + 1,
removed_letter(C, TT, TTR, A1, N).
% Insert letter in empty sublist if it's not where the letter came from;
% Insert letter at front of a sublist if it's not where the letter came from
% and the new letter is less than the current head letter;
% Or insert letter someplace later in the list of sublists
%
insert_letter(C, [[]|TT], A, N, [[C]|TT]) :-
A \== N.
insert_letter(C, [[C1|T]|TT], A, N, [[C,C1|T]|TT]) :-
A \== N,
C #< C1.
insert_letter(C, [L|TT], A, N, [L|TTR]) :-
A1 is A + 1,
insert_letter(C, TT, A1, N, TTR).
Results in:
| ?- move_letter(a, [[b,c],[],[a]], R).
R = [[a,b,c],[],[]] ? a
R = [[b,c],[a],[]]
no
| ?- move_letter(b, [[b,c],[],[a]], R).
R = [[c],[b],[a]] ? a
no
| ?- move_letter(b, [[b,c], [], [a], [b,d]], R).
R = [[c],[b],[a],[b,d]] ? a
R = [[b,c],[b],[a],[d]]
no

Prolog programs - how to make it work?

I have these two programs and they're not working as they should. The first without_doubles_2(Xs, Ys)is supposed to show that it is true if Ys is the list of the elements appearing in Xs without duplication. The elements in Ys are in the reversed order of Xs with the first duplicate values being kept. Such as, without_doubles_2([1,2,3,4,5,6,4,4],X) prints X=[6,5,4,3,2,1] yet, it prints false.
without_doubles_2([],[]).
without_doubles_2([H|T],[H|Y]):- member(H,T),!,
delete(H,T,T1),
without_doubles_2(T1,Y).
without_doubles_2([H|T],[H|Y]):- without_doubles_2(T,Y).
reverse([],[]).
reverse([H|T],Y):- reverse(T,T1), addtoend(H,T1,Y).
addtoend(H,[],[H]).
addtoend(X,[H|T],[H|T1]):-addtoend(X,T,T1).
without_doubles_21(X,Z):- without_doubles_2(X,Y),
reverse(Y,Z).
The second one is how do I make this program use a string? It's supposed to delete the vowels from a string and print only the consonants.
deleteV([H|T],R):-member(H,[a,e,i,o,u]),deleteV(T,R),!.
deleteV([H|T],[H|R]):-deleteV(T,R),!.
deleteV([],[]).
Your call to delete always fails because you have the order of arguments wrong:
delete(+List1, #Elem, -List2)
So instead of
delete(H, T, T1)
You want
delete(T, H, T1)
Finding an error like this is simple using the trace functionality of the swi-prolog interpreter - just enter trace. to begin trace mode, enter the predicate, and see what the interpreter is doing. In this case you would have seen that the fail comes from the delete statement. The documentation related to tracing can be found here.
Also note that you can rewrite the predicate omitting the member check and thus the third clause, because delete([1,2,3],9001,[1,2,3]) evaluates to true - if the element is not in the list the result is the same as the input. So your predicate could look like this (name shortened due to lazyness):
nodubs([], []).
nodubs([H|T], [H|Y]) :- delete(T, H, T1), nodubs(T1, Y).
For your second question, you can turn a string into a list of characters (represented as ascii codes) using the string_to_list predicate.
As for the predicate deleting vovels from the string, I would implement it like this (there's probably better solutions for this problem or some built-ins you could use but my prolog is somewhat rusty):
%deleteall(+L, +Elems, -R)
%a helper predicate for deleting all items in Elems from L
deleteall(L, [], L).
deleteall(L, [H|T], R) :- delete(L, H, L1), deleteall(L1, T, R).
deleteV(S, R) :-
string_to_list(S, L), %create list L from input string
string_to_list("aeiou", A), %create a list of all vovels
deleteall(L, A, RL), %use deleteall to delete all vovels from L
string_to_list(R, RL). %turn the result back into a string
deleteV/2 could make use of library(lists):
?- subtract("carlo","aeiou",L), format('~s',[L]).
crl
L = [99, 114, 108].
while to remove duplicates we could take advantage from sort/2 and select/3:
nodup(L, N) :-
sort(L, S),
nodup(L, S, N).
nodup([], _S, []).
nodup([X|Xs], S, N) :-
( select(X, S, R) -> N = [X|Ys] ; N = Ys, R = S ),
nodup(Xs, R, Ys).
test:
?- nodup([1,2,3,4,4,4,5,2,7],L).
L = [1, 2, 3, 4, 5, 7].
edit much better, from ssBarBee
?- setof(X,member(X,[1,2,2,5,3,2]),L).
L = [1, 2, 3, 5].

Prolog: recursive list construction

I'm having problem constructing a list of lists in my prolog program.
I have a predicate which gives me back a single case of a row. I have to group all the cases of this row and transform them into a list of lists. I can access them just fine but when I exit, all I'll get is the first element.
Here's the code:
sudoku3to2 :- s3to2(1).
s3to2(Line) :-
Line < 9,
Line1 is Line+1,
s3getLine(Line,0,[L]),
assert(sudoku2(Y,L])),
s3to2(Line1).
s3to2(9).
s3getLine(Line,X, , ) :-
X < 9,
X1 is X + 1,
sudoku3(Line,X, ),
s3getLine(Line,X1, , ).
s3getLine(Line,9,L,L).
sudoku3/3 will return the element at the X,Y coordinate. When I get to s3getLine(Line,9,L,L) I'll start going back. I want to keep all the elements I've gathered and not just the first one. And I'm really having trouble constructing the proper predicate calls.
findall/3 is the 'list constructor' more easily understood.
It's a builtin that list all solutions found, shaping the elements with a specified pattern. Here the pattern is really just the variable we are interested to.
I use between/3 to obtaing a correctly ordered matrix, without regard to sudoku3 rules order.
sudoku3(1, 1, a).
sudoku3(1, 2, b).
sudoku3(2, 1, c).
sudoku3(2, 2, d).
mat(M) :-
W = 2,
findall(Row,
(between(1, W, R),
findall(V, (between(1, W, C), sudoku3(R, C, V)), Row)
), M).
Result:
?- mat(M).
M = [[a, b], [c, d]].
You should change W=9.
HTH

Resources