Related
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.
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.
Question
Is it possible to schedule a goal to be executed as soon as the length of a list is known / fixed or, as #false pointed out in the comments, a given argument becomes a [proper] list? Something along this line:
when(fixed_length(L), ... some goal ...).
When-conditions can be constructed using ?=/2, nonvar/1, ground/1, ,/2, and ;/2 only and it seems they are not very useful when looking at the whole list.
As a further detail, I'm looking for a solution that presents logical-purity if that is possible.
Motivation
I think this condition might be useful when one wants to use a predicate p(L) to check a property for a list L, but without using it in a generative way.
E.g. it might be the case that [for efficiency or termination reasons] one prefers to execute the following conjunction p1(L), p2(L) in this order if L has a fixed length (i.e. L is a list), and in reversed order p2(L), p1(L) otherwise (if L is a partial list).
This might be achieved like this:
when(fixed_length(L), p1(L)), p2(L).
Update
I did implement a solution, but it lacks purity.
It would be nice if when/2 would support a condition list/1. In the meantime, consider:
list_ltruth(L, Bool) :-
freeze(L, nvlist_ltruth(L, Bool)).
nvlist_ltruth(Xs0, Bool) :-
( Xs0 == [] -> Bool = true
; Xs0 = [_|Xs1] -> freeze(Xs1, nvist_ltruth(Xs1, Bool))
; Bool = false
).
when_list(L, Goal_0) :-
nvlist_ltruth(L, Bool),
when(nonvar(Bool),( Bool == true, Goal_0 )).
So you can combine this also with other conditions.
Maybe produce a type error, if L is not a list.
when(nonvar(Bool), ( Bool == true -> Goal_0 ; sort([], L) ).
Above trick will only work in an ISO conforming Prolog system like SICStus or GNU that produces a type_error(list,[a|nonlist]) for sort([],[a|nonlist]), otherwise replace it by:
when(nonvar(Bool),
( Bool == true -> Goal_0 ; throw(error(type_error(list,L), _)).
Many systems contain some implementation specific built-in like '$skip_list' to traverse lists rapidly, you might want to use it here.
I've managed to answer my own question, but not with a pure solution.
Some observations
The difficulty encountered in writing a program that schedules some goal for execution when the length of a list is precisely known is the fact that the actual condition might change. Consider this:
when(fixed_length(L), Goal)
The length of the list might change if L is unbound or if the last tail is unbound. Say we have this argument L = [_,_|Tail]. L has a fixed width only if Tail has a fixed width (in other words, L is a list if T is a list). So, a condition that checks Tail might be the only thing to do at first. But if Tail becomes [a|Tail2] a new when-condition that tests if Tail2 is a list is needed.
The solution
1. Getting the when-condition
I've implemented a predicate that relates a partial list with the when-condition that signals when it might become a list (i.e. nonvar(T) where T is the deepest tail).
condition_fixed_length(List, Cond):-
\+ (List = []),
\+ \+ (List = [_|_]),
List = [_|Tail],
condition_fixed_length(Tail, Cond).
condition_fixed_length(List, Cond):-
\+ \+ (List = []),
\+ \+ (List = [_|_]),
Cond = nonvar(List).
2. Recursively when-conditioning
check_on_fixed_length(List, Goal):-
(
condition_fixed_length(List, Condition)
->
when(Condition, check_on_fixed_length(List, Goal))
;
call(Goal)
).
Example queries
Suppose we want to check that all elements of L are a when the size of L is fixed:
?- check_on_fixed_length(L, maplist(=(a), L)).
when(nonvar(L), check_on_fixed_length(L, maplist(=(a), L))).
... and then L = [_,_|Tail]:
?- check_on_fixed_length(L, maplist(=(a), L)), L = [_,_|L1].
L = [_G2887, _G2890|L1],
when(nonvar(L1), check_on_fixed_length([_G2887, _G2890|L1], maplist(=(a), [_G2887, _G2890|L1]))).
?- check_on_fixed_length(L, maplist(=(a), L)), L = [_,_|L1], length(L1, 3).
L = [a, a, a, a, a],
L1 = [a, a, a].
Impurity
conditon_fixed_length/2 is the source of impurity as it can be seen from the following query:
?- L = [X, Y|Tail], condition_fixed_length(L, Cond), L = [a,a].
L = [a, a],
X = Y, Y = a,
Tail = [],
Cond = nonvar([]).
?- L = [X, Y|Tail], L = [a, a], condition_fixed_length(L, Cond).
false.
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).
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.