extending a list of lists by a single element - prolog

I am trying to solve the following question in ProLog. I am a beginner.
Define a predicate extend such that if Xss and Yss are lists of
lists then extend(X, Xss, Yss) holds if Yss can be obtained by adding the
element X to the end of every element in Xss, e.g
?- extend(g, [[e], [b, c, f], [k, h]], Yss).
Yss = [[e, g], [b, c, f, g], [k, h, g]]
I have attempted this with the following, but there is an error message :
extend(X, [], []).
extend(X, [[Firstxss,_] | Restxss], Yss) :-
Firstxss is [Firstxss,_|X],
Yss is [Yss | [Firstxss,_]],
Xss is Restxss,
extend(X, Xss, Yss).
I have input the following :
?- extend(g, [[e], [b, c, f], [k, h]], Yss).
and it returns :
false.
I think I have a valid input and I do not understand why it is returning as false.

Since you want to do the same thing with every element of the outer list, this is quite a beautiful task for maplist/3. You can use append/3 to extend a list by an additional element like so:
?- append([1,2],[element],Z).
Z = [1, 2, element].
However, you'll want to have append/3 with two lacking arguments in maplist/3, therefore it would be opportune to have the first argument appended to the second argument. To realize that, you could write an auxiliary predicate that calls append/3 with the first two arguments flipped, e.g:
flippedappend(X,Y,Z) :-
append(Y,X,Z).
Building on this, you could define the actual relation like so:
x_lists_extended(X,Xss,Yss) :-
maplist(flippedappend([X]),Xss,Yss).
Your example query yields the desired result:
?- x_lists_extended(g, [[e], [b, c, f], [k, h]], Yss).
Yss = [[e, g], [b, c, f, g], [k, h, g]].
Note that you can also use this predicate the other way around:
?- x_lists_extended(X, Xss, [[e, g], [b, c, f, g], [k, h, g]]).
X = g,
Xss = [[e], [b, c, f], [k, h]] ;
false.

First, you have a singleton variable X here:
extend(X, [], []).
It would be better to say extend(_, [], []) because you never refer to X again. It's important to understand why this is the case. In Prolog, all the action happens because of relationships the variables are in. If the variable only appears in one place, it's not participating in any relationships, so it should be replaced with _. (If you make such a change and the code appears to be nonsense, stop and study it, because it always means you have misunderstood something.)
Second, is/2 is for evaluating arithmetic expressions. There's no math going on in this: Firstxss is [Firstxss,_|X] so you have confused it with =. This is really a double whammy though, because = does not mean assign in Prolog, it means unify. So there is no real situation in Prolog where you are going to have X = X+1 or anything like that, which is exactly the kind of thing yo'ure doing here, trying to reuse a variable for different purposes.
What does Firstxss mean in this clause? It looks like it is the first item in a nested list in the second argument in the head: in other words, if you called extend(g, [[e], [b, c, f], [k, h]], Yss), then Firstxss = e. The value of Firstxss can never change. It can only be rebound in a recursive call. So when you immediately say Firstxss is [Firstxss,_|X], what Prolog sees is b = [b,_|<another var>]. This does not unify and your predicate fails at this point. Say it advanced, somehow. You make the same mistake on the next line with Yss.
It would help to think about your problem relationally. You have the wrong base case too. What is your base case? It's the case where you have reached the end of the list, and what should you do? Append X. So this is your base case:
extend(X, [], [X]).
Now think about what you want to do in the other cases: you have a head and a tail. How do you extend? You extend the tail, and your result is the head appended to the extended tail. Try and write this clause yourself, it is not that difficult!
Once you have that, the machinery for extending nested lists is simple: you test the head to see if it is a list. If it is, recur on the head as well as the tail! Like so:
extend(X, [Y|Ys], Result) :-
(is_list(Y) -> extend(X, Y, Y1) ; Y1 = Y),
... % use Y1 as Y in building the result

Related

Adding to a list of lists in Prolog

I am currently attempting to write a Prolog program which will add a given character to the end of a list. The list's I want to append are elements within a list. This is what I currently have.
extends(X, [], []).
extends(X, [[Head]|Lists], Y):-
append([X], [Head], Y),
extends(X, Lists, [Y]).
Here I'm attempting to concatenate X and Head, storing it in Y. However I want Y to be a list of lists, so when it repeats the process again the next concatenation will be stored also in Y. So at the end of the program Y would store the results of all the concatenations. I would want the result to look like as follows.
?- extends(a, [[b,c], [d,e,f], [x,y,z]], Y).
Y = [[b,c,a], [d,e,f,a], [x,y,z,a]].
Could anyone help me out with this?
You want to apply some operation to corresponding elements of two lists. That operation talks about lists itself. It's easy to get confused with the nested levels of lists, so let's try not to think in those terms. Instead, define first a predicate that does the extension of one list:
element_list_extended(Element, List, Extended) :-
append(List, [Element], Extended).
This behaves as follows, using cases from your example:
?- element_list_extended(a, [b, c], Extended).
Extended = [b, c, a].
?- element_list_extended(a, List, [x, y, z, a]).
List = [x, y, z] ;
false.
Looks good so far. All we need to do is to apply this operation to corresponding elements of two lists:
extends(_Element, [], []).
extends(Element, [Xs | Xss], [Ys | Yss]) :-
element_list_extended(Element, Xs, Ys),
extends(Element, Xss, Yss).
And this works:
?- extends(a, [[b,c], [d,e,f], [x,y,z]], Y).
Y = [[b, c, a], [d, e, f, a], [x, y, z, a]] ;
false.
The key to making it work was to decompose the problem into two parts and to solve those simpler parts separately.
Now, if we like, since the definition of element_list_extended/3 is a single clause containing a single goal, we might decide to do without it and inline its definition into extends/3:
extends(_Element, [], []).
extends(Element, [Xs | Xss], [Ys | Yss]) :-
append(Xs, [Element], Ys),
extends(Element, Xss, Yss).
As you can see, you were quite close! You just had some superfluous brackets because you got confused about list nesting. That's precisely where decomposing the problem helps.
(As the other answer said, SWI-Prolog has some useful libraries that allow you to express even this in even shorter code.)
extends(PostFix, ListIn, ListOut) :-
maplist({PostFix}/[In,Out]>>append(In,[PostFix],Out),ListIn, ListOut).
This is using library(yall) a maplist/3 and append/3.

Prolog unification process (concat)

The following code works, but I have certain doubts as to how it does things under the hood. For example, on the first call to Exit(9) I don't understand how c is moved to the variable O. Is this part of the unification process or something else entirely? Care anyone to explain?
concat([], List, List).
concat([Head|[]], List, [Head|List]).
concat([Head|Tail], List, Concat) :- concat(Tail, List, C), concat([Head], C, Concat).
You can do 'by hand' the unification process, to verify that the trace line labelled Exit:(9) actually 'cons-ed' [c] to [x,y,z]:
?- [Head|[]]=[c],List=[x,y,z],[Head|List]=O.
Head = c,
List = [x, y, z],
O = [c, x, y, z].
but, you cannot claim it works:
?- concat([a,b,c],[x,y,z],L).
L = [a, b, c, x, y, z] ;
L = [a, b, c, x, y, z] ;
...
it doesn't terminate, and this clearly indicate some problem. The second clause is redundant - both in behaviour and syntax. It would be usually written like
concat([Head], List, [Head|List]).
since the empty tail list it's implicitly present in every list - except where a tail is explicitly indicated:
?- [Head|[]]=[X].
Head = X.
About the behaviour, you can see from your trace that it's the first clause that is never used. So, you can think it's the first that is redundant - maybe you added the second because of the last call of the third clause, where a 'singleton' list is required (I mean ...,concat([Head], C, Concat).). But such call it's causing the non termination issue. Better to simplify the whole program, removing the second clause and simplifying the third....

Prolog: lexicographic comparison and split a list

Given atom x, I am trying to split a list into one with atoms smaller than x and one with atoms equal to or greater than x.
For example)
%% split(d,[a,b,c,d,e,f],AtomSmall, AtomBig) should give me
%% AtomSmall = [a,b,c], AtomBig = [d,e,f]
Below is what I've tried so far. I get the concept.However my code includes the atom that is equivalent to x in AtomSmall list, not AtomBig, although I check the case with before predicate.
For example)
%% split(d,[a,b,c,d,e,f],AtomSmall, AtomBig) gives me
%% AtomSmall = [a,b,c,d], AtomBig = [e,f]
before(X,Y):-atom_codes(X,A),atom_codes(Y,B),small(A,B).
small([],[]).
small([H1|T1],[H2|T2]):-H1<H2.
small([H1|T1],[H2|T2]):-H1=:=H2,small(T1,T2).
split(X,[],[],[]).
split(X,[H1|T1],[H1|Small],Big):-before(H1,X),split(X,T1,Small,Big).
split(X,[H1|T1],Small,[H1|Big]):-not(before(H1,X)),split(X,T1,Small,Big).
Please help!
In SWI-Prolog, you can use partition/4 from library(lists) and the standard order comparison (#>)/2:
?- lists:partition(#>(d),[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f].
Since the order of arguments in comparison is fixed passing the pivot in as first argument, a lambda expression (using library(yall), needs a recent version) can help to give a more intuitive reading:
?- partition([E]>>(E#<d),[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f].
Anyway, your code could be patched like this:
split(_,[],[],[]).
split(X,[H1|T1],[H1|Small],Big):-H1#<X,split(X,T1,Small,Big).
split(X,[H1|T1],Small,[H1|Big]):- \+ H1#<X,split(X,T1,Small,Big).
?- split(d,[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f] ;
false.
Your before/2 predicate succeeds if the arguments are lexicographically equivalent. For example, before(a, a) is true. That's because your 3rd clause allows equal values throughout the list until the base case finally succeeds with two empty lists.
In addition, something you haven't encountered yet evidently, is that before(X, Y) will fail if X and Y are different length atoms. For example, before(ab, abc) will fail. So your small/2 needs to take care of that case as well.
A refactoring of small/2 will fix that:
% 1st clause is fixed so unequal length atoms are handled properly
small([], _).
small([H1|_], [H2|_]) :- H1 < H2.
% 3rd clause is fixed so that equal atoms won't succeed here
small([H,H1|T1], [H,H2|T2]) :- small([H1|T1], [H2|T2]).
But... you don't need to go through all that with before/2. Prolog knows how to compare, in a sensible way, atoms (and general Prolog terms) using the #< and #> operators, as #CapelliC indicated in his answer. So your before/2 just becomes:
before(X, Y) :- X #< Y.
And you don't need small/2 at all. That's basically the second solution that #CapelliC showed in his answer.

Count occurrences Prolog

I'm new in Prolog and trying to do some programming with Lists
I want to do this :
?- count_occurrences([a,b,c,a,b,c,d], X).
X = [[d, 1], [c, 2], [b, 2], [a, 2]].
and this is my code I know it's not complete but I'm trying:
count_occurrences([],[]).
count_occurrences([X|Y],A):-
occurrences([X|Y],X,N).
occurrences([],_,0).
occurrences([X|Y],X,N):- occurrences(Y,X,W), N is W + 1.
occurrences([X|Y],Z,N):- occurrences(Y,Z,N), X\=Z.
My code is wrong so i need some hits or help plz..
Here's my solution using bagof/3 and findall/3:
count_occurrences(List, Occ):-
findall([X,L], (bagof(true,member(X,List),Xs), length(Xs,L)), Occ).
An example
?- count_occurrences([a,b,c,b,e,d,a,b,a], Occ).
Occ = [[a, 3], [b, 3], [c, 1], [d, 1], [e, 1]].
How it works
bagof(true,member(X,List),Xs) is satisfied for each distinct element of the list X with Xs being a list with its length equal to the number of occurrences of X in List:
?- bagof(true,member(X,[a,b,c,b,e,d,a,b,a]),Xs).
X = a,
Xs = [true, true, true] ;
X = b,
Xs = [true, true, true] ;
X = c,
Xs = [true] ;
X = d,
Xs = [true] ;
X = e,
Xs = [true].
The outer findall/3 collects element X and the length of the associated list Xs in a list that represents the solution.
Edit I: the original answer was improved thanks to suggestions from CapelliC and Boris.
Edit II: setof/3 can be used instead of findall/3 if there are free variables in the given list. The problem with setof/3 is that for an empty list it will fail, hence a special clause must be introduced.
count_occurrences([],[]).
count_occurrences(List, Occ):-
setof([X,L], Xs^(bagof(a,member(X,List),Xs), length(Xs,L)), Occ).
Note that so far all proposals have difficulties with lists that contain also variables. Think of the case:
?- count_occurrences([a,X], D).
There should be two different answers.
X = a, D = [a-2]
; dif(X, a), D = [a-1,X-1].
The first answer means: the list [a,a] contains a twice, and thus D = [a-2]. The second answer covers all terms X that are different to a, for those, we have one occurrence of a and one occurrence of that other term. Note that this second answer includes an infinity of possible solutions including X = b or X = c or whatever else you wish.
And if an implementation is unable to produce these answers, an instantiation error should protect the programmer from further damage. Something along:
count_occurrences(Xs, D) :-
( ground(Xs) -> true ; throw(error(instantiation_error,_)) ),
... .
Ideally, a Prolog predicate is defined as a pure relation, like this one. But often, pure definitions are quite inefficient.
Here is a version that is pure and efficient. Efficient in the sense that it does not leave open any unnecessary choice points. I took #dasblinkenlight's definition as source of inspiration.
Ideally, such definitions use some form of if-then-else. However, the traditional (;)/2 written
( If_0 -> Then_0 ; Else_0 )
is an inherently non-monotonic construct. I will use a monotonic counterpart
if_( If_1, Then_0, Else_0)
instead. The major difference is the condition. The traditional control constructs relies upon the success or failure of If_0 which destroys all purity. If you write ( X = Y -> Then_0 ; Else_0 ) the variables X and Y are unified and at that very point in time the final decision is made whether to go for Then_0 or Else_0. What, if the variables are not sufficiently instantiated? Well, then we have bad luck and get some random result by insisting on Then_0 only.
Contrast this to if_( If_1, Then_0, Else_0). Here, the first argument must be some goal that will describe in its last argument whether Then_0 or Else_0 is the case. And should the goal be undecided, it can opt for both.
count_occurrences(Xs, D) :-
foldl(el_dict, Xs, [], D).
el_dict(K, [], [K-1]).
el_dict(K, [KV0|KVs0], [KV|KVs]) :-
KV0 = K0-V0,
if_( K = K0,
( KV = K-V1, V1 is V0+1, KVs0 = KVs ),
( KV = KV0, el_dict(K, KVs0, KVs ) ) ).
=(X, Y, R) :-
equal_truth(X, Y, R).
This definition requires the following auxiliary definitions:
if_/3, equal_truth/3, foldl/4.
If you use SWI-Prolog, you can do :
:- use_module(library(lambda)).
count_occurrences(L, R) :-
foldl(\X^Y^Z^(member([X,N], Y)
-> N1 is N+1,
select([X,N], Y, [X,N1], Z)
; Z = [[X,1] | Y]),
L, [], R).
One thing that should make solving the problem easier would be to design a helper predicate to increment the count.
Imagine a predicate that takes a list of pairs [SomeAtom,Count] and an atom whose count needs to be incremented, and produces a list that has the incremented count, or [SomeAtom,1] for the first occurrence of the atom. This predicate is easy to design:
increment([], E, [[E,1]]).
increment([[H,C]|T], H, [[H,CplusOne]|T]) :-
CplusOne is C + 1.
increment([[H,C]|T], E, [[H,C]|R]) :-
H \= E,
increment(T, E, R).
The first clause serves as the base case, when we add the first occurrence. The second clause serves as another base case when the head element matches the desired element. The last case is the recursive call for the situation when the head element does not match the desired element.
With this predicate in hand, writing count_occ becomes really easy:
count_occ([], []).
count_occ([H|T], R) :-
count_occ(T, Temp),
increment(Temp, H, R).
This is Prolog's run-of-the-mill recursive predicate, with a trivial base clause and a recursive call that processes the tail, and then uses increment to account for the head element of the list.
Demo.
You have gotten answers. Prolog is a language which often offers multiple "correct" ways to approach a problem. It is not clear from your answer if you insist on any sort of order in your answers. So, ignoring order, one way to do it would be:
Sort the list using a stable sort (one that does not drop duplicates)
Apply a run-length encoding on the sorted list
The main virtue of this approach is that it deconstructs your problem to two well-defined (and solved) sub-problems.
The first is easy: msort(List, Sorted)
The second one is a bit more involved, but still straight forward if you want the predicate to only work one way, that is, List --> Encoding. One possibility (quite explicit):
list_to_rle([], []).
list_to_rle([X|Xs], RLE) :-
list_to_rle_1(Xs, [[X, 1]], RLE).
list_to_rle_1([], RLE, RLE).
list_to_rle_1([X|Xs], [[Y, N]|Rest], RLE) :-
( dif(X, Y)
-> list_to_rle_1(Xs, [[X, 1],[Y, N]|Rest], RLE)
; succ(N, N1),
list_to_rle_1(Xs, [[X, N1]|Rest], RLE)
).
So now, from the top level:
?- msort([a,b,c,a,b,c,d], Sorted), list_to_rle(Sorted, RLE).
Sorted = [a, a, b, b, c, c, d],
RLE = [[d, 1], [c, 2], [b, 2], [a, 2]].
On a side note, it is almost always better to prefer "pairs", as in X-N, instead of lists with two elements exactly, as in [X, N]. Furthermore, you should keep the original order of the elements in the list, if you want to be correct. From this answer:
rle([], []).
rle([First|Rest],Encoded):-
rle_1(Rest, First, 1, Encoded).
rle_1([], Last, N, [Last-N]).
rle_1([H|T], Prev, N, Encoded) :-
( dif(H, Prev)
-> Encoded = [Prev-N|Rest],
rle_1(T, H, 1, Rest)
; succ(N, N1),
rle_1(T, H, N1, Encoded)
).
Why is it better?
we got rid of 4 pairs of unnecessary brackets in the code
we got rid of clutter in the reported solution
we got rid of a whole lot of unnecessary nested terms: compare .(a, .(1, [])) to -(a, 1)
we made the intention of the program clearer to the reader (this is the conventional way to represent pairs in Prolog)
From the top level:
?- msort([a,b,c,a,b,c,d], Sorted), rle(Sorted, RLE).
Sorted = [a, a, b, b, c, c, d],
RLE = [a-2, b-2, c-2, d-1].
The presented run-length encoder is very explicit in its definition, which has of course its pros and cons. See this answer for a much more succinct way of doing it.
refining joel76 answer:
count_occurrences(L, R) :-
foldl(\X^Y^Z^(select([X,N], Y, [X,N1], Z)
-> N1 is N+1
; Z = [[X,1] | Y]),
L, [], R).

Split list on given element

I have a list C and I want to split the list using the element c in the list.
The expected results are as example:
?- split([a,c,a,a,c,a,a,a],X).
X = [[a],[a,a],[a,a,a]].
Can anybody help? Thanks in advance.
I can remove the c in the list now and here is my codes.
split([],[]).
split([H|T],[H|S]) :- H=a,split(T,S).
split([H|T],S) :- H=c,split(T,S).
Your "remove c" predicate would look better like this:
remove_c([c|T], S) :-
remove_c(T, S).
remove_c([a|T], [a|S]) :-
remove_c(T, S).
This still only works for lists that have only c and a in them.
If you want to "split", this means you at least need another argument, to collect the a's between the c's. For example:
split_on_c(List, Split) :-
split_on_c_1(List, Split, []).
split_on_c_1([], [Acc], Acc).
split_on_c_1([c|Rest], [Acc|Split], Acc) :-
split_on_c_1(Rest, Split, []).
split_on_c_1([a|Rest], Split, Acc) :-
split_on_c_1(Rest, Split, [a|Acc]).
Again, this expects lists of a and c only. It could also be done in different ways, but this is a start.
While learning a language you need to get accomplished to common abstractions already established (in simpler terms, use libraries). What about
split(In, Sep, [Left|Rest]) :-
append(Left, [Sep|Right], In), !, split(Right, Sep, Rest).
split(In, _Sep, [In]).
to be used like
?- split([a,c,a,a,c,a,a,a],c,R).
R = [[a], [a, a], [a, a, a]].
Use the meta-predicate splitlistIf/3 together with reified term equality
(=)/3, like this:
Here is the query the OP gave in the question:
?- splitlistIf(=(c),[a,c,a,a,c,a,a,a],Xs).
Xs = [[a],[a,a],[a,a,a]].
Note that above code is monotone, so the following query gives reasonable results:
?- splitlistIf(=(X),[Y,X,Y,Y,X,Y,Y,Y],Xs), Y = a, X = c.
X = c,
Y = a,
Xs = [[a],[a, a],[a, a, a]].

Resources