update nth element of a list - prolog

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

Related

How to do recursion in a L-system inspired rewrite System, without DCG

I am trying to write a tiny recursive rewrite system inspired by Aristid Lindenmayers L-System basically to learn Prolog as well as to think about generative concepts in Prolog. I would like to achieve this without DCG. Due to the initial generate. and output predicate with side effects it is not a 100% pure prolog idea. DonĀ“t hesitate to take the concept apart.
My main problem is at the end of the listing. Matching the rule for every element in the original list and creating a new list with the result of each substitution.
[a] the Axiom becomes [a,b] becomes [a,b,a] and so on. Or better as a list of lists
[[a,b],[a]] to keep it more flexible and comprehensible and then flatten it later?
Basic example without constants, which could be added in a similar way. The Axiom is just used one time at the start. The idea is to encode the rule name or symbol to exchange and the symbols it should be exchanged with, as a fact/relation. Start with generate. would repeat it 20 times with a counter.
% The rules
axiom(a, [a]).
rule(a, [a, b]).
rule(b, [a]).
% Starts the program
generate :-
axiom(a, G),
next_generation(20, G).
% repeats it until counter 0.
next_generation(0, _) :- !.
next_generation(N, G) :-
output(G),
linden(G, Next),
succ(N1, N),
next_generation(N1, Next).
% Concatenates the list to one string for the output
output(G) :-
atomic_list_concat(G,'',C),
writeln(C).
% Here I am stuck, the recursive lookup and exchange.
% How do I exchange each element with the according substitution to a new list
linden([],[]). % Empty list returns empty list.
linden([R],Next) :- % List with just one Element, e.g. the axiom
rule(R, Next). % Lookup the rule and List to exchange the current
linden([H|T], Next) :- % If more than one Element is in the original list
rule(H,E), % match the rule for the current Head/ List element
% ????? % concatenate the result with the result of former elements
linden(T, Next). % recursive until the original list is processed.
% Once this is done it returns the nw list to next_generation/2
Yes, you want lists of lists. Each character can then map cleanly to one corresponding expansion list:
linden([], []).
linden([H|T], [E | Next]) :-
rule(H, E),
linden(T, Next).
(This is simpler and shorter than with a DCG for the same thing, BTW.)
For example:
?- linden([a], Expansion).
Expansion = [[a, b]].
?- linden([a, b, a], Expansion).
Expansion = [[a, b], [a], [a, b]].
Then flatten this to a flat list before expanding the next generation.

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.

Any additional information about Prolog's lists?

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.

create a list from a list of lists

I need to do the following: given a list of lists I need to find all possible combinations of the lists such that if some of these lists belong in such a combination, then they have no elements in common and the list created by appending the lists in the combination has a given length. Any ideas?
Example:
Say P= [[1,2,3],[4,5,6],[2,5],[7,9],[7,10],[8],[10]].
N a given number, say N=10. I need to search through P in order to find appropriate lists, with no elements in common, and add them in a list L such that the length of the union of L is 10. So in the above example :
L=[[1,2,3],[4,5,6],[7,9],[8],[10]]. It might be very easy but I'm new in Prolog
Given nobody's answered, and it's been quite a while since I've written anything in Prolog and I figured I needed the practice, here's how you'd do it.
First, to make generating the combinations easier, we create a term to preprocess the lists to pair them with their lengths to avoid having to get the lengths multiple times. The cut avoids needless backtracking:
with_lengths([], []) :- !.
with_lengths([H|T1], [(Len, H)|T2]) :-
length(H, Len),
with_lengths(T1, T2).
Here's the comb/3 predicate, which you use for generating the combinations:
comb(L, R, Max) :-
with_lengths(L, L1),
comb1(L1, R, Max).
comb1/3 does the actual work. The comments explain what's going on:
% Combination works.
comb1([], [], 0).
% Try combining the current element with the remainder.
comb1([(Len, Elem)|T1], [Elem|T2], Max) :-
NewMax is Max - Len,
comb1(T1, T2, NewMax).
% Alternatively, ignore the current element and try
% combinations with the remainder.
comb1([_|T1], T2, Max) :-
comb1(T1, T2, Max).

Resources