Prolog: Maplist appending results to main list instead of sublists - list

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).

Related

Prolog: apply predicate to all list elements and sum results

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).

Prolog: Deleting atom in nested lists

I'm trying to delete an item in a list. My code works but it doesn't delete the symbol in a nested list.
In the second to last rule I'm trying to check if the next element is a list. What am I doing wrong?
del(Symbol, [], []) :-
!.
del(Symbol, [Symbol|Tail], Result) :-
!,
del(Symbol, Tail, Result).
del(Symbol, [[List]|Tail], Result) :-
!,
del(Symbol, List, Result2),
append([List], Result2, Result).
del(Symbol, [Other|Tail], Result) :-
!,
del(Symbol, Tail, Result2),
append([Other], Result2, Result).
once you have a working del/3 on a flat list, you can extend it to handle nested lists, checking the type of the first element: if it's a list, recurse and keep the outcome.
To check the type, you can use is_list/1

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.

Custom reverse of a list in Prolog

I am trying to write a predicate that given the following list in Prolog:
[[1,a,b],[2,c,d],[[3,e,f],[4,g,h],[5,i,j]],[6,k,l]]
will produce the following list:
[[6,k,l],[[5,i,j],[4,g,h],[3,e,f]],[2,c,d],[1,a,b]]
As you can see I would like to preserve the order of the elements at the lowest level, to produce elements in the order 1, a, b and NOT b, a, 1.
I would also like to preserve the depth of the lists, that is, lists that are originally nested are returned as such, but in reverse order.
I have managed to achieve the desired order with the following code, but the depth is lost, i.e. lists are no longer nested correctly:
accRev([F,S,T],A,R) :- F \= [_|_], S \= [_|_], T \= [_|_],
accRev([],[[F,S,T]|A],R).
accRev([H|T],A,R) :- accRev(H,[],R1), accRev(T,[],R2), append(R2,R1,R).
accRev([],A,A).
rev(A,B) :- accRev(A,[],B).
I would appreciate help in correcting the code to preserve the correct nesting of lists. Thanks!
Two suggestions. First, here's one (rev_lists/2) which uses a bunch of SWI-PROLOG built-ins:
rev_lists(L, RL) :-
forall(member(M, L), is_list(M)), !,
maplist(rev_lists, L, L0),
reverse(L0, RL).
rev_lists(L, L).
This one works by testing if all elements of a list L are themselves lists (M); if so, it will recursively apply itself (via maplist) over all individual sub-lists, else it will return the same list. This has the required effect.
Secondly, here's rev_lists/2 again, but written such that it doesn't rely on built-ins except member/2 (which is common):
rev_lists(L, RL) :-
reversible_list(L), !,
rev_lists(L, [], RL).
rev_lists(L, L).
rev_lists([], Acc, Acc).
rev_lists([L|Ls], Acc, R) :-
( rev_lists(L, RL), !
; RL = L
),
rev_lists(Ls, [RL|Acc], R).
reversible_list(L) :-
is_a_list(L),
\+ (
member(M, L),
\+ is_a_list(M)
).
is_a_list([]).
is_a_list([_|_]).
It's basically the same strategy, but uses an accumulator to build up reverse lists at each level, iff they are comprised exclusively of lists; otherwise, the same list is returned.