How to state a person knows themselves in prolog - 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

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.

Representing truth regarding beliefs in prolog

How to make this (or something similar) work in Prolog:
belief(john,red(apple)).
belief(peter,red(apple)).
X :- belief(john,X), belief(peter,X).
And get true. for the following query (while consulting above):-
?- red(apple).
First, it's useful to define a little helper to capture when all (relevant) persons believe something:
all_believe(Belief) :-
belief(john, Belief),
belief(peter, Belief).
Then you can define, for example:
red(Object) :-
all_believe(red(Object)).
green(Object) :-
all_believe(green(Object)).
And with your given set of beliefs you get:
?- red(apple).
true.
?- green(apple).
false.
This works. It requires you to define similar rules for any term that you want to use as a belief.
You can make this a bit shorter with macro definitions using term_expansion:
term_expansion(declare_belief(Belief),
Belief :- all_believe(Belief)).
This means that every top-level definition in your source code of the form declare_belief(Belief) should be treated as if you had written Belief :- all_believe(Belief) instead (with the variable Belief substituted appropriately).
So now you can just write this:
declare_belief(red(_)).
declare_belief(green(_)).
and it will be treated exactly like the longer definitions for red(Object) and red(Object) above. You will still have to write this kind of declaration for any term that you want to use as a possible belief.
Prolog does not allow the head of a rule to be just a variable. The head must be a nonvar term, whose functor (i.e., name and arity) identifies the predicate being defined. So, a possible solution would be something like this:
true_belief(X) :-
belief(john, X),
belief(peter, X).
belief(john, red(apple)).
belief(peter, red(apple)).
Examples:
?- true_belief(red(apple)).
true.
?- true_belief(X).
X = red(apple).

turning off Redefined static procedure in prolog

anyone of you could tell me how to turn off "Redefined static procedure" warnings?
I red online documentation of swi-prolog and i found this predicate no_style_check(ultimate) that in principle should turn off these warnings, but when i execute this predicate
main:-
no_style_check(singleton),
no_style_check(discontiguous),
no_style_check(multiple),
require,
test_all.
i received this error
ERROR: Domain error: style_name' expected, foundmultiple'
Anyone knows an alternative way to do this or could tell me why i receive this error ?
Thanks in advance!
Prolog is a pretty loosey-goosey language, so by default it warns you when you do certain things that are not wrong per se, but tend to be a good indication that you've made a typo.
Now, suppose you write something like this:
myfoo(3, 3).
myfoo(N, M) :- M is N*4+1.
Then from the prompt you write this:
?- asserta(myfoo(7,9)).
ERROR: asserta/1: No permission to modify static procedure `myfoo/2'
ERROR: Defined at user://1:9
What's happening here is that you haven't told Prolog that it's OK for you to modify myfoo/2 so it is stopping you. The trick is to add a declaration:
:- dynamic myfoo/2.
myfoo(3, 3).
myfoo(N, M) :- M is N*4+1.
Now it will let you modify it just fine:
?- asserta(myfoo(7,9)).
true.
Now suppose you have three modules and they each advertise themselves by defining some predicate. For instance, you might have three files.
foo.pl
can_haz(foo).
bar.pl
can_haz(bar).
When you load them both you're going to get a warning:
?- [foo].
true.
?- [bar].
Warning: /home/fox/HOME/Projects/bar.pl:1:
Redefined static procedure can_haz/1
Previously defined at /home/fox/HOME/Projects/foo.pl:1
true.
And notice this:
?- can_haz(X).
X = bar.
The foo solution is gone.
The trick here is to tell Prolog that clauses of this predicate may be defined in different files. The trick is multifile:
foo.pl
:- multifile can_haz/1.
can_haz(foo).
bar.pl
:- multifile can_haz/1.
can_haz(bar).
In use:
?- [foo].
true.
?- [bar].
true.
?- can_haz(X).
X = foo ;
X = bar.
:- discontiguous does the same thing as multifile except in a single file; so you define clauses of the same predicate in different places in one file.
Again, singleton warnings are a completely different beast and I would absolutely not modify the warnings on them, they're too useful in debugging.

State facts with unbound variables

How would I state things "in general" about the facts? Suppose I need to state "everyone likes the person who likes him/her", and I have a list of people who may or may not like each other.
This is what I tried so far, but it's sure not the way to do it:
likes(dana, cody).
hates(bess, dana).
hates(cody, abby).
likes(first(Girl, OtherGirl), first(OtherGirl, Girl)).
hates(Girl, OtherGirl):- \+ likes(Girl, OtherGirl).
because this won't even compile.
everybody([dana, cody, bess, abby]).
likes_reflexive(dana, cody).
hates(bess, dana).
hates(cody, abby).
likes_reflexive(X, Y):- likes(X, Y), likes(Y, X).
hates(Girl, OtherGirl):- \+ likes(Girl, OtherGirl).
%% likes_reflikes_reflexive(X, Y):- likes(X, Y), likes(Y, X).
%% user:6: warning: discontiguous predicate likes_reflexive/2 - clause ignored
%% hates(Girhates(Girl, OtherGirl):- \+ likes(Girl, OtherGirl).
%% user:8: warning: discontiguous predicate hates/2 - clause ignored
Unfortunately I don't understand what the warnings say. Hope it makes my intention more clear. I.e. by stating one fact, I also want to state the other related fact.
If you want to change your knowledge base dynamically, you can use asserts. If you want to modify existing predicate, you should define it as dynamic, e.g. :- dynamic(likes/2).. If predicate is undefined, you can omit it.
add_mutual_likes(X, Y) :- asserta(likes(X, Y)), asserta(likes(Y, X)).
:- initialization(add_mutual_likes(dana, cody)).
initialization/1 calls add_mutual_likes(data, cody) goal when file is loaded. add_mutual_likes/2 adds two facts to a database. asserta/1 converts it's argument into a clause and adds it to a database.
| ?- [my].
yes
| ?- listing(likes/2).
% file: user_input
likes(cody, dana).
likes(dana, cody).
yes
| ?- likes(cody, dana).
yes
| ?- likes(dana, cody).
yes
| ?- add_mutual_likes(oleg, semen).
yes
| ?- listing(likes/2).
% file: user_input
likes(semen, oleg).
likes(oleg, semen).
likes(cody, data).
likes(data, cody).
yes
I use gprolog.
Let's start with the warnings. They are merely "style" suggestions. They are telling you that all the definitions for likes and hates should be together. Trust me if you have a big Prolog program it becomes a nightmare to go around tour code to get the full definition of your predicate. It would be like writing half a function in C++ and finish it in another file.
Now, you want to say "everyone likes the person who likes him/her". I'm not sure why you are using that function "first" in the code. This would be sufficient:
likes(dana, cody).
likes(Girl, OtherGirl) :- likes(OtherGirl, Girl).
The second clause reads "Girl likes OtherGirl if OtherGirl likes Girl. This won't work.
If you ask your program "is it true that cody likes dana"
? likes(cody, dana)
Prolog will reason like this:
The answer is yes if dana likes cody (using the second clause).
Yes! Because dana likes cody (using the first clause).
This is not enough to make it a correct program. Since we are in Prolog you can say: "give me another solution" (usually by entering ";" in the prompt).
Prolog will think "I only used the first clause, I haven't tried the second".
The answer is Yes also if dana likes cody (using the second clause).
The answer is Yes according to the second clause, if cody likes dana.
But that's our initial query. Prolog will give you the same answer again and again, looping forever if you asked for all the solutions.
You can do two things here. The first is telling Prolog that one solution is enough. You do this adding a "!" (that basically says, clear all the open branches left to explore).
likes(dana, cody) :- !.
likes(Girl, OtherGirl) :- likes(OtherGirl, Girl).
Another alternative is to "stratify the program".
direct_likes(dana, cody).
likes(Girl, OtherGirl) :- direct_likes(OtherGirl, Girl), !.
likes(Girl, OtherGirl) :- direct_likes(Girl, OtherGirl).
What you want is a fact where Prolog does not care about the order of arguments. Alas, something like that does not exist. What you can do instead is define facts where the implied meaning is that it is valid for all argument orders (like_each in the example below). But of course, you cannot use these facts in that way. Instead, you define the actual predicate to try (hence the or ;) all possible argument orders.
Thus, the solution is:
%% bi-directional like
like_each(dana, cody).
likes(A, B) :- like_each(A, B); like_each(B, A).
%% optional: one-directional like
% likes(cody, sarah).
Also, be careful with
hates(Girl, OtherGirl):- \+ likes(Girl, OtherGirl).
If both variables are unbound (e.g., ?- hates(A,B)), it will always fail. This happens because Prolog first tries to find a match for likes, which always succeeds for two variables, and then negates the result. Thus, you cannot use hates to find all pairs who don't like each other.

Prolog rule help

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.

Resources