Want PROLOG to require == matches on already matched variables, = for others - prolog

I have this code:
contradicts(at(X,_),location(X)).
mustContradict(A, B) :- contradicts(A, B).
contradicts/2 is meant to say: if X is at somewhere, then X can't itself be a location.
mustContradict/2 is meant to say: succeed if A and B are contradictory.
When I run it to detect that if you're at a location, you can't be a location (mustContradict(at(Thing,Location),location(Thing)).) -- it succeeds, as it should. On this one, however:
mustContradict(at(Thing,Location),location(Location)).
it also succeeds, with variable assignment Thing=Location.
I could probably mangle a way to make it ensure all variables are identical when trying to match, something like:
A=at(Thing,Location),B=location(Location),
contradicts(A,AsContradiction),
B==AsContradiction.
but then it would fail on the first test, trying to verify that a Thing that is "at" something can't be a location.
What I think I want is to be able to distinguish variables that are already assigned to other variables from those that are so far not matched to anything.

You shouldn't check your predicates with variables (starting with uppercase), but with terms (starting with lowercase).
mustContradict(at(thing,location),location(location)). fails as it should since thing doesn't equal location. In your example you use variables that can be assigned anything.
I have no idea why you are reassigning mustContradict(A, B) :- contradicts(A, B).
you can change contradicts definition to contradicts(at(X,Y),location(X)) :- not(X == Y).
I wonder if this is not what you wanted to achieve:
at(thing, location).
at(thingLocation, location).
location(location).
location(thingLocation).
contradicts(X) :- at(X,_), location(X).
now contradicts(X). succeeds with X = thingLocation

Looks like the solution was to convert all variables to atoms. Only converting those that were shared or repeated meant that the others could bind to inappropriate things (as in the first example), so the behavior didn't change.
Binding them to atoms, as in this code:
contradicts(at(X,_),location(X)).
mustContradict(X,Y) :-
replaceVariablesWithAtoms(X,NewX), replaceVariablesWithAtoms(Y,NewY),
contradicts(NewX,NewY).
replaceVariablesWithAtoms(Term,NewTerm) :-
Term =.. TermAsList,
terms_to_atoms(TermAsList,NewTermAsList),
NewTerm =..NewTermAsList.
terms_to_atoms([],[]).
terms_to_atoms([H|T],[NewH|NewT]) :-
terms_to_atoms(T,NewT),
term_to_atom(H,NewH).
gives the right answer to both queries.
?- mustContradict(at(Thing,Location),location(Thing)).
true.
?- mustContradict(at(Thing,Location),location(Location)).
false.

Wouldn't it be easier just to write it as you have defined the problem statement:
I have this code:
contradicts(at(X,_),location(X)).
mustContradict(A, B) :- contradicts(A, B).
contradicts/2 is meant to say: "if X is at somewhere, then X can't itself be a location."
mustContradict/2 is meant to say: "succeed if A and B are contradictory."
Assuming that your at/2 and location/1 are facts/predicates in your prolog program . . . why not something like this:
contradiction(X) :- at(X,_), location(X) .

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

My Swi-prolog code return true for every query

I'm trying to write Swi-Prolog code for family relations. There are no error but it always returns true. P
man(_Pete).
man(_Mark).
man(_John).
man(_Frank).
man(_Tom).
man(_Matt).
man(_Henry).
man(_Todd).
woman(_Lilly).
woman(_Kate).
woman(_Anne).
woman(_Alice).
woman(_Jenny).
parent(_Pete,_Mark).
parent(_Pete,_Tom).
parent(_Pete,_Anne).
parent(_Mark,_Lilly).
parent(_Mark,_John).
parent(_Mark,_Frank).
parent(_Tom,_Kate).
parent(_Anne,_Alice).
parent(_Anne,_Matt).
parent(_Alice,_Henry).
parent(_Matt,_Jenny).
parent(_Matt,_Todd).
father(X,Y) :- man(X),parent(X,Y).
mother(X,Y) :- woman(X),parent(X,Y).
sibling(X,Y) :- parent(Z,X),parent(Z,Y).
sister(X,Y) :- woman(X),sibling(X,Y).
brother(X,Y) :- man(X), sibling(X,Y).
grandparent(X,Y) :- parent(X,Z),parent(Z,Y).
I'm expecting to check relations. Like if I try a function ?- parent(Pete,John). I believe it should return false, but it actually returns true for every query. This is my first program on Prolog and might need help to understand the problem.
You probably meant to write names but instead you put anonymous variables in there.
Instead of parent(_Matt,_Todd) you should write parent('Matt', 'Todd') or even parent(matt, todd).
This is an anonymous variable: _X.
This is a normal variable: X.
This is a lower-case atom. It is has a length of 1, so it is also a "char": x.
This is an upper-case char: 'X'.
If you wrap anything in single quotes, it becomes an atom. It can also have spaces in it.
If you put an underscore at the front, you get an anonymous variable. It ends at the first space or operator.
If you are getting "Singleton variable" warnings, it is usually one of two things.
Beginners often mean to write 'Bob' but write Bob instead (without the single quotes).
You are defining a predicate and you forget to use one of the variables in it. You either have to make it an anonymous variable, _Bob, if you really don't care about it, or you find where in the predicate you were supposed to use it.

How to check whether some variable returns something in predicate

Lets assume I have facts as follows:
airport(nyc,'newyork').
I want want to display a message if the user inputs an airport that doesn't exist.
My Attempt:
isAirport(Air) :-
airport(Air,T),
(var(T) -> true
;
write('Airport not found'),
fail
).
However, this doesn't seem to work.
First let's see what happens if you query a conjunction (the , operator) first:
?- airport(nyc, _), write('found!').
found!
true.
?- airport(abc, _), write('found!').
false.
This means, isAirport(abc) directly fails after trying airport(abc,_) without the rest of your predicate being evaluated. In many cases, you can therefore get by without an explicit if-then-else construct and just write something of the form
predicate(X) :-
first_condition(X),
second_condition(X).
and it will only succeed if both conditions are fulfilled for X.
In case you really want to create some user interface, this is a bit more tricky, because I/O is inherently non-logical, in particular when there is backtracking involved. We usually call a program which behaves like we would expect from a logical formula pure and when it contains non-logical constructs like I/O or the cut operator ! are called impure.
Unfortunately, the if-then-else construct (-> and ;) and negation (\+) are implemented via cut and therefore impure as well. Luckily, most of the time people want a conditional, a pure disjunction is sufficient:
case(1,a).
case(2,b).
We have an automatic branching from the execution mechanism of Prolog:
?- case(X,Y).
X = 1,
Y = a ;
X = 2,
Y = b.
But sometimes we really want to do something that needs the impure constructs, like user input. Then the easiest way to keep the nice logical properties of our program is to separate the task into pure and impure ones:
main :-
uinput(Data),
pure_predicate(Data, Result),
write(Result).
After we have done all the impure parts, Data is unified with the user data we wanted. Let's have a look at the implementation of uinput/1:
uinput(data(Airport,D-M-Y)) :-
format('~nAirport? '),
read(Airport),
( ground(Airport), airport(Airport, _) )
->
(
format('~nDay? '),
read(D),
format('~nMonth? '),
read(M),
format('~nYear? '),
read(Y),
( ground(D-M-Y), isDate(D-M-Y) )
->
true
;
throw(failure('unknown date'))
)
;
throw(failure('unknown airport'))
.
We successively read terms from the input and throw an exception if we can't handle it. For the if-then-else construct to work, we need to take special care. If we compare the two queries:
?- between(1,3,X), write(X).
1
X = 1 ;
2
X = 2 ;
3
X = 3.
and
?- between(1,3,X) -> write(X); false.
1
X = 1.
you can see that the if-then-else is losing solutions. This means we need to make sure that our condition is deterministic. Asking for a user input term to be ground is already a good idea, because without variables, there is only one solution term. Still, a call to one of the data-predicates airport/1 and isDate/1 might generate the same term multiple times or not terminate at all. In this particular case, we just need to make sure that each airport has a unique shortcut name, we can also generate dates without repetition:
airport(nyc, 'New York City').
airport(wdc, 'Washington DC').
isDate(X-Y-Z) :-
between(1,31,X),
between(1,12,Y),
between(1970,2100,Z).
Another trick in the implementation of uinput is that we just succeed with true when we have validated everything. The only effect of is now that Data is instantiated with whatever the user entered.
If we give a dummy implementation of the actual implementation, we can already try the implementation oursevles:
pure_predicate(_Data, Result) :-
% here goes the actual stuff
Result='we have found something awesome'.
On the prompt we can use the pure predicate without trouble:
?- pure_predicate(someinputdata,Y).
Y = 'we have computed something awesome'.
On the other hand, we can also use the full predicate as follows:
?- main(_).
Airport? wdc.
Day? |: 1.
Month? |: 2.
Year? |: 2000.
we have found something awesome
true.
Since we are using read, we have to input prolog terms and terminate with a dot ., but everything worked as expected.
In case the user input fails, we get:
?- main(_).
Airport? bla(X).
ERROR: Unhandled exception: failure('unknown airport')
Please note that we only went through this trouble to actually fail early and give a user message in that case. For the actual computation, this is completely unneccessary.
In the code below you are making false assumption that T will remain unbound in case if airport will not be found in database:
airport(Air, T)
What happens actually is that call to airport(Air, T) will make isAirport(Air) to fail immediately and your var(T) and other parts will not be executed at all.
Try this code instead:
isAirport(Air) :-
airport(Air, _T), ! ; write('Airport not found'), fail.

Pattern-matching: query returns 'no' even when base case provided

I have a simple Prolog-program that I need some help debugging.
The point is to extend the program by pattern-matching to create a proof checker for propositional logic. The problem I have is that I get no when I expect yes and my 'fix' (providing a base case for valid_proof_aux) still gives me two solutions and I don't know why.
Not sure how to go about debugging Prolog yet, sorry.
%call:
valid_proof([p],p,[[1, p, premise]])
%src:
reverse_it([],Z,Z).
reverse_it([H|T],Z,Acc) :- reverse_it(T,Z,[H|Acc]).
valid_proof(Prems,Goal,Proof):-
last(Proof, [_, Goal, _]),
reverse_it(Proof, RevP, []),
valid_proof_aux(Prems, RevP) .
valid_proof_aux(Prems,
[[_,Prop,premise] | T]):-
memberchk(Prop,Prems),
valid_proof_aux(Prems,T).
%my 'fix'
valid_proof_aux(_, []) :- true .
You don't really show how to run the program and what exactly you get (you should edit your question with and add this), so this answer is a bit of a guess, but anyway:
You need the base case either way (as you observe yourself), valid_proof_aux/2 would fail when the list becomes empty [] and does not match [[...]|T] anymore.
?- [] = [_|_]. % try to unify an empty list with a non-empty list
false.
What you need to do to get rid of the choice point is to put the list argument as the first argument.
valid_proof_aux([], _).
valid_proof_aux([[_,Prop,premise]|T], Prems) :-
memberchk(Prop, Prems),
valid_proof_aux(T, Prems).
Note that you don't need the :- true., this is implicit. Also, avoid leaving any blanks on the two sides of the | in [Head|Tail].

Resources