Prolog recursively applying a function to a list - prolog

I have a list of lists and I want to remove duplicates from all of them.
I already have the code for removing duplicates from a list.
The only thing I need to do is to apply this to the whole list and return it via the second argument.
This is what I tried.
rem_list_dup([], _).
rem_list_dup([H | T], Final) :-
remove_duplicates(H, List), /* This already works. Removes all duplicates from list H. List is the resulting list */
rem_list_dup(T, [List | Final]).
EDIT:
Example Input:
[[a, b, a], [b, b, c], [c, c, c]]
Output:
[[a, b], [b,c], [c]]
The order does not matter.

Since you understand basics of using recursion and a base case down and know how to use a tracer, you should be able to quickly understand the few changes here without needing a walk thru of the why.
remove_duplicates(List,Set) :-
list_to_set(List,Set).
rem_list_dup([],[]).
rem_list_dup([H0|T0],[H|T]) :-
remove_duplicates(H0,H),
rem_list_dup(T0,T).
:- begin_tests(rem_list_dup).
rem_list_dup_test_case_generator([[a, b, a], [b, b, c], [c, c, c]],[[a, b], [b,c], [c]]).
test(1,[forall(rem_list_dup_test_case_generator(List0,List))]) :-
rem_list_dup(List0,List).
% Based on comment by #false
test(2,[forall(rem_list_dup_test_case_generator(List0,List))]) :-
maplist(list_to_set,List0,List).
:- end_tests(rem_list_dup).
Example run using SWI-Prolog
?- consult("C:/Users/Groot/Documents/Projects/Prolog/SO_question_182.pl").
true.
?- run_tests.
% PL-Unit: rem_list_dup .. done
% All 2 tests passed
true.

Related

Check if list is the reverse of the other list in prolog

I'm trying to write a prolog predicate called flip(Lst1, Lst2) that holds if the first list is the reverse of the second list and vice versa.
For instance: flip([a, b, c, d], [d, c, b, a]). and flip([a], [a]).
should both return true, while flip([a, b], [b, c]).
should return false.
My first thought was to reverse the first list and then compare it with the second list, but I wonder if there is a more efficient way of doing this.
Just figured out this works
flip([],[]).
flip([H|T],R) :-
flip(T,RevT),
append(RevT,[H],R).
You can use reverse built-in for this.
flip(List1,List2):-
reverse(List1,ReverseList),
List2=ReverseList.
Examples:
?- flip([a,b,c],[c,b,a]).
true
?- flip([c],[c]).
true
?- flip([a,b,c],[c]).
false
?- flip([],[]).
true

Prolog: how can I change the output of combinations(N, [H|T], P) to return a list of pairs, rather than just the first one before ;?

Prolog: How can I change the output of combinations(N, [H|T], P) to return a list of pairs, rather than just the first one before ; ? The program works well as long as I press ; in the command line, but I want to return directly a list of pairs.
comb(1, [H|_], [H]).
comb(N, [H|T], [H|C]) :- N1 is N - 1, N1 > 0, comb(N1, T, C).
comb(N, [_|T], C):- comb(N, T, C).
This is my program. Thank you very much!
You are looking for findall/3.
findall(+Template, :Goal, -Bag)
Create a list of the instantiations Template gets successively on backtracking over Goal and unify the result with Bag. Succeeds with an empty list if Goal has no solutions. findall/3 is equivalent to bagof/3 with all free variables bound with the existential operator (^), except that bagof/3 fails when Goal has no solutions.
Example:
?- findall(X, comb(2, [a,b,c,d], X), Xs).
Xs = [[a, b], [a, c], [a, d], [b, c], [b, d], [c, d]].

Intersection in SWI-Prolog

I am new to Prolog and I am having a little bit of trouble understanding recursion. I am trying to write a relation that finds the intersection of two sorted lists without using SWI's built-in intersect. I've used trace to see what's happening, and it's behaving as I expect up until the point where I want it to terminate and return the new list that contains the intersection. This makes me think that my base case is wrong. I've played around with several different ways of forming the base case, but it hasn't been fruitful. I've been using the lists [1, 2, 3, 4] and [2, 4, 6] as test cases with the following relations (the base case on top is just one I threw in as a placeholder... it doesn't work at all):
intersectS([], [], []).
intersectS([A | B], [C | D], Z) :- A < C, intersectS(B, [C | D], Z).
intersectS([A | B], [C | D], Z) :- A > C, intersectS([A | B], D, Z).
intersectS([A | B], [C | D], Z) :- A = C, append(Z, [A], Y), intersectS(B, D, Y).
Any help is appreciated. I've seen examples where the cut (!) operator is used alongside the member/non-member, but I'm supposed to take advantage of the fact that the lists are sorted so I thought I would try this approach. Thanks in advance.
Overall, the solution you have is partway there (as you observed). There are two areas that need fixing I think. One is, as you pointed out, the "base case". I would do it as follows:
intersectS([], _, []).
intersectS(_, [], []).
In other words, anything intersected with an empty list is empty.
The second trouble spot is the clause for A = C. You have:
intersectS([A | B], [C | D], Z) :- A = C, append(Z, [A], Y), intersectS(B, D, Y).
Which says that if the heads of the two lists match, then the intersection (Z) appended with [A] (the matching head) is the intersection of the tails of the two lists. This doesn't seem correct. I think you want to say that the intersection (Z) is the intersection of the tails B and D appended to [A], which looks like this:
intersectS([A | B], [C | D], Z) :- A = C, append([A], Y, Z), intersectS(B, D, Y).
So the whole thing looks like:
intersectS([], _, []).
intersectS(_, [], []).
intersectS([A | B], [C | D], Z) :- A < C, intersectS(B, [C | D], Z).
intersectS([A | B], [C | D], Z) :- A > C, intersectS([A | B], D, Z).
intersectS([A | B], [C | D], Z) :- A = C, append([A], Y, Z), intersectS(B, D, Y).
You can take it a step further and get rid of the append since you're just dealing with one element. append([A], Y, Z) is the same as saying Z = [A|Y]. So you can replace the last clause with simply:
intersectS([A | B], [C | D], [A | Y]) :- A = C, intersectS(B, D, Y).
Running your test case:
?- intersectS([1, 2, 3, 4], [2,4,6], L).
L = [2, 4] ;
false.
?-

Prolog , Append with no repititions

Hey I'm trying to append two list with no "double" members
for example
A = [a, b, c]
B = [x, c, q]
then ->
append2(A,B,P)
P= [a,b,c,x,q]
I write this code, but it doesn't work...
not_member(_, []).
not_member(X, [Y|Ys]) :- X \= Y, not_member(X, Ys).
append2(A, [], A).
append2([], A, A).
append2([h1|ls], B, [h1|P]) :- not_member(h1, B), !, append2(ls, B, P).
append2([h1|ls], B, P) :- member(h1, P), append2(ls, B, P).
Thanks for helping :)
Assuming there are no variables in your input lists, but allowing duplicates in each list you may write:
append2(A,B,C):-
findall(Item, append2_item(A,B,Item), C).
append2_item(A,_,ItemA):-
append(HeadA, [ItemA|_], A),
\+ member(ItemA, HeadA).
append2_item(A,B,ItemB):-
append(HeadB, [ItemB|_], B),
\+ member(ItemB, HeadB),
\+ member(ItemB, A).
First clause of append2_item/3 selects (ordered) distinct items from the first list. Second clause of append2_item/3 selects (ordered) distinct items from the second list which are not present in the first list.
append2/3 just collects those elements.
Test case:
?- append2([a,b,c,a],[x,c,q,x],C).
C = [a, b, c, x, q].
Check out the pure code in my answer
to the related question "intersection and union of 2 lists"!
Telling from your requirements, predicate list_list_union/3 is just what you are looking for:
?- list_list_union([a,b,c],[x,c,q],Ls).
Ls = [a,b,c,x,q]. % succeeds deterministically
list_list_union/3 is monotone, so we get sound answers
even when using non-ground terms:
?- As = [_,_,_], Bs = [_,_,_], list_list_union(As,Bs,Ls), As = [a,b,c], Bs = [x,c,q].
As = [a,b,c], Bs = [x,c,q], Ls = [a,b,c,x,q] ; % logically sound result
false.

Prolog compute the permutation

I'm writing a permutation function [a,b]-->[[[a], [b]], [[a, b]]
I have this so far, but it doesn't work.
perm([],[]).
perm(L,[H|T]) :- append(V,[H|U],L), append(V,U,W), perm(W,T).
Given your example, it looks like you might actually be wanting the powerset, not the permutation, of the given list.
For instance, the powerset of [a,b] is the set {[a,b], [a], [b], []}.
To compute the powerset of a list of items in Prolog, look at this answer by #gusbro. If this helps you, also please upvote that answer.
If you want all solutions of the powerset of a list L at once, you can wrap the call to powerset/2 in a findall/3 call like this:
?- findall(S, powerset(L, S), Ss).
If, on the other hand, you're after the partitions (as you've mentioned in one of your earlier edits), consider the following:
partition(L, PL) :-
partition(L, [], PL).
partition([], [], []).
partition([X|Xs], As, R) :-
% add X into the new partition...
append(As, [X], NewAs),
partition(Xs, NewAs, R).
partition(L, [A|As], [[A|As]|R]) :-
% ...or, collect the current non-empty partition
partition(L, [], R).
The predicate partition/2 takes a list and returns all partitions, as you've described. For example:
?- partition([a,b,c],L).
L = [[a, b, c]] ;
L = [[a, b], [c]] ;
L = [[a], [b, c]] ;
L = [[a], [b], [c]] ;
false.
Really? It seems to work in SWI-Prolog:
?- [user].
|: perm([],[]).
|: perm(L,[H|T]) :- append(V,[H|U],L), append(V,U,W), perm(W,T).
|: % user://1 compiled 0.00 sec, 3 clauses
true.
?- perm([a,b,c], X).
X = [a, b, c] ;
X = [a, c, b] ;
X = [b, a, c] ;
X = [b, c, a] ;
X = [c, a, b] ;
X = [c, b, a] ;
false.
?- perm([a,b,c,d], X).
X = [a, b, c, d] ;
/* trimming 22 solutions */
X = [d, c, b, a] ;
false.
This also yields the number of answers you'd expect: 3! = 6, 4! = 24. What's not working for you?
Quick note: Prolog doesn't offer functions, but relations.
In this case, perm/2 will hold true when the arguments are one the permutation of the other.
I find this definition more readable than your.
perm([], []).
perm([E|Es], P) :-
perm(Es, Q),
select(E, P, Q).
It's almost the same as that of permutation/2 SWI-Prolog, but hides a bug...

Resources