Reputation: 225
I want to write the following as a fact in Prolog using the format want_to_eat(Jack, food)
: Jack wants to eat food A OR food B. I tried to write it as want_to_eat(Jack, (A ; B))
, but want_to_eat(Jack, A)
returns false. What else can I do?
Follow-up question: Suppose Jack wants to eat apple, and at least one of bread and cherry. It seems one cannot distinguish And and Or if one uses the following.
wants_to_eat(jack, apple).
wants_to_eat(jack, bread).
wants_to_eat(jack, cherry).
What should I do in this case?
Upvotes: 1
Views: 172
Reputation: 476574
First of all there is a problem with the syntax: an uppercase identifier is a variable, not a constant. So you should only write:
wants_to_eat(jack, apple).
not:
wants_to_eat(Jack, Apple).
Next the ;
in an a parameter is just a functor. Prolog does not attach any semantics to these functors. For Prolog (;)/2
is just (;)/2
. The same happens for a comma: wants_to_eat(jack, (apple, apple, apple))
does not "fold" to the fact that jack
will eat an apple
, it is just a chain of (,)/2
functors. Only in the body of a clause, it is seen as a "logical or" (although in Prolog, most operators have a slightly different meaning than their logical counterpart, especially the not is a tricky one).
If you write:
wants_to_eat(jack, (apple; bread; cherry)).
then it only unify with the entire second parameter:
?- wants_to_eat(jack, A).
A = (apple;bread;cherry).
or due to unification, you can unify with a part of it:
?- wants_to_eat(jack, (A;_)).
A = apple.
?- wants_to_eat(jack, (_;B)).
B = (bread;cherry).
So we can not just write such values in a semi-colon separated list. Normally what one does is write several facts, like:
wants_to_eat(jack, apple).
wants_to_eat(jack, bread).
wants_to_eat(jack, cherry).
We can also perform unification in the body, and then use a semi-colon, like:
wants_to_eat(jack, F) :-
F = apple;
F = bread;
F = cherry.
The above might not be very feasible in case the are a large amount of people (alice
, bob
, jack
, etc.), and a large number of foods (apple
, bread
, cherry
), and we want to define a cross product: so all these people like all these foods. In that case we could for example write it like:
wants_to_eat(P, F) :-
(
P = alice;
P = bob;
P = jack
), (
F = apple;
F = bread;
F = cherry
).
But the above is rather ugly. We might solve this by writing two lists, and use the member/2
[swi-doc] instead:
wants_to_eat(P, F) :-
member(P, [alice, bob, jack]),
member(F, [apple, bread, cherry]).
The above can also be applied to jack
only:
wants_to_eat(jack, F) :-
member(F, [apple, bread, cherry]).
Upvotes: 2