Append lists prolog - list

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!

Related

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

Insert elements of one list to another list recursively in Prolog

I'm still learning the concept of recursion.
I want to add elements of one list to the head of another list recursively while eliminating any duplicates. The code I used work fine for an atom. This is the code without recursion:
insert(H,L,[H|L]):-
not(member(H,L)).
insert(H,L,L):-
member(H,L).
However when I try recursion, I don't get the expected output. I understand I'm writing the insert/3 predicate wrong.
insert([H|T],[H1|T1],[H,H1|T1]):-
not(member(H,[H1|T1])):-
insert(T,[H,H1|T1],L).
insert([H|T],[H1|T1],[H1|T1]):-
member(H,[H1|T1]),
insert(T,[H1|T1],L).
insert([],L,L).
I'd appreciate any ideas on how to rectify the error in the above code.
Your original insert could be composed within another "insert_all" clause. For example...
% insert_all(NEW_ELEMENTS, LIST_TO_ADD_ELEMENTS_TO, OUTPUT)
insert_all([], O, O).
insert_all([X | T], I, O) :-
insert(X, I, ITMP),
insert_all(T, ITMP, O).
Example output:
1 ?- insert_all([a,b,c], [1,2,c], O).
O = [b, a, 1, 2, c].
You could also simplify insert to avoid having to do the not(member(...)) check...
insert(H,L,L):-
member(H,L), !.
insert(H,L,[H|L]).
The "cut" tells Prolog to not bother trying alternatives if preceding sub-clauses in the insert clause succeed. So if member fails, it will just do the second clause.

Why does my Pradicate my_flatten/2 not flatten a nested list structure? (Prolog)

The predicate i wrote flattens a simple list like List=[a,b,c,[d,e],f],
but not a list like List2 = [a,b,[[c,d],e],f]. Here is my code:
my_flatten([], []).
my_flatten([H|T], R):- not(is_list(H)), my_flatten(T, R1), append([H], R1, R).
my_flatten([H|T], R):- is_list(H), my_flatten(T, R1), append(H, R1, R).
My idea is to check whether the head is a list or not and depending on this decision to go through recursion and append the tail to the head.
Am I missing an important point?
Am I missing an important point?
yes, of course. Boris is right that you will learn more if you try to find the problem yourself. Just an hint: you must recurse on the head, when it's a list, to get it flattened.
After that (just add a call in proper place in last clause) and you'll get
?- my_flatten([a,b,[[c,d],e],f], L).
L = [a, b, c, d, e, f] ;
false.

Reverse list of lists

I have a problem with my prolog code. I need to reverse all atomic elements of list.
Example: [1,2,[3,4]] -> [[4,3],2,1]
My solution:
myReverse([], []).
myReverse([H|T], X) :- myReverse(T, RT), myAppend(RT, H, X).
But it only gives me: [[3,4],2,1]
I think, I need to use is_list function and recursive call list if it's not atomic... but I am stuck... do you guys know how to write it?
Nearly. Consider this solution:
myReverse([], []) :- !.
myReverse([H|T], X) :-
!,
myReverse(H, NewH),
myReverse(T, NewT),
append(NewT, [NewH], X).
myReverse(X, X).
The first clause is the base case, which includes a cut (!) to exclude choices left because of the last clause.
The second clause reverses the head H, which may be an atom or a list. If H is an atom, the recursive subgoal after the cut evaluates with the last clause, and atoms are passed through unchanged. If H is a list, it is evaluated with the second clause and all elements are reversed. The next subgoal does the same with the remainder of the list (the tail, T), then are finally concatenated using the built-in append/3. Note that the new head element NewH is singular, so needs to be added to a singleton list structure as [NewH] as per the definition of append/3 which operates on lists.
The last clause passes all other things (i.e., atoms, numbers, etc. - anything that isn't a list or a variable) through unchanged.
revall(L, Y) :-
revall(L, [], Y).
revall([], Y, Y).
revall([H|T], T2, Y) :-
is_list(H),!,
revall(H, Hr),
revall(T, [Hr|T2], Y).
revall([H|T], T2, Y) :-
revall(T, [H|T2], Y).
here without append

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.