Prolog rule help - prolog

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.

Related

Is there a way to tell Prolog that the argument X of a specific predicate f(X) is always true if the predicate is true?

Apologies if this is a silly question, but I haven't been able to find an answer.
Suppose I have some predicate, proven_true(X), where X is some sort of factual statement like person(bob). Is there any way to tell Prolog that if proven_true(X) is true, then X itself is also true? Say I define proven_true(X) as
proven_true(X) :- condition_1(X), condition_2(X) ... condition_n(X).
and in my facts, all of the above conditions are true for X = person(bob). Then I not only want proven_true(person(bob)) to be true, but also person(bob) to be true.
Obviously for a specific X this would be doable, but I couldn't get it to work for variable X. My first try was something along the lines of
X :- f(x).
but that didn't work because I was treating the head of the rule itself as a variable.
Thanks in advance for any assistance!
Edit:
To clear up some confusion, suppose my code was:
proven_true(X) :- condition_1(X), condition_2(X).
condition_1(dog(fido)).
condition_2(dog(fido)).
Then I could query proven_true(dog(X)) and get fido, but if I queried dog(X), I wouldn't get a result. So if I then wanted to use the fact that fido is a dog as a condition for another rule, I'd have to wrap it in the proven_true() predicate, e.g.:
barks(X) :- proven_true(dog(X)).
What I would like is some way to have X always be true if proven_true(X) is also true. That way, I could write the above rule as
barks(X) :- dog(X).
For a specific term like dog(X), I could achieve this using
dog(X) :- proven_true(dog(X)).
but I'd like to be able to achieve it for all terms. Something like
X :- proven_true(X).
(although this doesn't work). Hopefully that clears up confusion.
You want asserta/1 or assertz/1. It will modify the Prolog database during run-time.
proven_true(X) :- condition_1(X), condition_2(X), assertz(X).
condition_1(dog(fido)).
condition_2(dog(fido)).
assertz adds the assertion at the end of the database.

How can I get facts from my knowledge base into a list?

Say I have these facts:
person(fred).
person(jim).
person(mary).
is_person(person(_)).
I would like to get a list like:
[person(fred), person(jim), person(mary)]
but my query with findall/3 does not give the expected result:
?- findall(Person,is_person(Person),ListOfPeople).
ListOfPeople = [person(_5034)].
Similarly with bagof/3:
?- bagof(Person,is_person(Person),ListOfPeople).
ListOfPeople = [person(_5940)].
I do not understand why findall/3 and bagof/3 behave like this.
The correct way:
findall(person(Person),person(Person),ListOfPeople).
or
bagof(person(Person),person(Person),ListOfPeople).
Why doesn't your approach work? Consider
findall(Person,is_person(Person),ListOfPeople).
Prolog tries to fulfill is_person(Person).
There is a fact is_person(person(_)).
So, for Person = person(_), we are good! So person(_) will be in the list.
And that's all, there are no other ways to derive is_person(Person).
To collect all the Person, we really need to ask for the Person which fulfills person(Person).
Thus:
findall(person(Person),person(Person),ListOfPeople).
Prolog will find three Person which fulfill person(Person). As the result should not be a list of Person but of person(Person) we slap a person/1 around Person in the 1st parameter, the template.
Alternatively (but a bit pointlessly), you could:
is_person(person(X)) :- person(X).
?- findall(X,is_person(X),ListOfPeople).
Here, Prolog collects all the X for which is_person(person(X)), which are all the X which appear in a (fact) person(X). Thus X is for example fred. We slap a person/1 around fred in the head of is_person/1. Done.

How to state a person knows themselves in prolog

I have the following predicates so far:
person(james).
person(jack).
knows(james,jack).
knows(jack,james).
My question is how do I use variables/constants say that someone knows themselves without explicitly going though all the persons and making them. I've tried:
knows(X,X).
but this just returns true.
You can use:
knows(X, X) :- person(X).
The advantage over knows(X, X). is that not just anything passes:
?- knows(42, 42).
true. % but it should be false

Prolog Relational Tracking without Lists

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.

False value returned in Prolog?

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).

Resources