sitting(mary, james).
sitting(rosie, andrew).
sitting(kiera, tom).
issitting(X, Y) :- sitting(X, Y).
Hey guys, I basically want to check who the true or false values of who is sitting next to who,
When I type in the compiler
issitting(rosie, andrew).
A true value is returned, however, when I type
issitting(andrew, rosie).
A false value is returned (Which should be true because they are sitting next to each other). I don't want to add three extra lines of code should the user check for who is sitting next to each other (with all possible combinations).
How would you alter the rule to get Prolog to understand that if the user switches the names around, they're still true (NOT false).
I don't understand why it's giving me 'false' .
I'm stuck and this is the best I could get done so far :/
Thank you.
(I could just point out the problem, but then you would not learn anything. I assume you are using SWI, since you say that false is returned.)
?- issitting(andrew, rosie).
false.
Let me restate what your problem is: You are expecting that issitting(andrew, rosie) is true. But it is not. What would you do if you asked that question to a person? Probably you would ask why? Why isn't andrew sitting next to rosie? And, say, you did not understand the explanations, you might have asked another question:
Is andrew at least sitting next to anyone?
So this question is a generalization of the original question. In Prolog, we can do the very same thing with the help of variables like so:
?- issitting(andrew, Anyone).
false.
So now we know that andrew issitting next to nobody? Confused? Well, we can generalize the query once again:
Is there at least one person sitting next to anyone?
?- issitting(Person, Anyone).
Person = mary, Anyone = james
; Person = rosie, Anyone = andrew
; Person = kiera, Anyone = tom.
So there are some persons around. Effectively, the reason is that you have sitting/2 and another relation issitting/2. You need to generalize issitting/2 by adding the following rule:
issitting(X, Y) :- sitting(Y, X).
But the point was to show you a good general debugging strategy:
In case of unexpected failure, try to generalize your query (and your program).
Related
I'm new to Prolog and having a bit of difficulty. I have:
man(ken).
man(tom).
woman(juli).
father(ken, tom).
father(ken, juli).
male(A) :- man(A).
brother(A,B) :- male(A), father(C,A), father(C,B), (A \= B).
I know the male/man is redundant, but it's part of the assignment. Anyway, when I try something like:
|?- brother(tom, juli).
I get "no" as the response. I'm sure I've made a stupid, simple mistake, but my lack of understanding is making it very hard to find. Can anyone see what my problem is?
When you enter:
|?- brother(tom, juli).
You'll see a response something like this (SWI Prolog):
true ? ;
no
| ?-
So it first responds with "true" (gives a match) and then, after you enter ; to show more solutions, it says "no" to indicate there are no further solutions. Some prolog interpreters may say "no" or "false" in this case, with the same meaning. This response from the prolog interpreters initially throws many a new prolog user.
You could, alternatively, press "enter" which just means you're done and don't want to see any further solutions:
true ?
yes
| ?-
Then you get "yes".
I am trying to get a predicate to relate from 1 fact to another fact and to keep going until a specified stopping point.
For example,
let's say I am doing a logistics record where I want to know who got a package from who, and where did they get it from until the end.
Prolog Code
mailRoom(m).
gotFrom(annie,brock).
gotFrom(brock,cara).
gotFrom(cara,daniel).
gotFrom(daniel,m).
gotFrom(X,Y) :- gotFrom(Y,_).
So what I am trying to do with the predicate gotFrom is for it to recursively go down the list from what ever point you start (ex: gotFrom(brock,Who)) and get to the end which is specified by m, which is the mail room.
Unfortunately when I run this predicate, it reads out,
Who = annie.
Who = brock.
Who = cara.
etc.etc....
I tried stepping through the whole thing but Im not sure where it goes from brock to annie, to cara and all the way down till it cycles through trues for infinity. I have a feeling that it has something to do with the wildcard in the function (_), but Im not sure how else I could express that part of the function in order for the predicate to search for the next fact in the program instead of skipping to the end.
I tried using a backcut (!) in my program but it gives me the same error.
Any help is greatly appreciated. I don't want code I just want to know what I am doing wrong so I can learn how to do it right.
Thanks.
I'm afraid this rule is meaningless:
gotFrom(X,Y) :- gotFrom(Y,_).
There is nothing here to constrain X or Y to any particular values. Also, the presence of singleton variable X and the anonymous variable _ means that basically anything will work. Try it:
?- gotFrom([1,2,3], dogbert).
true ;
true ;
What I think you're trying to establish here is some kind of transitive property. In that case, what you want is probably more like this:
gotFrom(X,Z) :- gotFrom(X, Y), gotFrom(Y, Z).
This produces an interesting result:
?- gotFrom(brock, Who).
Who = cara ;
Who = daniel ;
Who = m ;
ERROR: Out of local stack
The reason for the problem may not be immediately obvious. It's that there is unchecked recursion happening twice in that rule. We recursively unify gotFrom/2 and then we recursively unify it again. It would be better to break this into two predicates so that one of them can be used non-recursively.
got_directly_from(annie,brock).
got_directly_from(brock,cara).
got_directly_from(cara,daniel).
got_directly_from(daniel,m).
gotFrom(X,Y) :- got_directly_from(X, Y).
gotFrom(X,Z) :- got_directly_from(X, Y), gotFrom(Y, Z).
This gives us the desired behavior:
?- gotFrom(brock, Who).
Who = cara ;
Who = daniel ;
Who = m ;
false.
Notice this one is resilient to my attack of meaningless data:
?- gotFrom([1,2,3], dogbert).
false.
Some general advice:
Never ignore singleton variable warnings. They are almost always a bug.
Never introduce a cut when you don't understand what's going on. The cut should be used only where you understand the behavior first and you understand how the cut will affect it. Ideally, you should try to restrict yourself to green cuts—cuts that only affect performance and have no observable effects. If you don't understand what Prolog is up to, adding a red cut is just going to make your problems more complex.
first off thanks for helping. I am writing a prolog program describing family relationships, including all versions of in-laws. The logic is all there, what I need help with is some prolog problems as I am not very experienced with it. I am trying to set up multiple possibilities for each rule through use of semicolons.
The way I am treating in-laws is so that my brother in law is also my brother, so I need multiple checks to see which is true. I want prolog to return true, and only true, if any of the options are true. However, it returns true and false as possible options, since of course one of the options is always going to be false and the other is always going to be true. Either they are my brother in law, or my natural brother. I cant get prolog to return true only, and not have the option of false as another answer. If anyone has any advice it would be great. Relevant code is included below. So, if I type "brother(baby,dad)." I get true and false as possible answers when all I want is false. However, "brother(dad,baby)." only returns true. But I am rambling now. Sorry if any of the code is confusing with the baby dad stuff. Thanks!
/*facts for relationships*/
female(widow).
female(redhair).
spouse(i,widow).
spouse(widow,i).
spouse(dad,redhair).
spouse(redhair,dad).
child(i,dad).
child(redhair,widow).
child(baby,i).
child(onrun,dad).
male(onrun).
male(baby).
male(dad).
male(i).
/*rules*/
daughter(D,P):-
female(D), (child(D,P);(spouse(P,S),child(D,S))).
son(D,P):-
male(D), (child(D,P);(spouse(P,S),child(D,S))).
mother(X,Y):-
female(X),
child(Y,X).
father(X,Y):-
male(X),
child(Y,X).
son_in_law(C,P):-
male(C),spouse(C,S),
(child(S,P);(spouse(P,W),child(S,W))).
daughter_in_law(C,P):-
female(C),spouse(C,S),
(child(S,P);(spouse(P,W),child(S,W))).
brother(S1,S2) :- male(S1),
(child(S1,P) = child(S2,P2));
(child(S1,P),child(S2,P2),spouse(P,P2));
((child(S1,P),son_in_law(S2,P));(child(S2,P),son_in_law(S1,P))).
These multiple answers can be preventing with the meta-predicate once/1:
?- once(brother(baby,dad)).
true.
?-
thanks for reading. I know its not the easiest to understand. child is above in the set of facts that you see. Child doubles for a test to get parents. So when I pass in brother(baby, dad) the program then calls child(baby,X)=child(dad,X) the child function is being given the child, so it returns the parent. I then check to see if the parents are the same, as that would mean that the two are brothers.
I am new to Prolog and am experimenting around with some stuff, in particular i'm thinking about how to do a certain thing in prolog. I am aware of facts and rules, facts being something of the sort
specialCustomer(x). //person x is a specialcustomer
and rules:
totalSpend(x,500) :- specialCustomer(x). //if x spends 500, he is a special customer
Would this fact and rule be valid in prolog? Is the rule wrong? How would i be able to query this through prolog? As in would a call of
totalSpend(bob,500).
be a valid call?
sorry if i am answering my own question, i just seem to be a bit...well confused!
If you want to say that Bob, Jim and everyone who spends more than 500 are special customers, then define some people's spending, you would define it as follows:
specialCustomer(bob).
specialCustomer(jim).
specialCustomer(Who) :-
totalSpend(Who, Amount),
Amount >= 500.
totalSpend(mary, 400).
totalSpend(jack, 600).
totalSpend(pam, 500).
Then you would query it as follows:
?- specialCustomer(jim).
true.
?- specialCustomer(mary).
false.
?- specialCustomer(jack).
true.
?- specialCustomer(pam).
true.
?- specialCustomer(X).
X = bob ;
X = jim ;
X = jack ;
X = pam.
Everything you wrote is syntactically valid, but from your comments it doesn't seem like it does what you want it to.
specialCustomer(x).
Here you're saying specialCustomer(x) is true (and specialCustomer(anything_else) is false).
totalSpend(x,500) :- specialCustomer(x).
Here you're saying that totalSpend(x,500) is true iff specialCustomer(x) is true. Since you already defined special customer to be true, you could just as well have written
totalSpend(x,500).
Your comment makes it look as if you think that the part before the :- is the condition for the part after it, but it's the other way around.
totalSpend(bob,500).
Here you're asking whether totalSpend(bob, 500) is true, but since there is no rule for bob, it will be false.
Note that x and bob are symbols, not variables. So specialCustomer(x) will be true, but specialCustomer(bob) won't be.
Maybe you want x to be a variable? For that it has to be an upper case X.
What you probably want to express is
speccust(bob).
totalSpend(X,500) :- speccust(X).
such that bob is a special customer, and if somebody spent 500, then he is a special customer.
In practice, you would save that to a file, say customer.pl, and for instance in swi-prolog load it by putting ['customer.pl'].
Then, you can put queries to the database. In this case, you maybe want to know who is a special customer, then you would state:
totalSpend(Who, 500).
and receive Who = bob.
Every member of this club is either educated or rich or both.
I wanted to write a statement very similar to above in my PROLOG code. I wrote everything else.
edu(X);rich(X) :- member(X).
This is what I had written. But then PROLOG doesn't allow any operators in the clause head. I have spent 5 hours till now trying to do various things with this statement but unable to reach a solution that works. :(
See http://en.wikipedia.org/wiki/Horn_clause for am explanation of the form of logic Prolog is based on.
Given your statement, ("Every member of this club is either educated or rich or both."), the only things you can declare to be true are:
A person is educated if they are a member and not rich.
A person is rich if they are a member and not educated.
The following, for example, are not necessarily true:
A person who is rich and educated is a member.
A member who is rich is educated.
A member who is rich is not educated.
You can't combine multiple heads. If you want edu(X) and rich(X) to be true when member(X) is true, you have to define them separately ("every member of this club is educationed" and "every member of this club is rich"):
edu(X) :-
member(X).
rich(X) :-
member(X).
The tricky part is that your original statement is not well-formed. It says that some members may be rich but not educated or vice versa. This is problematic. For example, let's take the naive case that if a member isn't rich, he's educated, and the reverse:
edu(X) :-
member(X), \+ rich(X).
rich(X) :-
member(X), \+ edu(X).
Now, according to these rules, nobody is automatically rich and educated. So long as we define every member as at least one of the two, this is fine. However, consider these facts:
member(alice).
member(bob).
member(charlie).
member(dave).
rich(alice).
edu(bob).
rich(charlie).
edu(charlie).
In this case, rich(alice) works fine, because it's a fact. edu(alice) will result in no. The reverse is true for bob. With charlie, we've defined both as facts, so both are true. But what about dave? Both edu(dave) and rich(dave) refer back to the other, creating an infinite recursion. Without any further knowledge of what you're doing, the best we can do to resolve this is to default either edu(X) or rich(X) to true:
edu(X) :-
member(X).
rich(X) :-
member(X), \+ edu(X).
Now everyone is assumed to be educated unless we explicitly declare otherwise. You could do the same thing defaulting to rich if you preferred. Short of additional information, this is the best you can do.
As a side note: the idea of using disjunctions in heads of clauses has lead to disjunctive logic programming, see, e.g., "Foundations of Disjunctive Logic Programming" by Jorge Lobo, Jack Minker, Arcot Rajaseka. edu(X);rich(X) :- member(X). would be a valid disjunctive clause. A related topic, disjunctive Datalog, has been explored by Nicola Leone, Gerald Pfeifer and Wolfgang Faber in the DLV project: http://www.dbai.tuwien.ac.at/proj/dlv/
Maybe you want to write:
member(X) :- edu(X) ; rich(X)
If someone is educated, rich or both, is a member of the club.