I'm trying to write Prolog logic for the first time, but I'm having trouble. I am to write logic that takes two lists and checks for like elements between the two. For example, consider the predicate similarity/2 :
?- similarity([2,4,5,6,8], [1,3,5,6,9]).
true.
?- similarity([1,2,3], [5,6,8]).
false.
The first query will return true as those two lists have 5 and 6 in common. The second returns false as there are no common elements between the two lists in that query.
I CANNOT use built in logic, such as member, disjoint, intersection, etc. I am thinking of iterating through the first list provided, and checking to see if it matches each element in the second list. Is this an efficient approach to this problem? I will appreciate any advice and help. Thank you so much.
Writing Prolog for the first time can be really daunting, since it is unlike many traditional programming languages that you will most likely encounter; however it is a very rewarding experience once you've got a grasp on this new style of programming! Since you mention that you are writing Prolog for the first time I'll give some general tips and tricks about writing Prolog, and then move onto some hints to your problem, and then provide what I believe to be a solution.
Think Recursively
You can think of every Prolog program that you write to be intrinsically recursive in nature. i.e. you can provide it with a series of "base-cases" which take the following form:
human(John). or wildling(Ygritte) In my opinion, these rules should always be the first ones that you write. Try to break down the problem into its simplest case and then work from there.
On the other hand, you can also provide it with more complex rules which will look something like this: contains(X, [H|T]):- contains(X, T) The key bit is that writing a rule like this is very much equivalent to writing a recursive function in say, Python. This rule does a lot of the heavy lifting in looking to see whether a value is contained in a list, but it isn't complete without a "base-case". A complete contains rule would actually be two rules put together: contains(X, [X|_]).
contains(X, [H|T]):-contains(X, T).
The big takeaway from this is to try and identify the simple cases of your problem, which can act like base cases in a recursive function, and then try to identify how you want to "recurse" and actually do work on the problem at hand.
Pattern Matching
Part of the great thing about Prolog is the pattern matching system that it has in place. You should 100% use this to your advantage whenever you can -- it is especially helpful when trying to do anything with lists. For example:
head(X, [X|T]).
Will evaluate to true when called thusly: head(1, [1, 2, 3]) because intrinsic in the rule is the matching of X. This sort of pattern matching on the first element of a list is incredibly important and really the key way that you will do any work on lists in Prolog. In my experience, pattern matching on the head of a list will often be one of the "base-cases" that I mentioned beforehand.
Understand The Flow of the Program
Another key component of how Prolog works is that it takes a "top-down" approach to reading code. What I mean by that is that every time a rule is called (except for definitions of the form king(James).), Prolog starts at line 1 and continues until it reaches a rule that is true or the end of the file. Therefore, the ordering of your rules is incredibly important. I'm assuming that you know that you can combine rules together via a comma to indicate logical AND, but what is maybe more subtle is that if you order one rule above another, it can act as a logical OR, simply because it will be evaluated before another rule, and can potentially cause the program to recurse.
Specific Example
Now that I've gotten all of my general advice out of the way, I'll actually reference the given problem. First, I'd write my "base-case". What would happen if you are given two lists whose first elements are the same? If the first element in each list is not the same, then they have to be different. So, you have to look through the second list to see if this element is contained anywhere in the rest of the list. What kind of rule would this produce? OR it could be the case that the first element of the first list is not contained within the second at all, in which case you have to advance once in the first list, and start again with the second list. What kind of rule would this produce?
In the end, I would say that your approach is the correct one to take, and I have provided my own solution below:
similarity([H|_], [H|_]).
similarity(H1|T1], [_|T2]):- similarity([H1|T1], T2).
similarity([_|T1], [H2|T2]):- similarity(T1, [H2|T2]).
Hope all of this helps in some way!
I am trying to learn Prolog and it seems the completeness of the knowledge is very important because obviously if the knowledge base does not have the fact, or the fact is incorrect, it will affect the query results. I am wondering how best to handle unknown details of a fact. For example,
%life(<name>,<birth year>,<death year>)
%ruler(<name>,<precededBy>,<succeededBy>)
Some people I add to the knowledge base would still be alive, therefore their year of death is not known. In the example of rulers, the first ruler did not have a predecessor and the current ruler does not have a successor. In the event that there are these unknowns should I put some kind of unknown flag value or can the detail be left out. In the case of the ruler, not knowing the predecessor would the fact look like this?
ruler(great_ruler,,second_ruler).
Well, you have a few options.
In this particular case, I would question your design. Rather than putting both previous and next on the ruler, you could just put next and use a rule to find the previous:
ruler(great_ruler, second_ruler).
ruler(second_ruler, third_ruler).
previous(Ruler, Previous) :- ruler(Previous, Ruler).
This predicate will simply fail for great_ruler, which is probably appropriate—there wasn't anyone before them, after all.
In other cases, it may not be straightforward. So you have to decide if you want to make an explicit value for unknown or use a variable. Basically, do you want to do this:
ruler(great_ruler, unknown, second_ruler).
or do you want to do this:
ruler(great_ruler, _, second_ruler).
In the first case, you might get spurious answers featuring unknown, unless you write some custom logic to catch it. But I actually think the second case is worse, because that empty variable will unify with anything, so lots of queries will produce weird results:
ruler(_, SucceededHimself, SucceededHimself)
will succeed, for instance, unifying SucceededHimself = second_ruler, which probably isn't what you want. You can check for variables using var/1 and ground/1, but at that point you're tampering with Prolog's search and it's going to get more complex. So a blank variable is not as much like NULL in SQL as you might want it to be.
In summary:
prefer representations that do not lead to this problem
if forced, use a special value
So I was given an assignment to try to solve this problem in Prolog, though the teacher has only covered the basics and this is essentially the only project in Prolog. I feel like I'm over thinking it and that he's just expecting too much as a first time Prolog program.
The problem is listed below, how should I go about solving this?
Write a Prolog program that solves the word problem below. As part of the solution, it should print all the crossings, with the paddler listed first.
Tom, Jack, Bill, and Jim had to cross a river using a canoe that held only two people.
In each of the three crossings from the left to the right bank of the river, the canoe had two persons, and in each of the two crossings from the right to the left bank, the canoe had one person. Tom was unable to paddle when someone else was in the canoe with him.
Jack was unable to paddle when anyone else but Bill was in the canoe with him. Each person paddled for at least one crossing.
This is what I have so far, though it "works", it doesn't make sure that everyone paddles at least once.
state(tom(Side),jim(Side),jack(Side),bill(Side),c(Side)).
initial(state(tom(l),jim(l),jack(l),bill(l),c(l))).
final(state(tom(r),jim(r),jack(r),bill(r),c(r))).
canoe(P):-P=p.
canoe(P,C):-P=p,C=c.
bad(state(tom(W),jim(X),jack(Y),bill(Z),c(C))):-
C=l,(W=c;X=c;Y=c;Z=c).
move(state(tom(W),jim(X),jack(Y),bill(Z),c(C)),
state(tom(W1),jim(X),jack(Y),bill(Z),c(C1))):-
((canoe(W1),W=r,W=C,C1=m);(canoe(W),W1=l,W1=C1)).
move(state(tom(W),jim(X),jack(Y),bill(Z),c(C)),
state(tom(W),jim(X1),jack(Y),bill(Z),c(C1))):-
((canoe(X1),X=r,X=C,C1=m);(canoe(X),X1=l,X1=C1)).
move(state(tom(W),jim(X),jack(Y),bill(Z),c(C)),
state(tom(W),jim(X),jack(Y1),bill(Z),c(C1))):-
((canoe(Y1),Y=r,Y=C,C1=m);(canoe(Y),Y1=l,Y1=C1)).
move(state(tom(W),jim(X),jack(Y),bill(Z),c(C)),
state(tom(W),jim(X),jack(Y),bill(Z1),c(C1))):-
((canoe(Z1),Z=r,Z=C,C1=m);(canoe(Z),Z1=l,Z1=C1)).
move(state(tom(W),jim(X),jack(Y),bill(Z),c(C)),
state(tom(W1),jim(X1),jack(Y),bill(Z),c(C1))):-
((canoe(X1,W1),W=l,W=X,W=C,C1=m);
(canoe(X,W),W1=r,W1=X1,W1=C1)).
move(state(tom(W),jim(X),jack(Y),bill(Z),c(C)),
state(tom(W1),jim(X),jack(Y),bill(Z1),c(C1))):-
((canoe(Z1,W1),W=l,W=Z,W=C,C1=m);
(canoe(Z,W),W1=r,W1=Z1,W1=C1)).
move(state(tom(W),jim(X),jack(Y),bill(Z),c(C)),
state(tom(W),jim(X1),jack(Y1),bill(Z),c(C1))):-
((canoe(X1,Y1),Y=l,Y=X,Y=C,C1=m);
(canoe(X,Y),Y1=r,Y1=X1,Y1=C1)).
move(state(tom(W),jim(X),jack(Y),bill(Z),c(C)),
state(tom(W),jim(X1),jack(Y),bill(Z1),c(C1))):-
((canoe(Z1,X1);canoe(X1,Z1)),
Z=l,Z=X,Z=C,C1=m);
((canoe(Z,X);canoe(X,Z)),Z1=r,Z1=X1,Z1=C1).
move(state(tom(W),jim(X),jack(Y),bill(Z),c(C)),
state(tom(W),jim(X),jack(Y1),bill(Z1),c(C1))):-
((canoe(Y1,Z1);canoe(Z1,Y1)),
Y=l,Y=Z,Y=C,C1=m);
((canoe(Y,Z);canoe(Z,Y)),Y1=r,Y1=Z1,Y1=C1).
find(Path):-initial(S),rez(S,Path).
bkt(State,Path,[Path|State]):-final(State).
bkt(State,Path,Sol):-move(State,Next),not(bad(Next)),
not(member(Next,Path)),bkt(Next,[Path|Next],Sol).
rez(State,Sol):-bkt(State,[State],Sol).
start:-find(D),writef('%w\n',D).
(This answer may be too late, but since this is quite a classic problem/puzzle which has many many variants, I think it might still be useful to try and break the problem down a little bit.)
As yet stated in answers above, I think it might be a good idea to do some refactoring and try to write a simpler, more manageable model for this problem. What I mean with this is if someone asked you for example to 'quickly modify' your code to integrate let's say a fifth person to the puzzle, it wouldn't be much fun to refactor the code above.
You could start -this is just one approach to give you an idea- by encoding the configuration of the 4 men in a list, where we use an 'l' or 'r' to specify whether someone is located on the left or right side of the river bank. This would give us an initial state like so:
% Tom, Jack, Bill, and Jim are all on the left side
[l,l,l,l]
And we want to reach the goal state:
% Tom, Jack, Bill, and Jim are all on the right side
[r,r,r,r]
This gives us a model that is a lot easier to read/understand (imo).
We could then think some more about how we are going to encode actual transports between the river banks. We wrote our list configuration to specify which person is located where, so now we need a Prolog predicate that can transform one configuration into another. Let's say:
transport(StartState,[Persons],EndState)
Now, for the implementation, instead of explicitly matching on all possible moves (like you do in your current code), it's always a good idea to try and generalise what exactly is happening (the fun part in Prolog :) ).
Without writing too complicated code at once, we break the problem down into small pieces:
% Facts defining a crossing of the river
cross(l,r).
cross(r,l).
% Transport example for Tom
transport([X,Jack,Bill,Jim],[tom],[Y,Jack,Bill,Jim]) :- cross(X,Y).
As you can see, we now defined 'transport' in a very simple way: it is known that Tom will only cross the river on his own, so we use the cross fact to change his location. (Note that Jack, Bill and Jim are just variables stating either an 'l' or 'r' as indication on which river bank those people are located. Since Tom only crosses on his own, these variables will not change!). We could write this even more abstract and don't match specifically on 'tom', but I'm trying to keep it simple in this example.
Of course, we still need to express which crossings are valid and which aren't. From your question: "In each of the three crossings from the left to the right bank of the river, the canoe had two persons, and in each of the two crossings from the right to the left bank, the canoe had one person."
These conditions can very easily be coded using our 'transport' predicate since the initial state (first arg) tells us whether we are crossing from left to right, or vice versa and our 2nd argument specifies a list of which persons are crossing. In other words, the direction of the crossing and the amount of passengers are already known and it seems a bit trivial to write down these conditions here.
Next up: "Jack was unable to paddle when anyone else but Bill was in the canoe with him." Again, this is already very easily written together in our 'transport' (note that I've used wildcards to leave out information we don't care about for this particular condition, but of course, this will probably be different in the resulting end code. It is merely to give an example.):
% Transport example for Jack (Persons length = min 1 - max 2)
transport([_,_,_,_],Persons,[_,_,_,_]) :-
length(Persons,2),
( member(jack,Persons) ->
member(bill,Persons)
;
* other condition(s) *
).
% Alternative with pattern matching on Persons
transport([_,_,_,_],[A,B],[_,_,_,_]) :-
* if jack is A or B, then bill is the other one *
Another quick example: "Tom was unable to paddle when someone else was in the canoe with him."
% Tom cannot peddle in a team of 2
transport([_,_,_,_],Persons,[_,_,_,_]) :-
length(Persons,2),
\+ member(tom,Persons).
As you may have noticed, we have now almost completely broken down the problem in bits and pieces that can be very easily expressed in our model and we are not far from writing the actual solver. There are however enough code examples to be found online and I don't think it's necessary to work out any more of the code right here.
More inspiration can be found by searching for the classic Fox-Goose-Beans/Cabbage puzzle.
Good luck to everyone!
I'm a beginner at prolog and I'm trying to make pacman move by itself using netlogo and prolog. So this is part of my code:
walkfront(_,_,_,_,_,_,Pacman,DirP,Lab,Ghost,_,Pellet,_,_,Decision) :-
findall(Dir,
( member(Dir,[0,90,180,270]),
\+ ( member((G,false),Ghost), dangerous(Pacman,G,2,Dir,_) ) ),
L),
findall(Dir,(member(Dir,[0,90,180,270]),(member(P,Pellet))),T),
chooseNotDangerous(L,Pacman,DirP,Lab,Dir,T)
walkfront(_,_,_,_,_,_,Pacman,DirP,Lab,Ghost,_,Pellet,_,_,Decision) this line has all the lists of information I'm getting from netlogo, Pacman has the position of pacman (x,y), DirP is the direction pacman is facing, Lab is the free spaces in the maze, Ghost is the position of the ghosts (x,y,eaten?), Pellet is a list of all the positions of the pellets (x,y), Decision is the output choosen by pacman.
The first findall is supposed to give me all the directions (Dir) that don't have ghosts and that aren't dangerous and save them in a list called L.
The second findall, I wanted it to give me all the directions that have pellets and save them in a list called T.
My question is if this findall's are correct because my code isn't working for some reason and I think it might be beacause of the second findall.
Thank you for helping me :).
Technically, findall/3 never fails, as it will complete with an empty result list if none of the calls succeed (well, exceptions apart, if your Prolog implements them).
Of course, it's impossible to answer your question, without all the code. And probably, even with all the code available, you will get little - if any - help, because the structure of your program seems more complex than what could be advisable.
Prolog is a language with a relational data model, and such data model is better employed when it's possible to keep the relations clean, best if normalized. Now you have a predicate with 16 arguments. How are you going to ensure all of them play correctly together ?
I would say - not change now the structure of your program, if you succeed debugging it ok. But the next program - if any - use another style, and the facilities that your Prolog offers to implement data hiding.
Plain old Prolog 'only' had compound terms: you code should likely be
packman(CurrPackManState, CurrGhostsState, NextPackManState, NextGhostsState) :-
...
where CurrGhostsState should be a list of CurrGhostState, and each element of this list should unify with an appropriate structure, hiding information about position, color, shape, etc...
SWI-Prolog now has dicts, and any Prolog will let you use DCGs to reduce the complexity of the code. See this page from Markus Triska, look for 'Implicitly passing states around'.
Also, you can always choice to put some less frequently updated info - like for instance the maze structure - in global database, with assert/retract.
I just learned prolog for a week and I have to write a prolog program that counts the number of times an element appearing in a list L at even positions.
I have try to figure out the problem for the from am 12:00 to now (am 4:00 last 16 hours) and fail.
1.What I have tried until now is like
count(_,[],0).
count(E,[E|L],C):-!,count(E,L,C1),C is C1+1.
count(E,[A|L],C):-atom(A),count(E,L,C),!.
count(E,[A|L],C):-count(E,A,C1),count(E,L,C2),C is C1+C2.
It just can count the occurence of the whole list within the element is a list.
2.The second is takeoutsecond occurence element in list
What I have tried until now is like but fail
takeout(A,[A|B],B).
takeout(A,[B|C],[B|D]) :- takeout(A,C,D).
takeoutSecond(A,[B|C],[B|D]):- takeoutSecond(A,C,D).
takeoutSecond(A,[A|B],[A|C]):- takeout(A,B,C).
3.Can you give me some hint if takeoutsecondlast without reverse? I will appreciate it!
Can you give me some hint, I do my all effort on it.
I will reply not now because I stay up late, and I apology for it.
Thank for reading my question.
you miss a very simple use of Prolog pattern matching: namely, to match the second element just ignore the first
match_second(E, [_,E|Rest], Rest).
You can use that as 'building block' for your assignment, but it's so simple that really you'll be better to integrate it in your efforts. Use that pattern in the head of your predicates.