Prolog: apply predicate to all list elements and sum results - list

I have a certain list which is generated from a predicate and looks like this:
[a, b, c]
I also have a following predicate p/3 that could be applied to each element of my list:
?- p(a, NewList, Number).
and it will return:
NewList = [c, d],
Number = 2.
where NewList is a newly generated list from a element, and Number is the NewList length.
Problem:
I want to apply the p/3 predicate to all elements, and get
one list which consists of all elements from all NewLists aka all NewLists appended together
and the sum of all Numbers.
I tried to do it like this:
loop_list([Element|[]], NewList, Number) :-
p(Element, NewList, Number).
loop_list([Head|Tail], [Tmp|NewList], Number) :-
loop_list(Tail, Tmp, Number).
but failed.

It is often better to separate your concerns, and solve one task at once. You can use maplist/4 [swi-doc] here to call the predicate over all the elements in the list. This will then unify the third and the fourth element with the results of p/3.
Next we can make use of append/2 [swi-doc] to append lists together, and sumlist/2 [swi-doc] to sum the elements of a list together.
We thus can implement this as:
loop_list(Ls, Xs, Sum) :-
maplist(p, Ls, Xss, Items),
append(Xss, Xs),
sumlist(Items, Sum).

Related

Predicate gives list of unbound variables instead of all possible lists

Let's say I have a list L1 = [1,2,3], I want to write a predicate that can find all permutations of this list i.e
[1,2,3]
[1,3,2]
[2,1,3]
[2,3,1]
[3,1,2]
[3,2,1]
Note: I know permutation(L1, L2). does exactly this, but I want to write my own predicate that does this for an exercise.
I'm a prolog rookie, so I thought lets first make a predicate that returns truewhen two lists L1 and L2 are permutations of eachother. The requirements for that are:
They need to be the same length
Every element in L1 has to be in L2
So I came up with this:
permute(L1,L2):-
forall(member(X,L1), member(X,L2)), % every element that is a member in L1 has to be a member in L2
length(L1,A), % the length of the list L1 is A
length(L2,A). % AND the length of the list L2 is A
So when I query permute([1,2,3], [1,3,2]).I do get true as expected, and permute([1,2,3], [1,3]). and permute([1,2,3], [1,3,4]). both give false. So my predicate works to see if 2 lists are permutations of eachother.
But if I ask: permute([1,2,3], A). I want to be able to see all valid A, i.e all permutations of [1,2,3]. Instead I get unbounded variables.
Something like A = [_942, _948, _954].
Why does this happen, why can't i look through all possible lists A? Is there a simple way to modify my code to make that happen?
First of all your two points definition is wrong. According to it, permute( [1,1,2], [1,2,2]) should hold (and it does).
The "simple" way is to use select/3,
select( [A|B], X):- select(A, X, Y), select(B, Y).
select( [], []).
And it works, but only in one direction. Even adding (simple) same_length doesn't help:
permute( A, B):- same_length( A, B), select( B, A).
same_length( A, B):- length(A, N), length(B, N). % wrong
% permute( [1,2,3], X). % OK
% permute( X, [1,2,3]). % doesn't terminate after the last solution
No, same_length/2 must be defined carefully, as
same_length( [], []).
same_length( [_|A], [_|B]):- same_length(A, B).
Then permute is OK in both directions.

Prolog: Maplist appending results to main list instead of sublists

So I have the simple predicate defined as
pred(Info, List, Result) :-
maplist(pred_calculate(Info), List, Result).
pred_calculate returns a list of X elements after an operation on a element of list, so for example pred_calculate(Info, List, Result) would return something like [2,3,5]
I want to add all the results of applying the pred_calculate predicate to all the elements of List, the problem I'm running into is that at the moment it's adding all the results from pred_calculate as sublists instead of adding to the single main list only.
So at the moment Result returns
[[2,3,5],[5,7,8],[8,9,11]] when it should return only [2,3,5,5,7,8,8,9,11]
How would I go about changing it to fix this behaviour?
When using foldl/4 with append/3, you have to pass the arguments in the correct order to append, if the order of the items is important1:
pred(Info, List, Result) :-
maplist(pred_calculate(Info), List, List1),
foldl([A, B, C] >> append(B, A, C), List1, [], Result).
Also, flatten/2 would achieve the same result, i.e.:
pred(Info, List, Result) :-
maplist(pred_calculate(Info), List, List1),
flatten(List1, Result).
1: foldl(append, List1, [], Result) would give you [8,9,11,5,7,8,2,3,5] as result.
maplist calls pred_calculate(Info) on every corresponding element of List and Result. Perhaps maplist is not what you really want to use here if pred_calculate results in a list on each call since it's not a 1-1 correspondence. You have a 1-to-many and you want the many in one big, flat list. You could use flatten or fold as !joel76 suggests. Or, you could "manually" write your own maplist-like predicate which is very simple - just a basic list recursion and probably using append to achieve each step:
pred(Info, List, Result) :-
pred(Info, List, [], Result).
pred(Info, [], Result, Result).
pred(Info, [H|T], Acc, Result) :-
pred_calculate(Info, H, R),
append(Acc, R, Acc1),
pred(Info, T, Acc1, Result).

Append lists prolog

Given the list as input (in the format mentioned below) , I need to get the output that is a simple list of lists, If the given input list is empty then the predicate should return an empty list,
Given the input
[[[a,b],[c]],[[d,e]],[[g,h],[j,k]],[[h,k,l,l]]]
I need to get the output
[[a,b],[c],[d,e],[g,h],[j,k],[h,k,l,l]]
I am having trouble performing recursion,
The code I tried is below,
function([],X):-append([],X,X).
function([Head|Tail],X):-
first(Tail,A),
append(Head,A,X),
removehead(Tail,C),
function(C,X).
where the predicates first returns first element of the list, removehead removes the first element of the list.
You make a fair attempt in the code you have shared. Here are the things that you need to improve:
The predicate name fucntion describes the fact that this predicate has one solution whenever the first argument is a list. This is typically done in the documentation, e.g. %! function(+Nested:list, -Denested:list) is det.
append([], X, X) is true by definition if X is a list, so it is superfluous here.
What are first/2, removehead/2? If you want to instantiate to the first element of a list, you can also write the clause head argument as [Head,A|C]. Then you also do not need to remove the head from Tail explicitly.
Once I make alterations based on the above I come up with the following code:
%! denest(+Nested:list, -Denested:list) is det.
denest([], []).
denest([H|T1], L):-
denest(T1, T2),
append(H, T2, L).
Example run:
?- denest([[[a,b],[c]],[[d,e]],[[g,h],[j,k]],[[h,k,l,l]]], L).
L = [[a, b], [c], [d, e], [g, h], [j, k], [h, k, l|...]].
Hope this helps!

Reverse lists in list of lists prolog

I want to reverse each list from a list of lists.
I have something which looks like:
[[a,b],[],[c,d,e],[],[],[f,g]]
What I want is to read through the list of lists and reverse each list and get this result:
[[b,a],[],[e,d,c],[],[],[g,f]]
I already have a reverse function:
reverse(L, R) :- reverse(L, [], R).
reverse([], R, R).
reverse([H|T], A, R) :- reverse(T, [H|A], R).
How can I manage to read through the list?
Will a recursive function like this one work ?
reverseLL([H|T], L) :-
reverse(H,NH),
reverseLL([T],[NH|L]).
reverseLL([],L).
reverseInList([],[]).
reverseInList([H|Ts],[H1|R]):-
reverse(H,H1),
reverseInList(Ts,R).
This works by recursing over the list and using the library function 'reverse/2' to reverse each sublist.

Prolog: List recursion and modification

I'm having a little trouble understanding list recursion and modification in Prolog. I'm trying to take a list of lists, then with each list, multiply each element in the list by the last element.
Here's a snippet of my code:
/*Find the last element of a list*/
lastelement(X,[X]).
lastelement(X,[_|L]) :- lastelement(X,L).
/*Multiply two lists together*/
multiplication(M1,M2,M1*M2).
/*Take a list, find the last element and multiply every part of that list by that element*/
/*Attach modified list to X*/
modifyL([],X) :- X is [].
modifyL([First|Tset],X) :- lastelement(Y,First),
multiplication(Y,First,MFirst),
modifyL([Tset],X),
append(X,MFirst,X).
When I try any list of lists, however, all I get is false. Can someone give me any pointers
on list recursion that could help further understand this problem?
modifyL([],X) :- X is [].
This doesn't do what you think, is is used to get the result of an arithmetic evaluation.
you can write
modifyL([],X) :- X = [].
or simply
modifyL([],[]).
When you work with a list, and you repeat the same process to each element of this list you can use maplist which is exactly design for that.
the template is maplist(Goal, L1 L2).
modify(L1, L2) :-
maplist(multiply_one_list,L1, L2).
multiply_one_list works with a list, you it can be written like that :
multiply_one_list(L_in, L_out) :-
% getting last argument
reverse(L_in, [Last | _]),
% multiply each element of the list by
% the last element, one more maplist !
maplist(multiply_one_element(Last), L_in, L_out).
multiply_one_element(Last, In, Out) :-
Out is In * Last.