Using OR operator with different / non existent facts in Prolog - prolog

I have a fact:
loves(romeo, juliet).
then i have an 'or' rule:
dances(juliet) :- loves(romeo, juliet).
dances(juliet) :- dancer(juliet).
As you can see dancer fact does not exist but this should be no problem and dances(juliet) should return me true. Instead it returns me true and then throws an exsitence exception about dancer fact. Is there a way to write rules for non existent facts or rules? Do I need to check if the fact exists?

To achieve "failure if not existant", you can declare your predicate dynamic using the directive dynamic/1.
For example:
:- dynamic dancer/1.
If you add this directive to your program, you get:
?- dances(X).
X = juliet .
and no errors.

As far as I know there is not a way to use a nonexistant predicate. You could either check if the rule exists using the methods described in this question or you could just have some sort of placeholder to make sure that it does exist. A rule doesn't seem very useful if it is always false, so just write a couple of the true cases before you use it.
dancer(someone). %% To make sure that fact exists
loves(romeo, juliet).
dances(juliet) :- loves(romeo, juliet).
dances(juliet) :- exists(dancer), dancer(juliet).

Technically, you could do something like this:
dances(juliet) :- catch(dancer(juliet),
error(existence_error(procedure, dancer/1), _),
false
).
Which will run dancer(juliet) if the predicate exists, fail if it doesn't, and error otherwise.
I wouldn't say this is a very advisable thing to do though.

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.

prolog, checking if all members of a list are unique without built-in predicates

I want to write the rule unique(List) that checks if all elements in List are unique. I'm not allowed to use member, but I am allowed to use 'not'. Therefore I wrote the rule 'member' myself.
I wrote this:
member(Element, [Element|_]).
member(Element, [_|List]) :-
member(Element, List).
unique([H|T]) :-
not(in_list(H, T)),
unique(T).
The member-rule is working, it checks if Element is a member of List. But the unique- rule doesn't work. For the unique-rule is was expecting it would check if H was in T and then do the same for the Header of the Tail and so on. The 'not' makes from a false statement a True-output.
When I run this rule with query ?-unique([1,2,3,4,5]) it gives False. So what's my mistake?
I just discoverd the solutions a few moments later.
I added this above:
unique([]).
unique([_,[]]).

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

Prolog Cut operator

I defined my knowledge base as:
edge(mammal,isa,animal).
edge(human,isa,mammal).
edge(simba,isa,human).
edge(animal,swim,bybirth).
edge(human,swim,mustlearn).
path(X,Y) :- edge(X,isa,Y).
path(X,Y) :- edge(X,isa,Z), path(Z,Y).
swim(X,Y) :- edge(X,swim,Y).
swim(X,Y) :- path(X,Z), swim(Z,Y).
Now, to use the above knowledge base, I use the following:
?- swim(simba,bybirth).
?- swim(simba,mustlearn).
And for both the queries, Prolog returns true. I want Prolog to check for the property swim locally first, then look at the direct parent, and so on in a hierarchical fashion. And it should stop searching as soon as we know that Simba "mustlearn" to swim, and shouldn't look any further. Thus, it should return false for the first query and true for the second.
I know it has to be done by limiting backtracking. I tried using the cut and not operators, but couldn't succeed. Is there a way to achieve this?
I tried it and ran into a problem too. I thought this might work:
swim(X,Y) :- once((edge(X,swim,Y); path(X,Z), swim(Z,Y))).
It doesn't work, because if Y is already instantiated on the way in, the first step will fail to unify and it will try the second route going through the human intermediate. So even though the query only produces one result, it can be fooled into producing swim(simba, bybirth). The solution is to force Prolog to commit to a binding on another variable and then check that binding after the commitment:
swim(X,Y) :-
once((edge(X,swim,Method); path(X,Z), swim(Z,Method))),
Method = Y.
This tells Prolog, there is only one way to get to this method, so find that method, and then it must be Y. If you find the wrong method, it won't go on a search, it will just fail. Try it!

Prolog: Replace fact using fact

I am trying to implement a predicate replace(+OldFact,+NewFact)
which succeed only if the OldFact existed. If this succeeds then the
NewFact must be added to the set of clauses and the OldFact must be
deleted.
How do I do this?
I am not able to figure out clearly that how to achieve this
replacement using facts as well as how to use those assert and retract
database manipulation commands.
Thanks.
If I take the request at face value, you only need to use the predicates I mentioned in my comment. Your predicate would look something like this:
replace_existing_fact(OldFact, NewFact) :-
( call(OldFact)
-> retract(OldFact),
assertz(NewFact)
; true
).
I'm assuming that if the OldFact is not found, then you want the predicate simply to succeed. If failure of the predicate is acceptable if the old fact doesn't exist, this would be written simply:
replace_existing_fact(OldFact, NewFact) :-
call(OldFact),
retract(OldFact),
assertz(NewFact).
Note that if you have more than one same OldFact in the database, this predicate will backtrack for each one, replacing one occurrence on each backtrack. If you only want to replace one of them, you could use a cut:
replace_existing_fact(OldFact, NewFact) :-
call(OldFact), !, % Don't backtrack to find multiple instances of old fact
retract(OldFact),
assertz(NewFact).
Alternatively, if you want to replace each one without being prompted for backtracking:
replace_each_existing_fact(OldFact, NewFact) :-
forall(replace_existing_fact(OldFact, NewFact), true).

Resources