Any additional information about Prolog's lists? - prolog

I need more information about how lists work in Prolog.
From my what I've found it seems lists in Prolog can be divided into two parts: [Head|Tail], where the Head is for the 1st item of the list while the Tail takes in the items remaining in the list. Can anyone please explain to me in more detail how this code works:
up_and_down([A, B, C|Rest]) :-
A < B,
up_and_down([B, C|Rest]).
up_and_down([A, B, C|Rest]) :-
A < B,
B > C,
goes_down([C|Rest]).
goes_down([]).
goes_down([X]).
goes_down([A, B|Rest]]) :-
A > B,
goes_down([B | Rest]).
This is a code from: Prolog check if the list is like 1,2,3,4,2,1
I would like to make this as a basis into making a program in prolog which would identify if the list is bouncy or not, which should be something like this:
is_it_bouncy([1,2,3]).
false.
is_it_bouncy([3,2,1]).
false.
is_it_bouncy([1,3,2]).
True.
Explanations are much appreciated :D
Edit: almost done but not sure about my if then statement. it should be like if not ascending and descending then bouncy bouncy([X|[Y|Zs]]):- not ascending([Y|Zs]), descending ([Y|Zs]); bouncy([Y|Zs]).

[A, B, C|D] is the same has writing [A|[B|C|D]], it meens that you take the three first element in your list. It work for has many element has you want as long as you're not trying to get more element than the list contain.
Si up_and_down take the first three element's of the list and check if they go up (A < B) and then down (B > C). Goes_down just check that, given the first two element's of the list A and B, A is superior to B.

Related

How can I pair all elements in a list in Prolog?

The goal is to create pairs/triplets/quartets from short lists, since these lists occur in a list of lists that I flatten. Since I want these elements to stay connected, I need a way to flatten the lists without losing the connection between the items in these particular lists.
In short, [a, b, c] needs to be converted to a-b-c. In theory long lists need to be handled too, but in reality only short lists will be relevant.
What I tried so far (which I know is horribly wrong):
create_pair([], Pair).
create_pair([H, H1|T], Pair):-
NPair = H-H1,
create_pair(T, NPair).
This is just for the case of where the list has 2 elements.
You can build your pair/triplet/quartet/... by joining the two first items of the list and replacing it with your connection term until the whole list is processed:
create_ntets([H], H).
create_ntets([H,H1|T], NTet):-
create_ntets([H-H1|T], NTet).
This procedure assumes there is no 0-tet.
Sample runs
?- create_ntets([a,b,c], Triplet).
Triplet = a-b-c
?- create_ntets([a,b,c,d], Quartet).
Quartet = a-b-c-d
If the data structure you want to convert the short lists to doesn't really matter, you can just use =../2 to convert the list to a term. Something like:
list_term(L,T) :- T =.. [ listlet | L ].
So evaluating list_to_term( [a,b,c], T) binds T as listlet(a,b,c) and evaluating list_to_term( L , listlet(a,b,c,d) ) binds L as [a,b,c,d].
See https://swish.swi-prolog.org/p/list-to-term.pl for a runnable playground.

How to append an element to each element of a list ? (Prolog)

I'll like to append an element to each element of a list. the element must be a list too.
Exemple :
A = [a,b,c]
B = [ele,ele2]
The result would be:
R = [[a,ele,ele2],[b,ele,ele2],[c,ele,ele2]]
I tried
maplist(custom_append,A,B,R).
But it returns false with
custom_append(X,Y,[X|Y]).
How can I achieve this ?
Note that B is not a list over which you want to iterate, you want to append an element of A to the same list B.
The easiest way to achieve this, is probably by swapping the order of the elements in the custom_append/3 to:
custom_append(Y, X, [X|Y]).
and then we can obtain this by using a maplist/3:
maplist(custom_append(B), A, R).
we thus already make something that behaves quite similar to partial application: we pass a functor custom_append(B), and Prolog will then make a call with custom_append(B, Ai, Ri) (Ai and Ri are here used to denote the elements of the lists A and R).
The straightforward way would be like this:
append_list([], _, []).
append_list([A|As], B, [[A|B]|Cs]) :-
append_list(As, B, Cs).
Don't even need to use maplist.

Prolog - Using Bagof

I've been stuck on a past paper question while studying for my exams.
The question is:
https://gyazo.com/ee2fcd88d67068e8cf7d478a98f486a0
I figured I've got to use findall/bagof/setof because I need to collect a set of solutions. Furthermore, setof seems appropriate because the list needs to be presented in descending order.
My solution so far is:
teams(List) :-
setof((Team, A),
(Team^team(Team, _, Wins, Draws, _), A is Wins*3 + Draws*1),
List).
However the problem is I don't quite get the answers all in one list. I'm very likely using Team^ incorrectly. I'd really appreciate pointers on how I can get a list of ordered tuples in terms of points. The output it gives me is:
X = [(queenspark,43)] ? ;
X = [(stirling,26)] ? ;
X = [(clyde,25)] ? ;
X = [(peterhead,35)] ? ;
X = [(rangers,63)] ? ;
Also, it's not really apparent what kind of order, if any it's in, so I'm also lost as to how setof is ordering.
Whats the best way to approach this question using setof?
Thanks.
Firstly, I would suggest to change (Team,A) to a pair representation A-Team with the A being in front since this is the total score of the team and thus the key you want to use for sorting. Then you would like to prefix the variables that should not be in the list with a ^ in front of the query you want to aggregate. See the following example:
?- setof(A-Team, P^Wins^Draws^L^(team(Team, P, Wins, Draws, L), A is Wins*3 + Draws*1), List).
List = [25-clyde,26-stirling,35-peterhead,43-queenspark,63-rangers]
Since you asked, consider the following query with the pair ordering flipped to Team-A for comparison reasons:
?- setof(Team-A,P^Wins^Draws^L^(team(Team,P,Wins,Draws,L), A is Wins*3 + Draws*1),List).
List = [clyde-25,peterhead-35,queenspark-43,rangers-63,stirling-26]
Now the resulting list is sorted with respect to the teamnames. So A-Team is the opportune choice. You could then use the predicate lists:reverse/2 to reverse the order to a descending list and then define an auxilary predicate pair_second/2 that you can use with apply:maplist/3 to get rid of the leading scores in the pairs:
:- use_module(library(lists)).
:- use_module(library(apply)).
% team(+Name, +Played, +Won, +Drawn, +Lost)
team(clyde,26,7,4,15).
team(peterhead,26,9,8,9).
team(queenspark,24,12,7,5).
team(rangers,26,19,6,1).
team(stirling,25,7,5,13).
pair_second(A-B,B). % 2nd argument is 2nd element of pair
teams(Results) :-
setof(A-Team,
P^Wins^Draws^L^(team(Team, P, Wins, Draws, L), A is Wins*3 + Draws*1),
List),
reverse(List,RList),
maplist(pair_second,RList,Results). % apply pair_second/2 to RList
If you query the predicate now you get the desired results:
?- teams(T).
T = [rangers,queenspark,peterhead,stirling,clyde]
Concerning your question in the comments: Yes, of course that is possible. You can write a predicate that describes a relation between a list of pairs and a list than only consists of the second element of the pairs. Let's call it pairlist_namelist/2:
pairlist_namelist([],[]).
pairlist_namelist([S-N|SNs],[N|Ns]) :-
pairlist_namelist(SNs,Ns).
Then you can define teams/1 like so:
teams(Results) :-
setof(A-Team,
P^Wins^Draws^L^(team(Team, P, Wins, Draws, L), A is Wins*3 + Draws*1),
List),
reverse(List,RList),
pairlist_namelist(RList,Results).
In this case, besides maplist/3, you don't need pair_second/2 either. Also you don't need to include :- use_module(library(apply)). The example query above yields the same result with this version.

For each element in the list

I'm new in prolog, I have a problem.
I got a list of numbers like [7,88,10,11] and what I want to do is:
for each element in [7,88,10,11] A
for each element in [88,10,11] B
for each element in [10,11] C
write(A-B-C).
I want all the combinations (permutations of 3 elements) in the list.
Thank you!
Edit: The list is an example, the actual list is L:
list(L,J) :- findall(X,(task(X,K),K==J),L).
So then I would like to iterate like I said through list L.
actual prolog code is very similar to your description
?- forall((member(A, [7,88,10,11]),
member(B, [88,10,11]),
member(C, [10,11])
), writeln(A-B-C)).
you can think of comma operator as join in SQL (in the simple syntax select * from A,B,C)
edit: of course, that code is not similar at all to your description. Should be instead
?- forall(member(A, [7,88,10,11]),
forall(member(B, [88,10,11]),
forall(member(C, [10,11]), writeln(A-B-C)))).
(hope I balanced right brackets...)
edit: sorry, I completely missed that relation among A,B,C. Does
?- L = [7,88,10,11],
forall((select(A,L,L1),
select(B,L1,L2),
member(C,L2)
), writeln(A-B-C)).
works better ?

update nth element of a list

I am new to prolog , I have a list in prolog like A=[1,2,3,4], and than I accessed nth element using nth(N,[_|T],R). Now I have Nth element in R, than I have done some calculation on R. Now what I want is to update that nth element in list.
Because of I am doing a lot of calculations with each element in list I can't make a new list each time.
I didn't find any method to update list.
With regard to our conversation, you can add two lists together, creating a third, by specifying that the two head elements of the source lists, added together, make the head element of the result list, and that this applies to the remainder of the lists.
There is also a need for a base case, that is, when the two source lists are empty, so should the result list.
addLists([X|A], [Y|B], [Z|C]) :- Z is X+Y, addLists(A, B, C).
addLists([], [], []).
Remember you are always aiming to specify the constraints of the answer, more than the method of answering it. Prolog is very different to other programming languages in that you do not tell it how to do something, you simply tell it conditions that are true for the answer and let it extrapolate it.
From the comments you exchanged with #Orbling seems that what you need is a kind of maplist/4
process_list(A, B, C) :-
maplist(process_elem, A, B, C).
process_elem(A, B, C) :- C is A + B. % or whatever needed
If you are using the index in process_elem then this is not appropriate. Then make a recursive visit of list, passing down the index
process_list(A, B, C) :-
process_list(1, A, B, C).
process_list(I, [A|As], [B|Bs], [C|Cs]) :-
C is A + B * I, % or whatever needed
J is I + 1,
!, process_list(J, As, Bs, Cs).
process_list(_, [], [], []).
edit Just to add to the various ways exposed in answers to the question #Orbling suggests, here a way using nth0/4
?- I = 6, nth0(I,"hello world",_,T), nth0(I,U,0'W,T), format('~s',[U]).
hello World

Resources