I am studying prolog at university and facing some problems. What I already found out is just solution to a problem. However, I'm more interested in the way to think, i.e. how to get such solution.
Can somebody give me an advise on this field. I would really appreciate your help.
I give an example I am coping with and also, found a solution on stackoverflow here, but what I looking for is how does he do that, how does he find the answer :)
Write a predicate flatten(List,Flat) that flatten a list, e.g. flatten([a,b,[c,d],[[1,2]],foo],X) will give X=[a,b,c,d,1,2,foo].
This is the answer I found on stackoverflow:
flatten(List, Flattened):-
flatten(List, [], Flattened).
flatten([], Flattened, Flattened).
flatten([Item|Tail], L, Flattened):-
flatten(Item, L1, Flattened),
flatten(Tail, L, L1).
flatten(Item, Flattened, [Item|Flattened]):-
\+ is_list(Item).
this answer belongs to user gusbro and asked by user Parhs, I have try to find a way to contact user gusbro to ask him how he can derive such answer but I cannot.
Thank you very much.
Well, all I can say is that the way to solve a problem depends largely on the problem itself. There is a set of problems which are amenable to solve using recursion, where Prolog is well suited to solve them.
In this kind of problems, one can derive a solution to a larger problem by dividing it in two or more case classes.
In one class we have the "base cases", where we provide a solution to the problem when the input cannot be further divided into smaller cases.
The other class is the "recursive cases", where we split the input into parts, solve them separately, and then "join" the results to give a solution to this larger input.
In the example for flatten/2 we want to take as input a list of items where each item may also be a list, and the result shall be a list containing all the items from the input. Therefore we split the problem in its cases.
We will use an auxiliary argument to hold the intermediate flattened list, and thats the reason why we implement flatten/3.
Our flatten/2 predicate will therefore just call flatten/3 using an empty list as a starting intermediate flattened list:
flatten(List, Flattened):-
flatten(List, [], Flattened).
Now for the flatten/3 predicate, we have two base cases. The first one deals with an empty list. Note that we cannot further divide the problem when the input is an empty list. In this case we just take the intermediate flattened list as our result.
flatten([], Flattened, Flattened).
We now take the recursive step. This involves taking the input list and dividing the problem in two steps. The first step is to flatten the first item of this input list. The second step will be to recursively flatten the rest of it:
flatten([Item|Tail], L, Flattened):-
flatten(Item, L1, Flattened),
flatten(Tail, L, L1).
Ok, so the call to flatten(Item, L1, Flattened) flattens the first item but passes as intermediate list an unbound variable L1. This is just a trickery so that at the return of the predicate, the variable L1 still remain unbounded and Flattened will be of the form [...|L1] where ... are the flattened items of Item.
The next step, which calls flatten(Tail, L, L1) flattens the rest of the input list and the result is bounded with L1.
Our last clause is really another base case, the one that deals with single items (which are not lists). Therefore we have:
flatten(Item, Flattened, [Item|Flattened]):-
\+ is_list(Item).
which checks whether item is a list and when it is not a list it binds the result as a list with head=Item and as tail the intermediate flattened list.
First, I'll show you my approach to the problem, then I've got some resources for learning to think recursively.
Here's my solution to the problem "flatten a list of lists (of lists ...)". I've annotated it to show how I got there:
First, let's define the public interface to our solution. We define flatten/2. It's body consists of a call to the internal implementation flatten/3, which takes an accumulator, seeded as an empty list.
flatten ( X , R ) :-
flatten ( X , [] , R ) ,
.
That was easy.
The internal predicate flatten/3 is a little more complex, but not very.
First, we have the boundary condition: the empty list. That marks the end of what we need to do, so we unify the accumulator with the result:
flatten( [] , X , X ).
The next (and only) other case is a non-empty list. For this, we examine the head of the list. Our rule here is that it needs to flattened and appended to the result. A good rule of programming is to write descriptive code, and Prolog is itself a descriptive, rather than procedural, language: one describes the solution to the problem and lets the inference engine sort things out.
So...let's describe what needs to happen now, and punt on the mechanics of flattening the head of the list:
flatten( [X|Xs] , T , Y ) :-
flatten_head(X,X1) ,
append( T,X1,T1) ,
flatten( Xs , T1 , Y )
.
That, too, was easy.
That's the essence of the entire solution, right there. We've broken our problem into 3 pieces:
a special case (the empty list)
the normal case (a non-empty list)
what to do with each element in the list (not yet defined).
Let's move on to the implementation of how to flatten a single list element. That's easy, too. We've got two cases, here: the list item might be a list, or it might be something else.
First, the list element might be an unbound variable. We don't want untowards behaviour, like unbounded recursion happening, so let's take care of that straightaway, by disallowing unbound terms (for now). If the element is bound, we try to flatten it by invoking our public interface, flatten\2 again (oooooooh...more recursion!)
This accomplishes two things
First, it tells us whether we've got a list or not: flatten/2 fails if handed something other than a list.
Second, when it succeeds, the job of flatten_head/2 is done.
Here's the code:
flatten-head( X , Y ) :-
nonvar(X) ,
flatten( X , Y )
.
Finally, the last case we have to consider is the case of list elements that aren't lists (unbound vars, atoms or some other prolog term). These are already "flat"...all we need to do is wrap them as a single element list so that the caller (flatten\3) gets consistent semantics for its "return value":
flatten-head( X , [X] ).
Here's the complete code:
flatten ( X , R ) :-
flatten ( X , [] , R )
.
flatten( [] , X , X ) .
flatten( [X|Xs] , T , Y ) :-
flatten_head(X,X1) ,
append( T,X1,T1) ,
flatten( Xs , T1 , Y )
.
flatten-head( X , Y ) :-
nonvar(X) ,
flatten( X , Y )
.
flatten-head( X , [X] ) .
Each individual step is simple. It's identifying the pieces and weaving them together that's difficult (though sometimes, figuring out how to stop the recursion can be less than obvious).
Some Learning Resources
To understand recursion, you must first understand recursion—anonymous
Eric Roberts' Thinking Recursively (1986) is probably the best (only?) book specifically on developing a recursive point-of-view WRT developing software. There is an updated version Thinking Recursively With Java, 20th Anniversary Edition (2006), though I've not seen it.
Both books, of course, are available from the Usual Places: Powell's, Amazon, etc.
http://www.amazon.com/Thinking-Recursively-Eric-S-Roberts/dp/0471816523
http://www.amazon.com/Thinking-Recursively-Java-Eric-Roberts/dp/0471701467
http://www.powells.com/biblio/61-9780471816522-2
http://www.powells.com/biblio/72-9780471701460-0
You might also want to read Douglas Hofstadtler's classic Gödel, Escher, Bach: An Eternal Golden Braid Some consider it to be the best book ever written. YMMV.
Also available from the Usual Suspects:
http://www.powells.com/biblio/62-9780140289206-1
http://www.amazon.com/Godel-Escher-Bach-Eternal-Golden/dp/0465026567
A new book, though not directly about recursive theory, that might be useful, though I've not seen it (it's gotten good reviews) is Michael Corballis' The Recursive Mind:
The Origins of Human Language, Thought, and Civilization
Related
Write a PROLOG program (i.e., set of predicates) that implements the following function. The program should compare three lists and determine if the first element of the first list is the same as both the last element of the second list and the second to last element of the third list. Call the main predicate: compare(List1, List2, List3).
I went ahead and wrote separate codes for the two separate conditions, which works on its own.
1. 1st item of List1 equals last item of List2.
2. 1st item of List1 equals second to last item of List3.
Now I'm having trouble combining the codes to work together. My train of thought is that condition 1 and condition 2 have to be met separately before the overall condition is met. So somehow I have to run the code for condition 1 and condition 2 on its own but in the same program?? And if both of those return true then I can have something else that says my conditions are met.
compare(List1,List2,List3):- last(true), secondLast(true).
Condition1:
last([HeadList1|RestList1],[HeadList1]).
last([HeadList1|RestList1],[HeadList2|RestList2]) :-
last([HeadList1|RestList1],RestList2).
Condition2:
secondLast([HeadList1|RestList1],[HeadList1,RestList3]).
secondLast([HeadList1|RestList1],[HeadList3|RestList3]) :-
secondLast([HeadList1|RestList1],RestList3).
What I'm expecting:
?- compare([2,8,9,1],[4,5,6,2],[1,2,3]).
yes
?- compare([a,b,c,d,k],[a,c,f,e],[a,s]).
no
With SWI, you can use last/2 and the definition of secondTast/2 from this question:
secondLast([X,_], X).
secondLast([_|T], X) :- secondLast(T, X).
my_compare([H|_],L1,L2):-
last(L1,H),
secondLast(L2,H).
?- my_compare([2,8,9,1],[4,5,6,2],[1,2,3]).
true
?- my_compare([a,b,c,d,k],[a,c,f,e],[a,s]).
false
You can put a cut to avoid the solution false in the first query. This is a first solution, you can get super fancy and use for instance reverse/2 and other predicates to find another solution (but maybe slower).
#damianodamiano suggests an implementation using reverse/2 and I thought it might be interesting to see what it is.
mycompare([H|_], L2, L3) :-
reverse(L2, [H|_]),
reverse(L3, [_, H|_]).
reverse/2 is somewhat more expensive than a list traversal, so this may not be the best way to solve the problem, I think it's worth seeing because it's fairly close to the question as stated and it demonstrates that this problem is solved really by unification and only unification. damianodamiano's solution has a similar property in that you are finding the first thing, H and then showing that H appears in other positions in the other two lists.
Now I have some miscellaneous feedback for you:
You are right to believe that if you have two predicates, say p1 and p2, you can combine them by doing p1, p2. In general, they are going to share variable bindings between them because what you are doing in programming in Prolog is setting up a relationship between certain things.
This is also why singleton "warnings" are actually errors: they reveal cases where you believe there is a relationship, but where Prolog could tell that you didn't share the variable anywhere, so no relationship was established.
Your variable names are really bad. If 99% of all your variable names are the same, you are going to get confused. It would be better to use A and B than HeadList1 and HeadList2. If you must use names like these, simplify to H1 and H2. When you see [X|Y], you know X is a head of a list and Y is a list tail, you do not need to make that information part of the name. Focus on the content of the variable if you can, or the relationship you're trying to establish between the expressions that variable is a part of.
Prolog predicates do not "return true." They can succeed or fail but they are not evaluated like functions: you cannot replace mycompare(A,B,C) with true just because mycompare(A,B,C) succeeds, you cannot assign a value to the result R = mycompare(A,B,C), and you cannot nest predicates like writeln(mycompare(A,B,C)). So break this habit now so you don't confuse yourself further in the future.
I find myself narrowing a (very simple) problem more and more.
Let's say I have this operation: listsplit([H1,H2,H3|T], H1,H2,H3, T).
Which gives me the first three elements of a list. I want a program, cells, to travel an input list and make (at least that ONE operation!!) to every element of the list.
So I have something like:
cells(Input, Result):-
cellsBody(Input, [], Result).
cellsBody([],Result,Result).
cellsBody([Head|Input], Acc, [Headd|Result]):-
listsplit(Input,H1,H2,H3,_),
cellsBody(Input, [OutputBody|Acc], Result).
I have that code because I have used many I've seen as examples that go like that to travel a list. They separate head from body and go on. I fail to see how this is done in prolog. I tried changing variable names, so that they would match (as I would do in other languages), and I've tried to make the problem as simple as possible.
So, how do I travel a list AND make operations to every element (that I choose to, starting with the first one, the head).
Edit: Examples of what I want to archieve:
I get an input list like oxo, oxxxo, oxoxo, so on. I then apply a rule to the first three elements, then the next three, and so on, and while I do that I add the result of the rule to another list that I return (which is why I am trying to use the accumulator).
You've almost got it. Keeping your predicate cells/2 as is, think about the special cases first: The lists [], [_], [_,_] haven't got three elements, so whatever operation you have in mind for those three elements, there's nothing to do in these cases. Otherwise you have a recursive rule to do what you intend to.
Looking at listsplit/5: you can do that directly in the head of the recursive rule, no need for an extra predicate. Then you have one or more goals for your intended operation. For the sake of an example let's say packaging the 3 head elements as a triplet. And of course the relation must hold for the tail T of the list too. Then your code might look something like that:
cellsBody([],Result,Result).
cellsBody([_],Result,Result).
cellsBody([_,_],Result,Result).
cellsBody([H1,H2,H3|T], Acc, Result):- % the first 3 elements
Triplet=(H1,H2,H3), % at least ONE operation with them
cellsBody(T, [Triplet|Acc], Result).
Example queries:
?- cells([],Result).
Result = []
?- cells([1],Result).
Result = []
?- cells([1,2],Result).
Result = []
?- cells([1,2,3],Result).
Result = [(1,2,3)]
?- cells([1,2,3,4,5,6,7],Result).
Result = [(4,5,6),(1,2,3)]
Of course, if the intended operation is as simple as in the above example, you don't need an extra goal for it: You can do that directly in the recursive goal:
cellsBody([H1,H2,H3|T], Acc, Result):-
cellsBody(T, [(H1,H2,H3)|Acc], Result).
I'm trying to re-familiarize myself with Prolog and I thought this could be the type of problem with an elegant solution in Prolog.
I'm following along this example:
http://home.deib.polimi.it/matteucc/Clustering/tutorial_html/hierarchical.html
I've tried a variety of data formats:
dist('BA','FI',662).
dist(0,'BA','FI',662).
dist(['BA'],['FI'],662).
but I haven't found any particular one most suitable.
Here's all the data in the first format:
%% Graph distances
dist('BA','FI',662).
dist('BA','MI',877).
dist('BA','NA',255).
dist('BA','RM',412).
dist('BA','TO',996).
dist('FI','MI',295).
dist('FI','NA',468).
dist('FI','RM',268).
dist('FI','TO',400).
dist('MI','NA',754).
dist('MI','RM',564).
dist('MI','TO',138).
dist('NA','RM',219).
dist('NA','TO',869).
dist('RM','TO',669).
Now, there seems to be some awesome structure to this problem to exploit, but I'm really struggling to get a grasp of it. I think I've got the first cluster here (thought it may not be the most elegant way of doing it ;)
minDist(A,B,D) :- dist(A,B,D), dist(X,Y,Z), A \= X, A \= Y, B \= X, B \= Y, D < Z.
min(A,B,B) :- B < A
min(A,B,A) :- A < B
dist([A,B],C, D) :- minDist(A,B,D), dist(A,C,Q), dist(B,C,W), min(Q,W,D)
The problem I have here is the concept of "replacing" the dist statements involving A and B with the cluster.
This just quickly become a brainteaser for me and I'm stuck. Any ideas on how to formulate this? Or is this perhaps just not the kind of problem elegantly solved with Prolog?
Your table is actually perfect! The problem is that you don't have an intermediate data structure. I'm guessing you'll find the following code pretty surprising. In Prolog, you can simply use whatever structures you want, and it will actually work. First let's get the preliminary we need for calculating distance without regard for argument order:
distance(X, Y, Dist) :- dist(X, Y, Dist) ; dist(Y, X, Dist).
This just swaps the order if it doesn't get a distance on the first try.
Another utility we'll need: the list of cities:
all_cities(['BA','FI','MI','NA','RM','TO']).
This is just helpful; we could compute it, but it would be tedious and weird looking.
OK, so the end of the linked article makes it clear that what is actually being created is a tree structure. The article doesn't show you the tree at all until you get to the end, so it isn't obvious that's what's going on in the merges. In Prolog, we can simply use the structure we want and there it is, and it will work. To demonstrate, let's enumerate the items in a tree with something like member/2 for lists:
% Our clustering forms a tree. So we need to be able to do some basic
% operations on the tree, like get all of the cities in the tree. This
% predicate shows how that is done, and shows what the structure of
% the cluster is going to look like.
cluster_member(X, leaf(X)).
cluster_member(X, cluster(Left, Right)) :-
cluster_member(X, Left) ; cluster_member(X, Right).
So you can see we're going to be making use of trees using leaf('FI') for instance, to represent a leaf-node, a cluster of N=1, and cluster(X,Y) to represent a cluster tree with two branches. The code above lets you enumerate all the cities within a cluster, which we'll need to compute the minimum distance between them.
% To calculate the minimum distance between two cluster positions we
% need to basically pair up each city from each side of the cluster
% and find the minimum.
cluster_distance(X, Y, Distance) :-
setof(D,
XCity^YCity^(
cluster_member(XCity, X),
cluster_member(YCity, Y),
distance(XCity, YCity, D)),
[Distance|_]).
This probably looks pretty weird. I'm cheating here. The setof/3 metapredicate finds solutions for a particular goal. The calling pattern is something like setof(Template, Goal, Result) where the Result will become a list of Template for each Goal success. This is just like bagof/3 except that setof/3 gives you unique results. How does it do that? By sorting! My third argument is [Distance|_], saying just give me the first item in the result list. Because the result is sorted, the first item in the list will be the smallest. It's a big cheat!
The XCity^YCity^ notation says to setof/3: I don't care what these variables actually are. It marks them as "existential variables." This means Prolog will not provide multiple solutions for each city combination; they will all be thrown together and sorted once.
This is all we need to perform the clustering!
From the article, the base case is when you have two clusters left: just combine them:
% OK, the base case for clustering is that we have two items left, so
% we cluster them together.
cluster([Left,Right], cluster(Left,Right)).
The inductive case takes the list of results and finds the two which are nearest and combines them. Hold on!
% The inductive case is: pair up each cluster and find the minimum distance.
cluster(CityClusters, FinalCityClusters) :-
CityClusters = [_,_,_|_], % ensure we have >2 clusters
setof(result(D, cluster(N1,N2), CC2),
CC1^(select(N1, CityClusters, CC1),
select(N2, CC1, CC2),
cluster_distance(N1, N2, D)),
[result(_, NewCluster, Remainder)|_]),
cluster([NewCluster|Remainder], FinalCityClusters).
Prolog's built-in sorting is to sort a structure on the first argument. We cheat again here by creating a new structure, result/3, which will contain the distance, the cluster with that distance, and the remaining items to be considered. select/3 is extremely handy. It works by pulling an item out of the list and then giving you back the list without that item. We use it twice here to select two items from the list (I don't have to worry about comparing a place to itself as a result!). CC1 is marked as a free variable. The result structures will be created for considering each possible cluster with the items we were given. Again, setof/3 will sort the list to make it unique, so the first item in the list will happen to be the one with the shortest distance. It's a lot of work for one setof/3 call, but I like to cheat!
The last line says, take the new cluster and append it to the remaining items, and forward it on recursively to ourself. The result of that invocation will eventually be the base case.
Now does it work? Let's make a quick-n-dirty main procedure to test it:
main :-
setof(leaf(X), (all_cities(Cities), member(X, Cities)), Basis),
cluster(Basis, Result),
write(Result), nl.
Line one is a cheesy way to construct the initial conditions (all cities in their own cluster of one). Line two calls our predicate to cluster things. Then we write it out. What do we get? (Output manually indented for readability.)
cluster(
cluster(
leaf(FI),
cluster(
leaf(BA),
cluster(
leaf(NA),
leaf(RM)))),
cluster(
leaf(MI),
leaf(TO)))
The order is slightly different, but the result is the same!
If you're perplexed by my use of setof/3 (I would be!) then consider rewriting those predicates using the aggregate library or with simple recursive procedures that aggregate and find the minimum by hand.
I am new in Prolog and I am studying it for an universitary exam, we use SWI Prolog
I have some problem to understand how work this simple program that say TRUE if a list S is a sublist of a list L, otherwise say that the predicate is FALSE.
I have the following solution but I have some problem to understand it's declarative meaning
Reading the book I think that I had have some idea but I am not sure about it...
This is the solution that use concatenation:
sublist(S,L) :- conc(L1, L2, L),
conc(S, L3, L2).
conc([],L,L).
conc([X|L1],L2,[X|L3]) :- conc(L1,L2,L3).
This solution use an other litle program that respond TRUE if the third list is the concatenation of the first and the second list.
To say if S i sublist of L have to be TRUE the following two conditions:
L have to be a list that is the concatenation of L1 and L2
L2 have to be a list that is the concatenation of S (my sublist if exist into L list) and another list L3
This is the book explaination but it is just a litle obsucre for me...
I have try to reasoning about it and try to understand what really deeply mean...
So I think that, in some way, it is like to search if an element is member of a list using this other program:
member2(X, [X|_]).
member2(X,[_|T]):- member2(X,T).
In this program I simply say that if X is the element in the top of the list (its head) then X is in the list and the program respond true. Otherwise, if X element is not in the top of the list (or it is not my solution) I try to search it it the TAIL T of this list.
Back to the sublist program I think that the reasoning is similar
First I decompose L list in two list L1 and L2 (using conc program)**
Then I check if it is true that the concatenation of S and L3 is the L2 list.
If booth these condition it is true then S is sublist of L
I think that the L1 list have a similar role of the X element that I extract from the list in the member program.
Since the sublist S can start at the beginning of the list L, L1 can be [] and I have that I can decompose L in the concatenation of L1=[] and L2 and the I can try to decompose L2 in S and L3.
If I can do this last decomposition then the program end and I can say that it is true that S is a sublist of the original list L
If it is not true that conc(S, L3, L2) then ddo backtrack and take an other branch of computation
Is it right my declarative interpretation?
I am finding great difficulties with this example, I have also try to find a procedural explaination (using the operation trace in the Prolog shell) but I have big problem because the computation it is so big also for a short list...
The book explanation is more declarative, because it doesn't invoke Prolog's search mechanism. I would probably write this with more underscores:
sublist(S, L) :- append(_, Suffix, L), append(S, _, Suffix).
This at least makes the relationship between S and L2 (renamed Suffix) a little more clear. What we're trying to say, and this is hard to express clearly in declarative English, is that S is a sublist of L if there is a suffix of L called Suffix and S is a prefix of Suffix. Naming the other constituents only adds confusion. Prolog will internally name these variables and unify something with them as it attempts to unify everything else, but it won't share that information with the caller. Though these variables need to exist in some sense, they aren't germane to your formula or they would not be singletons. Whenever you get a singleton variable warning, replace the variable with the underscore. It will add clarity.
It happens that since the prefixes and suffixes involved can be empty lists, S can be a proper prefix of L or a proper suffix of L and everything will work out.
The declarative reading of member/2, for reference, is X is a member of a list if X is the head of the list or if X is a member of the tail of the list. Note carefully what is absent: mention of checking, success or failure, or, really, any order of operations. It is equally declarative to say X is a member of a list if it is a member of the tail or if it is the head. It is just an unavoidable fact of life that to make a computer perform a calculation it must be done in a certain order, so you have to tell Prolog things in the right order or it will enter infinite loops, but this is not an aspect of logic, just Prolog.
As we've gone over several other times, when you invoke the machinery of Prolog, you are no longer in a declarative reading. So when you say, for instance "First I decompose..." you've already left the declarative world and entered the procedural world. The declarative world doesn't have steps, even though Prolog must do things in a certain order to perform a computation on a real-life computer. Likewise, in a declarative reading you do not check things, they simply are or are not. The word backtrack also cannot appear as part of a declarative reading. The only "verb" you should be using in a declarative reading is the verb of being, "is."
That said, your Prolog/procedural readings are perfectly correct.
While learning Prolog, I'm trying to solve the following problem, using accumulators:
Write a predicate addone2/ whose first argument is a list of integers, and whose second argument is the list of integers obtained by adding 1 to each integer in the first list. For example, the query
addone([1,2,7,2],X).
should give
X = [2,3,8,3].
I created the following code:
addone([], _).
addone([E|Tail], [R|Rs]) :-
NewE is E+1,
append([R|Rs], [NewE], NewRs),
addone(Tail, NewRs).
But it's not working. Can someone tell me why? So, how do I use accumulators in Prolog?
Thanks!
anthares is correct in that you have to refine your base case. However, you are also making things very inefficiently with your append calls. In Prolog, it takes some time to get used to the power of unification, but for example, in this case it helps you to immediately set up your result list. Try the following:
addone([E|Tail], [E1|Rs]) :-
E1 is E+1,
addone(Tail, Rs).
That's really all there is to it. By immediately placing E1 in your second argument's pattern, you have already created the first element of your result list. The remaining elements Rs will be created during the recursion. A very typical Prolog pattern.
The bottom of your recursion should be addone([],[]). in order NewRs to be connected with the []