Printing list elements - How are these two solutions different? - prolog

I am currently going through "Programming in Prolog" by Clocksin & Mellish. One of the exercises asks to print list elements each on a line while indenting nested elements, so for example we need to print [a,b,[c,d],e,f] as:
a
b
c
d
e
f
So, here is my solution (assume we have a predicate 'indent' that prints a specified no. of spaces for indentation). I have defined two predicates 'print' & 'printelement', each takes a first argument to be printed and a second for the indentation (no. of spaces):
print([],_).
print([H|T],Indent):- H\=[_|_], % if not a list
printelement(H,Indent),
print(T,Indent).
print([H|T],Indent):- H=[_|_], NewIndent is Indent+2, % if a list, increase the indent
print(H,NewIndent), % NewIndent
print(T,Indent). % Indent
printelement(X,I):- indent(I), write(X), nl. % print individual elements
... and it does the job. On the other hand, the book presents a solution that does the job too but with a bit of going back and forth between two predicates as follows:
printA([H|T], I) :- !, J is I + 2, printA(H, J), printB(T, J), nl.
printA(X, I) :- indent(I), write(X), nl.
printB([],_).
printB([H|T], I) :- printA(H, I), printB(T, I).
There are a number of other exercises that are solved in a similar manner; and even though I can trace those solutions and validate their correctness, I am a bit confused by this approach. So, would you please help point out the differences between the above solutions? I find mine a bit more logical and straight-forward, and I don't quite get the second one!

If I had to pick between the two solutions, I actually prefer the first solution to the one in the textbook. At least I see no advantages to the second approach, and both solutions are a fairly imperative approach to Prolog. If you had a big enough list, you could do a performance comparison, if that was an important factor. Both have a somewhat awkward calling convention where you need to provide a second argument even though you don't care what it is, ultimately. The second solution has the two arbitrarily named predicates printA and printB that don't seem to have a distinguishable enough semantic meaning between them. You can call printA(MyList, 0). or printB(MyList, 0). and get (sort of) the same results (one having one extra level of indent).
Both printA/2 and print/2 treat [] as an atom rather than an empty list. Thus:
| ?- print([a,b,[],c], 0).
a
b
[]
c
And similarly for printA([a,b,[],c], 0).
If I were writing this, I would take a different approach altogether. First, I might write a predicate with 3 arguments: element_depth(List, X, D) that succeeds if X is in the multi-level list List at depth D and it fails otherwise.
element_depth(List, X, Depth) :-
element_depth(List, X, 0, Depth). % Starts with depth 0
element_depth([X|_], X, Depth, Depth) :-
\+ is_list(X).
element_depth([L|_], X, D, Depth) :-
is_list(L),
D1 #= D + 1,
element_depth(L, X, D1, Depth).
element_depth([_|Xs], X, D, Depth) :-
element_depth(Xs, X, D, Depth).
Now you have a Prolog predicate that behaves more like a predicate and less like a C function. You use it to make queries and it provides solutions. You can do queries such as:
| ?- element_depth([a,b,[d, []], c], X, D).
D = 0
X = a ? a
D = 0
X = b
D = 1
X = d
D = 0
X = c
no
| ?- element_depth([a,b,[d,[]], c], X, 1).
X = d ? ;
no
| ?- element_depth([a,b,[d,[]], c], c, D).
D = 0 ? ;
no
If you want to do a formatted printing of results, you can write a specific formatting predicate that calls it:
print_elements(L) :-
element_depth(L, X, D),
N #= D * 2,
indent(N),
write(X), nl,
fail.
Which you can then call like this:
| ?- print_elements([a,b,[d,[]], c]).
a
b
d
c
no
| ?-
This looks like a little more code, but it is more general and more Prology.

Related

prolog pattern identification for list of numbers

So I'm trying to identify if a list of numbers can be identified as a arithmetic progression. For example I have a list of numbers [5, 10, 15, 20] I need to make predicates that will identify this as arithmetic progression.
I'll try to give you a framework without giving away the whole answer. The bottom line is that you should go online or get a text book and study Prolog recursive list processing.
arith_prog([X,Y|T]) :-
Diff #= X - Y,
arith_prog([Y|T], Diff).
arith_prog([_], _). % A single element list is a degenerate arith prog
arith_prog([X,Y|T], Diff) :- ... (what goes here?)
Note that I'm using CLP(FD) here (thus, the #=/2 operator). That's the best way of reasoning with integers in Prolog and provides the most general solution. If you want to limit this to checking fully instantiated numeric lists, then you could use Diff is X - Y.
We can find out the difference between two separate numbers just fine:
diff_between( A, B, C):-
C is A - B.
As for the lists, we need to pair up the consecutive elements
pairs( G3, [A | B], C):- % G3 is a goal expecting of 3 arguments
append( D, [_], [A | B]),
maplist( call(G3), B, D, C).
Now we can get the list of differences between the consecutive elements:
consec_diffs( L, Diffs):-
pairs( diff_between, L, Diffs).
% pairs( G3, [A | B], C)
% maplist( call(diff_between), B, D, Diffs )
% consec_diffs( [a,b,c, ..., n,m], Diffs)
% =
% [ b,c, ..., n,m ]
% [ a,b, ....., n ]
% ------------------- pairwise diff_between
% Diffs = [ ............. ]
And then we just need to find out whether all of them are the same:
is_arith_prog( A ):-
consec_diffs( A, [B | C]),
maplist( =:=(B), C).
This answer mainly just has a curiosity value. It does too much work potentially. The proper way to code anything is while doing as little work as possible and reaching the conclusion as soon as possible. In this case it is done by a straightforward recursive definition processing the list in the top-down manner.

Prolog multiply elements of a list

How can I get my Prolog program to output
1*a*b*c
If I input simplify([1,a,b,c],S).?
At the moment the result would be
1*(a*(b*c)).
simplify(S,S1):-
s(S,S1).
s([H|T],C) :- T\=[],s(H,SA), s(T,SB), s0(SA*SB,C).
s([H|T],H) :- T==[].
s(A,A).
s0(A*B,S):-
S = A*B.
Thanks for your help.
The difference between 1*a*b*c and 1*(a*(b*c)) is associativity, i.e., the position of the parentheses:
?- X = 1*a*b*c, X = ((One * A) * B) * C.
X = 1*a*b*c,
One = 1,
A = a,
B = b,
C = c.
One way to do this is to "fold over the list from the left", that is to say, compute a result for the first element of the list, combine with the second element, then the third, etc. This is typically done using an accumulator argument to pass the intermediate result. In contrast, your recursion folds the list "from the right" (combining a result for the tail list with the first element, instead of the initial list with the last element).
Here's a way (very lightly tested):
list_multexp([X|Xs], Multexp) :-
list_multexp(Xs, X, Multexp). % use first element as initial acc
list_multexp([X], Acc, Acc * X).
list_multexp([X|Xs], Acc, Multexp) :-
dif(Xs, []),
list_multexp(Xs, Acc * X, Multexp).
This works for your example:
?- list_multexp([1,a,b,c], Multexp).
Multexp = 1*a*b*c ;
false.
Depends on what Prolog you're using. SWI has foldl/4 built in, which is like "reduce" in other languages. So, you could simplify your program to the following:
s(B,A,A*B).
simplify([H|L],E):- foldl(s,L,H,E).
Not sure that is what do you want but... using atom_concat/3...
simplify([H],H).
simplify([A | T], D) :-
simplify(T,B),
atom_concat(A, '*', C),
atom_concat(C, B, D).
But you have to use 1 as an "atom", so
simplify(['1',a,b,c], S),

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

Relying on rule order

To calculate the hamming distance between two lists of the same length, I use foldl(hamm, A, B, 0, R). with this definition of hamm/4:
hamm(A, A, V, V) :- !.
hamm(A, B, V0, V1) :- A \= B, V1 is V0 + 1.
The cut in the first rule prevents the unnecessary backtracking. The second rule, however, could have been written differently:
hamm2(A, A, V, V) :- !.
hamm2(_, _, V0, V1) :- V1 is V0 + 1.
and hamm2/4 will still be correct together with foldl/5 or for queries where both A and B are ground.
So is there a really good reason to prefer the one over the other? Or is there a reason to keep the rules in that order or switch them around?
I know that the query
hamm(a, B, 0, 1).
is false, while
hamm2(a, B, 0, 1).
is true, but I can't quite decide which one makes more sense . . .
The OP implemented two accumulator-style predicates for calculating the Hamming distance (hamm/4 and hamm2/4), but wasn't sure which one made more sense.
Let's read the query that puzzled the OP: "Is there an X such that distance(a,X) is 1?". Here are the "answers" Prolog gives:
?- hamm(a,X,0,1).
false. % wrong: should succeed conditionally
?- hamm2(a,X,0,1). % wrong: should succeed, but not unconditionally
true.
From a logical perspective, both implementations misbehave in above test. Let's do a few tests for steadfastness:
?- hamm(a,X,0,1),X=a. % right
false.
?- hamm(a,X,0,1),X=b. % wrong: should succeed as distance(a,b) is 1
false.
?- hamm2(a,X,0,1),X=a. % wrong: should fail as distance(a,a) is 0
X = a.
?- hamm2(a,X,0,1),X=b. % right
X = b.
Note that in previous queries hamm/4 rightly fails when hamm2/4 wrongly succeeded, and vice-versa.
So both are half-right/half-wrong, and neither one
is steadfast.
What can be done?
Based on if_/3 and (=)/3 presented by #false in this answer, I implemented the following pure code for predicate hamm3/4:
:- use_module(library(clpfd)).
hamm3(A,B,V0,V) :-
if_(A = B, V0 = V, V #= V0+1).
Now let's repeat above queries using hamm3/4:
?- hamm3(a,X,0,1).
dif(X,a).
?- hamm3(a,X,0,1),X=a.
false.
?- hamm3(a,X,0,1),X=b.
X = b.
It works! Finally, let's ask the most general query to see the entire solution set of hamm3/4:
?- hamm3(A,B,N0,N).
A = B, N0 = N ;
dif(A,B), N0+1 #= N.
You already spotted the differences between those definitions: efficiency apart, you should decide about your requirements. Are you going to accept variables in your data structures? Such programming style introduces some of advanced Prolog features (incomplete data structures).
Anyway, I think the first form is more accurate (not really sure about, I would say steadfast on 4° argument)
?- hamm(a, B, 0, 1).
false.
?- hamm(a, B, 0, 0).
B = a.
while hamm2 is
?- hamm2(a, B, 0, 1).
true.
?- hamm2(a, B, 0, 0).
B = a.

Resources