Prolog - get the first list from a list of lists - prolog

I've got a list consisting of smaller lists inside of it, each list consisting of 2 items:
[[a,1],[b,2],[c,3]]
I'm using a function called take(1,L,R) to take the first item from list L and return the item R. The code for the take function is here:
take(0,X,X).
take(N,[H|T],[H|R]):-
N>0, M is N-1,
take(M,T,R).
At the moment a run may look like this:
1 ?- take(1,[[a],[b],[c]],Taken).
Taken = [[a], [b], [c]]
Which is the same as the input! This is the same for a "regular" 1-level-depth list:
2 ?- take(1,[a,b,c],Taken).
Taken = [a, b, c]
Question:
The question for you is how can I make the result look like:
1 ?- take(1,[[a],[b],[c]],Taken).
Taken = [a]
I want to return the first N items of the list I send it.

Your base case take(0, X, X). is doing exactly what it says -- given any value X, the result is X. What I think you were trying to say is take(1, [H|T], H). (which yields the first element of a list).
What I think you're actually after is take(0, _, [ ]). which yields an empty list when "taking" 0 items from any list. This works well with your existing recursive case.
You say that you want to get the "first N items of the list" -- such a result must be stored in a list of N items. It follows that take(1, [a, b, c], Taken) would yield Taken = [a], not Taken = a. Similarly, take(1, [[a], [b], [c]], Taken). would yield Taken = [[a]].. To special-case the take(1, ...) form to return the first item only (without it being wrapped in a list) would break your recursion.

Related

Prolog question, manipulate list of lists

I'm new to Prolog and have a question:
Suppose I have a list of lists; [list1, list2, list3,..., list_n]
If list_j contains list_i, i.e. every variable in list_i occurs in list_j, then remove list_j.
For example, if the input is
[[a,b,c], [a,c], [a,d], [a,d,e]]
the output should be
[[a,c], [a,d]]
because [a,b,c] contains [a,c] and [a,d,e] contains [a,d].
How to implement this in SWI-Prolog? Any help is appreciated.
First of all, SWI already has a predicate to check whether a list is "contained" (in terms of set-inclusion) in another list: subset/2 (http://www.swi-prolog.org/pldoc/man?predicate=subset/2).
Now you can use that to check whether or not to remove a specific list from all lists:
remove(Lists, List) :-
member(List, Lists),
member(Sublist, Lists),
Sublist \= List,
subset(Sublist, List).
Read as: remove List from Lists if it is a member of Lists and there is also another (confirmed by \=) member of Lists (call it Sublist), which is a subset of List.
?- remove([[a,b,c], [a,c], [a,d], [a,d,e]], L).
L = [a, b, c] ;
L = [a, d, e] ;
Now you can use that to answer your original question:
remaining(Lists, Remaining) :-
bagof(List,
(
member(List, Lists),
\+ remove(Lists, List)
),
Remaining).
Let these lists be Remaining from Lists which are members of the original list of Lists and are not (\+) to be removed.
?- remaining([[a,b,c], [a,c], [a,d], [a,d,e]], Remaining).
Remaining = [[a, c], [a, d]].

Prolog, List of lists contains another list exactly

What I basically want to achieve is, that given a list of lists A, I want a predicate that checks if the elements of a list B are exactly contained in list A.
So for example:
A = [[1,2],[3,4],[5],[]]
B = [1,2,3,4,5]
and
A = [[1,2],[3,4],[5],[]]
B = [2,5,3,4,1]
Would result to true, but
A = [[1,2],[3,4],[5],[]]
B = [1,2,3,4]
and
A = [[1,2],[3,4],[5],[]]
B = [1,2,3,4,5,6]
would both result to false.
is this possible in prolog?
Exactly means:
Order doesn't matter, it just has to contain all the elements.
Also, imagine that the B list doesn't contain duplicates.
So if A would contain duplicates, we should get false as a result.
The trivial answer:
?- flatten([[1,2],[3,4],[5],[]], [1,2,3,4,5]).
true.
?- flatten([[1,2],[3,4],[5],[]], [1,2,3,4]).
false.
?- flatten([[1,2],[3,4],[5],[]], [1,2,3,4,5,6]).
false.
Or,
foo(A, B) :- % because I don't know how to call it
flatten(A, B).
If you are talking about sets:
bar(A, B) :-
flatten(A, A_flat),
sort(A_flat, A_sorted),
sort(B, A_sorted).
You can use msort/2 if you don't want to remove duplicates.
If the question is, "how do I implement flatten/2", you can find several answers on SO.

Why prolog outputs a weird tree-like list?

In this Prolog code I intend to list the first N primes,
(...)
biggerPrime(N,P) :-
isPrime(N),
P is N,
!.
biggerPrime(N,P) :-
N1 = N+1,
biggerPrime(N1,P).
primeListAcc(0,A,R,R) :- !.
primeList(N,L) :-
primeListAcc(N,1,[],L).
primeListAcc(N,A,L,R) :-
N1 is N-1,
biggerPrime(A,P),
A1 is P+1,
primeListAcc(N1,A1,[P|L],R).
And it works fine if I want the list ordered backwards:
?- primeList(5,L).
L = [11, 7, 5, 3, 2].
But if I change the last line of the code from [P|L] to [L|P] like this:
primeListAcc(N,A,L,R) :-
N1 is N-1,
biggerPrime(A,P),
A1 is P+1,
primeListAcc(N1,A1,[L|P],R).
I get:
?- primeList(5,L).
L = [[[[[[]|2]|3]|5]|7]|11].
What am I missing? This is driving me mad!
Recall that a list is either the empty list [] or a term with functor '.' and two arguments, whose second argument is a list. The syntax [P|Ps] is shorthand notation for the term '.'(P, Ps), which is a list if Ps is a list (as is the case in your example). The term '.'(Ps, P), on the other hand, which can also be written as [Ps|P] (as you are doing), is not a list if P is not a list. You can obtain a reverse list with reverse/2.
Great, so you've discovered the problem of adding elements to the end of a list. In Prolog, we can do it with
add(X,L,Z):- L=[X|Z].
wait, what? How to read this? We must know the calling convention here. We expect L and Z to come in as uninstantiated variables, and we arrange for L from now on to point to a newly created cons node with X at its head, and Z its tail. Z to be instantiated, possibly, in some future call.
IOW what we create here is an open-ended list, L = [X|Z] = [X, ...]:
primeList(N,L) :-
primeListAcc(N,1,[],L).
primeListAcc(N,A,Z,L) :- N > 0, % make it explicitly mutually-exclusive,
N1 is N-1, % do not rely on red cuts which are easily
biggerPrime(A,P), % invalidated if clauses are re-arranged!
A1 is P+1,
L = [P|R], % make L be a new, open-ended node, holding P
primeListAcc(N1,A1,Z,R). % R, the tail of L, to be instantiated further
primeListAcc(0,A,R,R). % keep the predicate's clauses together
We can see now that Z is not really needed here, as it carries the [] down the chain of recursive calls, unchanged. So we can re-write primeListAcc without the Z argument, so that its final clause will be
primeListAcc(0,A,R):- R=[].
Keeping Z around as uninstantiated variable allows for it to be later instantiated possibly with a non-empty list as well (of course, only once (unless backtracking occurs)). This forms the basis of "difference list" technique.
To answer your literal question - here, consider this interaction transcript:
1 ?- X=[a|b].
X = [a|b]
2 ?- X=[a|b], Y=[X|c].
X = [a|b]
Y = [[a|b]|c]
the [a|b] output is just how a cons node gets printed, when its tail (here, b) is not a list. Atoms, as numbers, are not lists.

Prolog - return value from base case

Ok, here's the deal:
I've got two piles of shirts
I want to take a random shirt from each pile and put them in a new pile
Then get the new pile out
And here is the code:
mix([],[],_).
mix(P1,P2, Pile):-
takeshirt(P1,1,Taken1,Rem1), takeshirt(P2,1,Taken2,Rem2), #Take one
append(Pile,Taken1,New), append(New,Taken2,NewPile), #Put both of them
mix(Remain1,Remain2,NewPile).
This is what the result look like:
1 ?- mix([a,b],[c,d],NewPile).
NewPile = [] .
I want it to look like:
1 ?- mix([a,b],[c,d],NewPile).
NewPile = [b, d, a, c] .
Or whatever the result is. I checked via the graphical debugger and found out that when the final call to mix happens, the bindings are:
P1 = Taken1 = [b]
P2 = Taken2 = [c]
Pile = [a, d]
Rem1 = Rem2 = []
New = [a, d, b]
NewPile = [a, d, b, c] #<--- Interresting
So the wanted value is in NewPile when the final call to:
mix([],[],_).
happens. After this is it collapses like a house of cards.
So the question is:
mix([],[],_).
I'd like to return the _ value from the base case, this rule mix is actually used from a higher instance where I send in two piles and get the new pile out.
Update:
To clarify some comments about the takeshirt rule, here it is:
takeshirt(_,0,[],_).
takeshirt(List,Number,[Element|Taken],Remain) :- N > 0,
length(List,Len),
Index is random(Len) + 1,
removeshirt_at(Element,List,Index,Remain),
Number1 is Number - 1,
takeshirt(Remain,Number1,Taken,Remain).
Consider the following modifications to your code:
mix([], [], []) :- !.
mix(P1, P2, Pile) :-
takeshirt(P1, 1, Taken1, Rem1),
takeshirt(P2, 1, Taken2, Rem2),
append(Taken1, Taken2, Pile0),
mix(Rem1, Rem2, Pile1),
append(Pile0, Pile1, Pile).
It seems you need to accumulate the 'shirts' (as list atoms). Here, we are recursively appending them onto the third argument of mix/3 (Pile), until the base case (the first clause) is hit when both input lists are empty lists (note that the cut ! is necessary here as the binding pattern for the second clause matches the first, so we want to exclude it). The behaviour of the second clause, which takes a shirt from each input list for every step, requires that they must have been of equal length to start with.
To test this, I used the following definition of takeshirt/4:
takeshirt(Ps, _, [P], Rem) :-
select(P, Ps, Rem).
Note that the second argument here is unused, as select/3 is being used to take a single element (a shirt) from the list, and return the remainder. The absence of a cut (!) after the select allows this predicate to backtrack in selecting all other elements (shirts) from the list. If we now execute your example query with this definition, we can get:
1 ?- mix([a,b],[c,d],NewPile).
NewPile = [a, c, b, d] ;
NewPile = [a, d, b, c] ;
NewPile = [b, c, a, d] ;
NewPile = [b, d, a, c] ;
false.
...we can see that mix/3 enumerates all possible 'piles' on backtracking by taking a shirt from the first pile (first input list), then a shirt from the second pile (second input list), and so on, until both input lists are empty. If your definition of takeshirt/4 doesn't leave choice-points, (is non-backtracking), then you could only get one solution, if any.

Pattern matching list of lists

I have a problem where I have a list like this:
[[el1, el2, el3],
[el4, el5, el6],
[[el7, el8, el9], [el10, el11, el12], ..... , [elxx, elyy, elzz]],
[el, el, el]...]]
I want to pattern match the inner list of lists, the
[el7, el8, el9], [el10, el11, el12], ..... , [elxx, elyy, elzz]
How can this be done?
As of now I patternmatch the other elements with
my_method([[El1, El2, El3] | Rest]).
UPDATE
I want to pattern match if the next item of the list is a list of lists - I will be iterating over this list, removing item after item. There can be any number of lists of lists, and they can contain any number of items. They can also contain lists of lists. In fact, I will recursively call the same processing method whenever I come upon a list of lists.
All bottom level lists will have three elements, however these elements might be different:
[1, p, neg(5,6)]
[5, neg(7,6), assumption]
You said "I will be iterating over this list, removing item after item", so here's code that does just that, assuming an "item" is a three-element list of non-lists.
nested_member(X,X) :-
X = [A,_,_],
\+ is_list(A).
nested_member(X,[L|_]) :-
nested_member(X,L).
nested_member(X,[_|L]) :-
nested_member(X,L).
This can be used to backtrack over the "items":
?- nested_member(X,[[el1, el2, el3], [el4, el5, el6],
[[el7, el8, el9], [el10, el11, el12],[elxx, elyy, elzz]]]).
X = [el1, el2, el3] ;
X = [el4, el5, el6] ;
X = [el7, el8, el9] ;
X = [el10, el11, el12] ;
X = [elxx, elyy, elzz] ;
false.
I you want, you can even find out how deep in the list the items were found:
nested_member(X,L,D) :-
nested_member(X,L,0,D).
nested_member(X,X,D,D) :-
X = [A,_,_],
\+ is_list(A).
nested_member(X,[L|_],D0,D) :-
D1 is D0+1,
nested_member(X,L,D1,D).
nested_member(X,[_|L],D0,D) :-
nested_member(X,L,D0,D).
You can use predicates similar to the following.
qualify([], []).
qualify([H|T], [HN|TN]) :- qualify_one(H, HN), qualify(T, TN).
qualify_one([H|_], N) :- qualify_one(H, N1), N is N1 + 1, !.
qualify_one(_, 0).
What qualify does is for each member of the list to find out on what level of the scale “not a list”, “simple list”, “list of lists”, … it is, based on the first item.
Example:
?- qualify([1,[2,3,3],[[4,5,6], [7,8,9]]], NS).
NS = [0, 1, 2].

Resources