I'm confused about the structure of how my Prolog rules should be written.
Lets say, I want to state that only birds can fly.
Should my rule be written as
fly(X):- bird(X).
or
bird(X):-fly(X).
What is the difference in meaning between them?
Furthermore, do I need to explicitly state that if the entity is not a bird, it cannot fly?
Also, if I wish to say...
I can either go to the zoo or the library. Either zoo or library, but not both. How should it be?
I am assuming it to be..
go_there(X,Place):-
go_there(X,zoo),
go_there(X,library).
Please go gentle on me, as this is my first try with Prolog programming! Thank you!
To say that only birds can fly can be expressed as, if a creature can fly, then it must be a bird. Depending upon the semantics of this terse phrase, it might leave open the possibility that there could be some birds that cannot fly.
Therefore, the predicate:
fly(X) :- bird(X).
Would not be correct. This says that, if X is a bird, then X can fly, which is not what the only birds can fly says, logically.
The more direct translation to Prolog would then be:
bird(X) :- fly(X).
It says that, X is a bird if X can fly (or, if X can fly, then X must be a bird).
The exclusivity of only would occur due to the absence of any other predicate that says some other creature can fly, such as:
bee(X) :- fly(X).
Regarding the second question:
go_there(X,Place):-
go_there(X,zoo),
go_there(X,library).
This says that, X goes to Place if X goes to the zoo, and X goes to the library. This doesn't sound at all like, X can either go to the zoo, or to the library, but not both. I could say something like:
go_there(fred, zoo).
go_there(fred, library).
These say that fred can go to the zoo, or fred can go to the library.
And then if I query:
go_there(fred, Place).
It will yield two different results for Place:
Place = zoo
Place = library
To say that X can go to one or the other, but not both, requires qualification. Does this mean within a specific period of time that X cannot go to both? Or does it mean that once X goes to one, then it can never ever go to the other? Whether the above predicate satisfies the first case is unclear. It depends upon the context. In either case, you'd need to add some Prolog logic to handle either the time aspect, or, if the "forever" case, you'd need a random selection of one or the other, and then have that selection remain persistent from that point forward.
In response to additional comments, if you to say:
go_there(human(fred), zoo).
go_there(human(fred), library).
You are choosing to represent a person, such as fred, as a human via a functor, human/1. In order to designate fred as human, you have to carry the functor around with fred and always refer to fred as human(fred) whenever used in a predicate that is looking for freds membership in the human race. If you wanted to ask if fred goes to the zoo, go_there(fred, zoo). would fail, unfortunately, because the fact that fred is human needs to be a part of the atom representing fred. You'd have to query, go_there(human(fred), zoo). To determine if fred is human, you would query, go_there(human(fred), _). which is also a bit awkward.
Separating the relationships is clearer:
go_there(fred, zoo).
go_there(fred, libary).
human(X) :- go_there(X, zoo).
human(X) :- go_there(X, library).
Now if you query, human(fred)., you get "true". And if you query, go_there(fred, zoo) you also get "true".
Related
I have several Prolog facts indicating that something or someone is either a person, location or object. I have a clause go(person,location) that indicated that a person moves from where they are to the location given in the clause. However, when I ask the relevant query to find out if someone is at a certain location, Prolog responds with every person that was ever there according to the clauses. How do I go about writing a rule that says that if you are in one location you are by definition not in any of the others?
It appears that you left one important aspect out when modeling the situation as Prolog facts: When did the person go to the location?
Assume you had instead facts of the form:
person_went_to_at(Person, Location, Time).
then it would be pretty easy to determine, for any point in time, where everyone was, and where they moved to last (and, therefore, are now).
You probably need to add timing information to your facts. Imagine the following situtation:
go(dad, kitchen, bathroom).
go(dad, bathroom, garage).
go(dad, garage, kitchen).
Since Prolog is (more or less) declarative, in this case, the actual order of the facts in the file does not matter. So, you cannot conclude that dad is in the kitchen, he might have started from and returned to the garage. Even if you add some kind of starting predicate, say startLoc(dad, kitchen), this does not help with loops (e.g. when you add go(dad, kitchen, outside) to the above rules).
If you add timing information (and leave out the previous room, as this is clear from the timing information), this becomes:
go(dad, bathroom,1).
go(dad, garage,2).
go(dad, kitchen,3).
The actual numbers are not relevant, just their order. You can now get the latest location by ensuring that there is no later "go" command with dad:
location(X, Y) :- go(X, Y, T), \+ ( go(X, _, T2), T2 > T ).
I have a somewhat complex predicate with four arguments that need to work when both the first and last arguments are ground/not ground, not ground/ground or ground/ground, and the second and third arguments are ground.
i.e. predicate(A,B,C,D).
I can't provide my actual code since it is part of an assignment.
I have it mostly working, but am receiving instantiation errors when A is not ground, but D is. However, I have singled out a line of code that is causing issues. When I change the goal order of the predicate, it works when D is ground and A is not, but in doing so, it no longer works for when A is ground and D is not. I'm not sure there is a way around this.
Is there a way to use both lines of code so that if the A is ground for instance it will use the first line, but if A is not ground, it will use the second, and ignore the first? And vice versa.
You can do that, but, almost invariably, you will break the declarative semantics of your programs if you do that.
Consider a simple example to see how such a non-monotonic and extra-logical predicate already breaks basic assumptions and typical declarative properties of well-known predicates, like commutativity of conjunction:
?- ground(X), X = a.
false.
But, if we simply exchange the goals by commutativity of conjunction, we get a different answer:
?- X = a, ground(X).
X = a.
For this reason, such meta-logical predicates are best avoided, especially if you are just beginning to learn the language.
Instead, better stay in the pure and monotonic subset of Prolog. Use constraints like dif/2 and CLP(FD) to make your programs usable in all directions, increasing generality and ease of understanding.
See logical-purity, prolog-dif and clpfd for more information.
I meet some problem when I try to implement
friends(mia, ellen).
friends(mia, lucy).
friends(X,Y) :-
friends(X,Z),
friends(Y,Z).
and when i ask ?- friends(mia, X)., it run out of local stack.
Then I add
friends(ellen, mia) friends(lucy, mia)
I ask ?- friends(mia, X). ,it keeps replying X = mia.
I can't understand, why it is recursive?
First, two assumptions:
the actual code you wanted to write is the following one, with appropriate dots:
friends(mia,ellen).
friends(mia,lucy).
friends(X,Y) :-
friends(X,Z),
friends(Z,Y).
transivity holds: friends of friends are my friends too (I would rather model friendship as a distance: "A is near B" and "B is near C" does not necessarly imply "A is near C"). repeat's answer is right about figuring out first what you want to model.
Now, let's see why we go into infinite recursion.
Step-by-step
So, what happens when we ask: friends(mia,X) ?
First clause gives Y=ellen (you ask for more solutions)
Second clause gives Y=lucy (you ask again for more solutions)
Stack overflow !
Let's detail the third clause:
I want to know if friends(mia,Y) holds for some variable Y.
Is there a variable Z such that friends(mia,Z) holds ?
Notice that apart from a renaming from Y to Z, we are asking the same question as step 1 above? This smells like infinite recursion, but let's see...
We try the first two clauses of friends, but then we fail because there is no friends(ellen,Y) nor friends(lucy,Y), so...
We call the third clause in order to find if there is a transitive friendship, and we are back to step 1 without having progressed any further => infinite recursion.
This problem is analogous to infinite Left recursion in context-free grammars.
A fix
Have two predicates:
known_friends/2, which gives direct relationships.
friends/2, which also encodes transitivity
known_friends(mia,ellen).
known_friends(mia,lucy).
friends(X,Y) :- known_friends(X,Y).
friends(X,Y) :- known_friends(X,Z), friends(Z,Y).
Now, when we ask friends(mia,X), friends/2 gives the same answer as the two clauses of known_friends/2, but does not find any answer for the transitive clause: the difference here is that known_friends will make a little progress, namely find a known friend of mia (without recursion), and try to find (recursively) if that friend is a friend of some other people.
Friends' friends
If we add known_friends(ellen, bishop) :-) then friends will also find Y=bishop, because:
known_friends(mia,ellen) holds, and
friends(ellen,bishop) is found recursively.
Circularity
If you add cyclic dependencies in the friendship graph (in known_friends), then you will have an infinite traversal of this graph with friends. Before you can fix that, you have to consider the following questions:
Does friends(X,Y) <=> friends(Y,X) hold for all (X,Y) ?
What about friends(X,X), for all X ?
Then, you should keep a set of all seen people when evaluating friends in order to detect when you are looping through known_friends, while taking into account the above properties. This should not be too difficult too implement, if you want to try.
This clause of friends/2 is flawed:
friends(X,Y) :- friends(X,Z),friends(Y,Z).
Translate that into English: "If X and Y have a mutual friend Z, then X and Y are friends."
Or, let's specialize, let X be "me", let Y be my neighbour "FooBert", and let Z be "you": So if I am your friend and FooBert is your friend... does that make me and FooBert friends? I don't think so, I hate that guy---he always slams the door when he gets home. :)
I suggest you consider the algebraic properties that the relation friends/2 should have, the ones it may have, and ones it should not have. What about reflexivity, symmetry, anti-symmetry, transitivity?
I am working on a dictionary-like program with prolog, and my code goes like this:
define(car,vehicle).
define(car,that).
define(car,has).
define(car,four).
define(car,wheels).
define(wheels,round).
define(wheels,object).
define(wheels,used).
define(wheels,in).
define(wheels,transportation).
defined(X):-define(X,_).
anotherdefined(X):- \+ undefined(X).
undefined(X):- \+define(X,_).
I am trying to write a defined/1 predicate which will give me:
?-defined(X).
X = car ;
X = wheels ;
false.
Yet, my defined/1 gives me X=car. five times (naturally) for everytime it counters define(car,_).
and my anotherdefined/1 gives me only true. What is the method to stop prolog backtracking to the other instances of define(car,_).,and skip to define(wheels,_).?
Edit: I have written the following lines to get the result I want with givedefinedword/1,
listdefined(X):-findall(Y,defined(Y),Z),sort(Z,X).
givedefinedword(X):-listdefined(List),member(X,List).
However since I wanted an efficient predicate (which I will use in many others) it beats the purpose. This predicate does too much process.
Or, Would it be better to use a predicate that modifies the code? say prepares a list of defined words, and modifies it when new definitions are added.
Thanks.
If you change define to relate items and lists, like
definelist(car, [vehicle, that, has, four, wheels]).
% etc.
defined(X) :- definelist(X, _).
then defined will no longer produce duplicates, nor require linear space.
Of course, a query define(X, Y) must now be performed as definelist(X, L), member(Y, L). If you want this to be efficient as well, you may need to duplicate all definitions.
What are you trying to achieve with your program? It seems that you want to have facts in the form:
"A car is a vehicle that has four wheels"
"Wheels are round objects used in transportation" (a bit vague)
How are you going to use these facts? #larsmans suggestion if perfectly fine, if you want to just have your statement as a "sentence". It really depends what you will do with the information though.
Consider structuring the information in your database:
is(car, vehicle).
is(bicycle, vehicle).
is(boat, vehicle).
has(car, wheel(four)).
has(car, motor).
has(bicycle, wheel(two)).
Given this database, you can at least ask a question like, "what vehicles are there?", "does a bicycle have a motor?", or maybe, "how many wheels does a car have?", or "which vehicles have no wheels?"
?- is(X, vehicle).
?- has(bicycle, motor).
?- has(car, wheel(N)).
?- is(X, vehicle), \+ has(X, wheel(_)).
and so on.
Once you have defined your problem better, you can define your data structures better, which will make writing a program to solve your problem easier.
Clue
Four guests (Colonel Mustard, Professor Plum, Miss Scarlett, Ms. Green) attend a dinner party at the home of Mr. Boddy. Suddenly, the lights go out! When they come back, Mr Boddy lies dead in the middle of the table. Everyone is a suspect. Upon further examination, the following facts come to light:
Mr Boddy was having an affair with Ms. Green.
Professor Plum is married to Ms. Green.
Mr. Boddy was very rich.
Colonel Mustard is very greedy.
Miss Scarlett was also having an affair with Mr. Boddy.
There are two possible motives for the murder:
Hatred: Someone hates someone else if that other person is having an affair with his/her spouse.
Greed: Someone is willing to commit murder if they are greedy and not rich, and the victim is rich.
Part A: Write the above facts and rules in your Prolog program. Use the following names for the people: colMustard, profPlum, missScarlet, msGreen, mrBoddy. Be careful about how you encode (or don’t encode) symmetric relationships like marriage - you don’t want infinite loops! married(X,Y) :- married(Y,X) % INFINITE LOOP
?-suspect(Killer,mrBoddy)
Killer = suspect_name_1
Killer = suspect_name_2
etc.
Part B: Write a predicate, suspect/2, that determines who the suspects may be, i.e. who had a motive.
?-suspect(Killer,mrBoddy)
Killer = unique_suspect.
Part C: Add a single factto your database that will result in there being a unique suspect.
Clearly indicate this line in your source comments so that it can be removed/added for
grading.
?-suspect(Killer,mrBoddy)
Killer = unique_suspect.
Whenever I type in
suspect(Killer,mrBoddy).
I get
suspect(Killer,mrBoddy).
Killer = profPlum
I'm missing
Killer = colMustard.
Here's my source.
%8) Clue
%facts
affair(mrBoddy,msGreen).
affair(missScarlett, mrBoddy).
affair(X,Y) :- affair(X,Y), affair(Y,X).
married(profPlum, msGreen).
married(X,Y) :- married(X,Y), married(Y,X).
rich(mrBoddy).
greedy(colMustard).
%rules
hate(X,Y) :- married(X,Spouse), affair(Y,Spouse).
greed(X,Y) :- greedy(X), not(rich(X)), rich(Y).
%suspect
suspect(X,Y):- hate(X,Y).
suspect(X,Y):- greed(X,Y).
There are two kinds of problems with your program. One is on the procedural level: you observed that Prolog loops; the other is on the logical level — Prolog people call this rather the declarative level. Since the first annoying thing is this endless loop, let's first narrow that down. Actually we get:
?- suspect(Killer,mrBoddy).
Killer = profPlum ;
ERROR: Out of local stack
You have now several options to narrow down this problem. Either, go with the other answer and call up a tracer. While the tracer might show you the actual culprit it might very well intersperse it with many irrelevant steps. So many that your mind will overflow.
The other option is to manually modify your program by adding goals false into your program. I will add as many false goals as I can while still getting a loop. The big advantage is that this way you will see in your source the actual culprit (or to be more precise one of potentially many such culprits).1 After trying a bit, this is what I got as failure-slice:
?- suspect(Killer,mrBoddy), false.
married(profPlum, msGreen) :- false.
married(X,Y) :- married(X,Y), false, married(Y,X).
hate(X,Y) :- married(X,Spouse), false, affair(Y,Spouse).
suspect(X,Y):- hate(X,Y), false.
suspect(X,Y):- false, greed(X,Y).
All remaining parts of your program were irrelevant, that is, they are no longer used. So essentially the rule
married(X,Y) :- married(X,Y), married(Y,X).
is the culprit.
Now, for the declarative part of it. What does this rule mean anyway? To understand it, I will interpret :- as an implication. So provided what is written on the right-hand side is true, we conclude what is written on the left-hand side. In this case:
Provided X is married to Y and Y is married to X
we can conclude that
X is married to Y.
This conclusion concluded what we have assumed to be true anyway. So it does not define anything new, logically. You can just remove the rule to get same results — declaratively. So married(profPlum, msGreen) holds but married(msGreen, profPlum) does not. In other words, your rules are not correct, as you claim.
To resolve this problem, remove the rule, rename all facts to husband_wife/2 and add the definition
married(M,F) :- husband_wife(M,F).
married(F,M) :- husband_wife(M,F).
So the actual deeper problem here was a logical error. In addition to that Prolog's proof mechanism is very simplistic, turning this into a loop. But that is not much more than a welcome excuse to the original logical problem.2
Footnotes:1 This method only works for pure, monotonic fragments. Non-monotonic constructs like not/1 or (\+)/1 must not appear in the fragment.
2 This example is of interest to #larsmans.
The problem is the recursive rules of the predicates affair/2 and married/2. Attempting to use them easily leads to an endless loop (i.e. until the stack memory is exhausted). You must use a different predicate in each case to represent that if X is having an affair with Y, then Y is having an affair with X. You also need to change your definition of the suspect/2 predicate to call those new predicates.
To better understand why you get an endless loop, use the trace facilities of your Prolog system. Try:
?- trace, suspect(Killer, mrBoddy).
and go step by step.