Take elements from one list and append to other - prolog

I want a function that will take two lists A and B and return lists Aout and Bout, such that elements from the beginning of A up to a given element (say the atom 'a') have been removed and appended to the end of B, discarding the character. My attempt below:
% usage: take_while(A, Aout, B, Bout)
take_while([], [], B, B).
take_while(['a'|As], As, B, B).
take_while([A|As], As, B, Bout) :-
append(B, [A], Bout),
%take_while(???
The last clause might be the wrong approach. How do I do this?

Looks like you need to simply add the call to take_while to that last clause: (Actually, I am not sure why the second parameter is needed so I'm removing it from this answer).
take_while([], [], B, B).
take_while(['a'|As], As, B, B).
take_while([A|As], ARem, B, Bout) :-
append(B, [A], BTemp), take_while(As, ARem, BTemp, Bout).

Related

Inclusion function in prolog for multisets

I want to write a prolog program that checks if a list is included in other list.
Multiple elements matter
This is what I wrote but it fails for the input - inclusion([a,b,b,d],[a,b,b,c,c,d,d]).This should return true. other examples - inclusion([a, b, b, b, d], [a, b, b, c, c, d, d])
should return false.
inclusion([],_).
inclusion([X|L],Set):-
member(X,Set),delete(Set,X,Set2), inclusion(L,Set2).
Above is the code that I wrote. The logic was check if the first element is in Set.
Then delete that element from the set and check if the remaining list is in the Set.
But this doesn't seem to work
This predicate does not work with entries in the first list that appear multiple times, because delete removes all appearances of Set. Use select to remove only the first element that matches:
inclusion([],_).
inclusion([X|L],Set):-
member(X,Set),select(X, Set, Set2), inclusion(L,Set2).
Gives you:
?- inclusion([a,b,b,d],[a,b,b,c,c,d,d]).
true .
?- inclusion([a,b,b,b,d],[a,b,b,c,c,d,d]).
false.
inclus([],[]).
inclus([],[_|_]).
inclus([H1|T1],[H1|T2]) :- inclus(T1,T2).
inclus([H1|T1],[H2|T2]) :- \=(H1,H2),inclus([H1|T1],T2).
Note: the other answer defining the inclusion/3predicate will return true for the following goal:
?- inclusion([b, c, a],[a,b,c]).
true
I dont think this is what you want.

obtaining the rest of a clause as a list and creating a list of lists

let's say that I have some clauses, two of which are the following:
has_basket('Sarah', 'bigBasket','apple','grape').
has_basket('Sarah', 'bigBasket','orange','berry').
How can I write a rule named
all_baskets(S,L).
which will give me the list of all the baskets that person S has in the following form?
for example
all_baskets('Sarah',L).
will give us:
L=[['bigBasket','apple','grape], ['bigBasket','orange','berry']]
Whenever you consider a Prolog programming problem, you need to clarify the aspects that are important to you.
Think of the order of the two elements in the list. Are they in that order because they are in alphabetical ascending order, or is it just luck?
What do you expect for all_baskets('Nemo', L)? Should this fail, or rather answer L = []?
What do you expect for all_baskets(P, [])?
If you say 1 alphabetical, 2 fail, and 3 fail, then setof/3 is the way to go.
has_basket('Sarah', bigBasket, apple, grape).
has_basket('Sarah', bigBasket, orange, berry).
has_basket('Bernie', bigBasket, orange, apple). % another fact
all_baskets(P, L) :-
setof([A, B, C], has_basket(P, A, B, C), L).
?- all_baskets(P, []).
false.
?- all_baskets('Nemo', L).
false.
?- all_baskets(P, L).
P = 'Bernie', L = [[bigBasket,orange,apple]]
; P = 'Sarah', L = [[bigBasket,apple,grape],[bigBasket,orange,berry]].
We can make use of the findall/3 predicate [swi-doc]:
all_baskets(S,L) :-
findall([A, B, C], has_basket(S, A, B, C), L).
Here [A, B, C] is the "template" of the items in the list, has_basket(S, A, B, C) the "goal" that needs be fullfilled, and L the list of results.

Find all positions of a value in a list in Prolog

My assignment is this: Write a program that reads an integer x and a list of integers L; then locate the list of all positions of x into L, and return the resulting list. For example, for x=2 and L=[1,2,3,4,2,5,2,6] the program should return the list R=[2,5,7].
So far, I've been able to write an indexOf predicate:
indexOf([E|_], E, 1).
indexOf([_|T], E, I) :- indexOf(T, E, I2), I is I2 + 1.
However, this doesn't "return" a list. So:
indexOf([a,b,c,a,d], a, R).
R = 1;
R = 4
I'd like to do something like this:
findAll([a,b,c,a,d], a, R).
R = [1, 4]
But I'm not sure how to collect the values into a list.
This is a school assignment, so I'd appreciate just a nudge in the right direction.
A nudge: you find the indices, but you don't collect them.
indices(List, E, Is) :-
indices_1(List, E, Is, 1).
For an empty list, the list of indices is empty,
and the element doesn't matter
indices_1([], _, [], _).
If the element is like the head, collect the index.
indices_1([E|Xs], E, [I|Is], I) :-
I1 is I + 1,
indices_1(Xs, E, Is, I1).
This needs another clause to work properly.
EDIT:
One way to do it would be:
indices_1([X|Xs], E, Is, I) :- dif(X, E),
I1 is I + 1,
indices_1(Xs, E, Is, I1).
In the previous clause, the head of the list and the Element are unified. In this clause, they are explicitly different. This means that only one of the two clauses can be true for an element of the list in the first arguemnt.
EDIT:
Another way to do that is to use findall and nth1:
indices(List, E, Is) :-
findall(N, nth1(N, List, E), Is).

Prolog Subtract List Unification

I am trying to subtract one list from another in prolog. In my program the input list have blank spaces in them (e.g. [1,2,_,4])
I am getting the following output:
?- subtract([1,2,3,4],[3,4,_],L).
L = [2].
when I want my output to be
L = [1,2].
So my question is how can I prevent the blank spaces from unifying with other elements? Have been stuck on this for a while.
Assuming you want the "blank spaces" to be ignored, you can simply make a version of each list with those removed and compute their difference:
listWOblanks( [], [] ).
listWOblanks( [H|T], Tx ) :- var(H), !, listWOblanks( T, Tx ).
listWOblanks( [H|T], [H|Tx] ) :- listWOblanks( T, Tx ).
If, when the first list has a blank and the second does not, you need the result to still have a blank, you could modify the above to add a 3rd argument that tells you if any blanks were removed so you can correct the difference accordingly. I believe SWI-Prolog has a predicate, ground, which will tell you if a term has no variables in it, which would do the job w/o needing to modify listWOblanks.
larsmans is correct, the _ is an anonymous variable, and the definition of lists:subtract/3 (which I'm assuming you're using in SWI-Prolog) will always unify them to ground list members because of it's definition using memberchk/2.
If you want subtract behaviour where variables are to be treated like ground terms, then you can redefine it like this:
subtract2([], _, []) :- !.
subtract2([A|C], B, D) :-
var_memberchk(A, B), !,
subtract2(C, B, D).
subtract2([A|B], C, [A|D]) :-
subtract2(B, C, D).
Note that subtract2/3 here is nearly the same as the definition of lists:subtract/3 (try listing(subtract). to see for yourself). The only difference is the list membership predicate, var_memberchk/2, which is defined like this:
var_memberchk(A0, [A1|_]) :-
A0 == A1, !.
var_memberchk(A0, [_|R]) :-
var_memberchk(A0, R).
This checks to see if a variable, atom or term is in the list. So, trying this we get:
?- subtract2([1,2,3,4],[3,4,_],L).
L = [1, 2].
Note that it still works if we name the variables, as you'd expect:
?- subtract2([1,2,A,3,B,4],[3,A,4],L).
L = [1, 2, B].
It also works if we explicitly give names to anonymous variables, like this:
?- subtract2([1,2,_A,3,_B,4],[3,_A,4],L).
L = [1, 2, _B].
Finally, note that since _ doesn't have a name, subtract2/3 will never be able to match it to other anonymous variables in either list, for example:
subtract2([1,2,_,4],[3,_,4],L).
L = [1, 2, _G415].
Where _G415 is the anonymous global variable denoted by the _ in the first input list. The second is a different global variable (like _G416, for instance), so could never match the anonymous variable in the first list.
Another way:
% Uses list catenation to generate sublists /subtraction
conc([], L, L).
conc([X|L1], L2, [X|L3]) :-
conc(L1, L2, L3).
% Finds all list members that have values and then
% use list catenation to generate the sublists
subtract(L1, L2, L3) :-
findall(D, (nth0(N, L2, D), nonvar(D)), PureL2),
conc(L3, PureL2, L1).
This assumes that only one list has '_', but you could do the same findall for L1 if both lists have the same problem.

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.

Resources