Getting started with prolog and I am trying to do some simple exercises, however I got stuck pretty early... What I am trying to 'say' is: mike likes anyone if it's a man or a woman and it is not mike. But the X \= mike seems to be ignored:
man(mike).
man(danny).
man(samuel).
man(henry).
woman(samantha).
woman(jane).
woman(betty).
woman(jenny).
likes(mike, X) :-
man(X);
woman(X),
X \= mike.
mike shows up...
?- findall(X, likes(mike, X), L).
L = [mike, danny, samuel, henry, samantha, jane, betty, jenny].
I assume it's because prolog evaluates the rule man(X) first so mike is true. However if I change it to:
likes(mike, X) :-
X \= mike,
man(X);
woman(X).
I will only get the women.
?- findall(X, likes(mike, X), L).
L = [samantha, jane, betty, jenny].
The question is how to do it then? Thanks!
Note: I am using swi-prolog
The problem is operator precedence. Just C/C#/Java/SQL and other procedural languages, in Prolog, logical OR (;) has a different precedence than does logical AND (',').
In most procedural languages, an expression like
A || B && C
Is parsed as
A || ( B && C )
In Prolog, an expression like yours
A ; B , C
is parsed as if written
A ; (B,C)
So your
likes(mike, X) :-
man(X);
woman(X),
X \= mike.
is essentially
likes(mike,X) :- man(X) ; ( woman(X) , X \= mike ) .
You are asserting that Mike likes anyone who is
a man (including himself), OR
a woman who is not mike.
When what you mean was that Mike likes anyone — male or female — other than himself.
So...you need to make the precedence explicit with parentheses,
likes(A,B) :- ( man(B) ; woman(B) ) , A \= B .
or better yet, break your predicate up into 2 clauses and make it generic:
likes(A,B) :- man(B) , A \= B .
likes(A,B) :- woman(B) , A \= B .
Improve things further by making gender an attribute of the entity (a person) rather than a fact in and of itself:
person( mike , male ) .
person( danny , male ) .
person( samuel , male ) .
person( henry , male ) .
person( samantha , female ) .
person( jane , female ) .
person( betty , female ) .
person( jenny , female ) .
Then likes/2 is even simpler, since one can like people of both genders:
likes(A,B) :- person(B,_) , A \= B .
Besides the OR-problem there is another problem. The predicate (\=)/2 is not a constraint, means its essentially not a fully declarative predicate.
The predicate is usually bootstrapped via negation as failure, and negation as failure itself is not fully declarative.
The predicate is bootstrapped from ordinary unification as follows:
X \= Y :- \+ X = Y.
An alternative definition would be:
X \= X :- !, fail.
_ \= _.
If you really want to be able to move around the inequality you should take a Prolog system with constraints and then resort to dif/2.
With dif/2 you can write:
likes(mike, X) :-
(dif(X, mike),
man(X)
; woman(X)).
Or the following:
likes(mike, X) :-
(man(X),
dif(X, mike)
; woman(X)).
And you will get the same results. This is not possible with (\=)/2.
Bye
P.S.: Reasons for the problems with (\=)/2. Negation as failure \+ A sometimes not only acts as ~A, but also as ~exists X1,..,Xn A. The interested reader might like to wade through the admittedly little old, but still applicable:
The Proof Theory of Logic Programs with Negation
Robert Stärk, Bern, 1992
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.29.2745&rep=rep1&type=pdf
The problem is with the OR operator (;) :
man(mike).
man(danny).
man(samuel).
man(henry).
woman(samantha).
woman(jane).
woman(betty).
woman(jenny).
Your solution:
likes(mike, X) :- (man(X);woman(X)),X\=mike.
Another solution (using an equivalent to the OR operator) could be:
likes(mike, X) :- man(X), X\=mike.
likes(mike, X) :- woman(X).
Notice that you don't need an OR operator.
Related
here's the assignment: In a Prolog program, predicates are defined:
mother(M,Y) — M is the mother of Y
father(F,X) — F is the father of X
Write Prolog code to implement the predicate:
cousins(X,Y) — X and Y are cousins
brother_or_sister(X,Y) — X and Y are brother or sister of each other.
My attempts:
mother(m1, nicolas).
father(f1,nicolas).
mother(m2, mark).
father(f2, mark).
father(f3, f1).
mother(m3, f1).
father(f3, f2).
mother(m3, f2).
brother_or_sister(X, Y) :-
father(f3, X),
father(f3, Y),
mother(m3, X),
mother(m3, Y).
cousins(X, Y) :-
(
mother(m1, X),
father(f1, X),
mother(m2, Y),
father(f2, Y)
)
(
(
brother_or_sister(m1, m2) ;
brother_or_sister(f1, f2)
)
;
(
brother_or_sister(f1, m2) ;
brother_or_sister(m1, f2)
).
Program output:
true
false
Although it's supposed to be true
Please help!
Brothers and sisters are siblings. Two people are siblings if they have common parentage (and half-siblings if they share just one common parent). So we can say things like:
parents(F:M,X) :- mother(M,X), father(F,X) .
sibling(X,Y) :- parents(F:M,X), parents(F:M,Y) .
Similarly, two people are cousins if they have parents who are siblings of each other. That leads to:
parent(P,X) :- father(P,X) .
parent(P,X) :- mother(P,X) .
cousin(X,Y) :- parent(Px,X), parent(Py,Y), sibling(Px,Py) .
I have recently discovered the language Prolog and have been doing exercises on its basics. I am currently creating a database on animal classes like mammals, birds and reptiles, I want to expand the database by having a size comparison within the animals but not sure how.
Here is my database.
warm_blooded(bat).
warm_blooded(penguin).
cold_blooded(crocodile).
has_fur(bat).
has_feathers(penguin).
has_scales(crocodile).
gives_birth_live(bat).
lays_eggs(penguin).
lays_eggs(crocodile).
produces_milk(bat).
has_lungs(crocodile).
has_lungs(bat).
has_lungs(penguin).
%% if the being belongs to the mammalai class ,mammalia being the scientific word for mammal
mammalia(X) :-
warm_blooded(X),
produces_milk(X),
(
has_fur(X)
;
gives_birth_live(X)
),
format('~w ~s mammal ~n', [X, "is a"]).
%% if the being belongs to the aves class aves being the scientific word for bird
aves(X) :-
warm_blooded(X),
has_feathers(X),
lays_eggs(X),
has_lungs(X),
format('~w ~s bird ~n', [X, "is a"]).
%% if the being belongs to the reptillia class(reptillia being the scientific word for reptile
reptillia(X) :-
cold_blooded(X),
lays_eggs(X),
has_scales(X),
has_lungs(X),
format('~w ~s reptile ~n', [X, "is a"]).
I've tried adding sizes within the parameters but I keep getting compilation errors. I want to have an output wherein the user is able to determine which animal is bigger when compared with each other.
A simple an effective way is to just associate a size fact with each animal.
size(bat,1).
size(penguin,2).
size(crocodile,3).
Then add one predicate with two clauses to chose the larger of the two animals.
larger(A,B,A) :-
size(A,S1),
size(B,S2),
S1 > S2.
larger(A,B,B) :-
size(A,S1),
size(B,S2),
S2 >= S1.
Examples:
?- larger(penguin,crocodile,X).
X = crocodile.
?- larger(penguin,bat,X).
X = penguin ;
false.
?- larger(bat,bat,X).
X = bat.
Note that for examples where the the second animal is smaller, it tries the first clause and succeeds, but then has a choice point and so tries the second clause and fails. This is the pure solution.
If you want to use a cut to avoid the choice point, which is impure, you can do the following
larger_2(A,B,A) :-
size(A,S1),
size(B,S2),
S1 > S2,
!.
larger_2(A,B,B) :-
size(A,S1),
size(B,S2),
S2 >= S1,
!.
Examples:
?- larger_2(penguin,crocodile,X).
X = crocodile.
?- larger_2(penguin,bat,X).
X = penguin.
?- larger_2(bat,bat,X).
X = bat.
Another way as noted by Daniel Lyons is to use ->/2
larger_3(A,B,Larger) :-
size(A,SA),
size(B,SB),
(
SA > SB
->
Larger = A
;
Larger = B
).
This variation is not one operator of just ->/2 but a combination of both ->/2 and ;2.
This also does not leave a choice point and is impure because it too uses a cut (!). Using listing/1 we can see the implementation in Prolog.
?- listing('->'/2).
:- meta_predicate 0->0.
system:A->B :-
call(( A
-> B
)).
true.
?- listing(;/2).
:- meta_predicate 0;0.
system:A:B;A:C :- !,
call(A:(B;C)).
system:A:B;C:D :-
call(A:(B;C:D)).
true.
Notice the cut !.
How the two operators work together is noted in the SWI-Prolog documentation.
The combination ;/2 and ->/2 acts as if defined as:
If -> Then; _Else :- If, !, Then.
If -> _Then; Else :- !, Else.
If -> Then :- If, !, Then.
One other point to note about the use of ->/2 with ;/2 is that the syntactic layout among many Prolog programmers is to use () with the combination and offset the operators ->/2 and ;2 so that the ; stands out.
(
% condition
->
% true
;
% false
)
When a ; is used as an OR operator and not offset the ; is often overlooked in doing a quick scan of the source code as it is seen as a comma , instead of a ;.
Also note the absence of . or , after
SA > SB
and
Larger = A
and
Larger = B
but at the end an operator is needed,
).
Consider this code
:- use_module(library(clpfd)).
p(1).
p(3).
p(5).
p(7).
predecessor(A, B) :- A #= B - 1. % is true for pairs
q(X) :- predecessor(P, X), \+ p(P).
If I query ?- p(X) I correctly get the results
?- p(X).
X = 1 ;
X = 3 ;
X = 5 ;
X = 7.
But if I query ?- q(X) then I get false.
I realize that \+ is really not negation but faliure to prove, but what if not being able to prove something is sufficient for another predicate being true?
I wanted to give a reasonable use case / example which is why I resorted to using clpfd. Even without using it, I have another example which I can present:
likes(betty, butter).
likes(betty, jam) :- fail.
dislikes(betty, Item) :- \+ likes(betty, Item).
This example too, has a shortcoming that likes(betty, jam) :- fail. isn't really doing anything. But I hope I'm able to get my point across.
Is there a way in prolog to define this dependence?
You have to specifically define the "negative universe" of possibilities if you want Prolog to provide solutions in that space.
For instance, \+ p(X) cannot tell you specific values of X because the possible X that meet this criteria have not been defined. You're asking Prolog to invent what X might possibly be, which it cannot do.
You could define the universe of all possible values, then you can define what \+ p(X) means:
:- use_module(library(clpfd)).
p(1).
p(3).
p(5).
p(7).
predecessor(A, B) :- A #= B - 1. % is true for pairs
q(X) :- predecessor(P, X), P in 0..9, label([P]), \+ p(P).
Then you get:
2 ?- q(X).
X = 1 ;
X = 3 ;
X = 5 ;
X = 7 ;
X = 9 ;
X = 10.
3 ?-
Here we've told Prolog that the possible universe of P to choose from is defined by P in 0..9. Then the call \+ p(P) can yield specific results. Unfortunately, using \+, you still have to apply label([P]) before testing \+ p(P), but you get the idea.
In your other example of likes, it's the same issue. You defined:
likes(betty, butter).
likes(betty, jam) :- fail.
As you indicated, you wouldn't normally include likes(betty, jam) :- fail. since failure would already occur due to lack of a successful fact or predicate. But your inclusion is really an initial attempt to define the universe of possible choices. Without that definition, Prolog cannot "invent" what to pick from to test for a dislike. So a more complete solution would be:
person(jim).
person(sally).
person(betty).
person(joe).
food(jam).
food(butter).
food(eggs).
food(bread).
likes(betty, butter).
Then you can write:
dislikes(Person, Food) :-
person(Person),
food(Food),
\+ likes(Person, Food).
How to create such logic in GNU Prolog? How to define not_a_parent() predicate?
parent(john,chris).
parent(mary,chris).
not_a_parent(X) :- \+ parent(X,Y).
The interesting answer to the similar question is What is the logical 'not' in Prolog?. But I do not see how to implement it here.
This worked for me:
parent(john,chris).
parent(mary,chris).
parent(mary,suzanne).
parent(suzanne,jane).
parent(suzanne,peter).
parent(peter,rose).
parent(jerry,rose).
parent(jane,carl).
not_a_parent(NonParents) :- setof(Z,Y^parent(Y,Z),SetOfChildren),
findNonParents(SetOfChildren, NonParents, []),!.
findNonParents([],A,A).
findNonParents([H|SetOfChildren], NonParents, A):-
not(call(parent(H,_))),
findNonParents(SetOfChildren,NonParents,[H|A]).
findNonParents([_|SetOfChildren], NonParents, A):-
findNonParents(SetOfChildren,NonParents,A).
Result for querying not_a_parent(NonParents) is:
?- not_a_parent(NonParents).
NonParents = [rose, chris, carl].
You need to enumerate all the persons somehow. For example
not_a_parent(X) :- ( X = john ; X = mary ; X = chris ), \+ parent(X,_).
In any real program you would probably have some simple way to get all persons, and then you can do
not_a_parent(X) :- person(X), \+ parent(X,_).
You need to get all the instances of parent/2 such that X never unifies parent(X,_). findall(Template, Goal, Instances) executes the Goal until it fails and populate the list Instances with the terms that unify the Template. That way, if the list Instances is empty then parent(X,_) does not exist.
So your predicate would be like:
not_a_parent(X):- findall(_, parent(X,_) , []).
This is the problem :
Victor has been murdered, and Arthur, Bertram, and Carleton are
suspects. Arthur says he did not do it. He says that Bertram was the
victim’s friend but that Carleton hated the victim. Bertram says he
was out of town the day of the murder, and besides he didn’t even know
the guy. Carleton says he is innocent and he saw Arthur and Bertram
with the victim just before the murder. Assuming that everyone–except
possibly for the murderer–is telling the truth, use resolution to
solve the crime.
This is what I wrote in SWI Prolog
% Facts:
p('Arthur'). % suspect
p('Bertram'). % suspect
p('Carleton'). % suspect
p('Victor'). % victim
% Arthur
says('Arthur', i('Arthur')).
says('Arthur', f('Bertram', 'Victor')).
says('Arthur', ht('Carleton', 'Victor')).
% Bertram
says('Bertram', o('Bertram')).
says('Bertram', nk('Bertram', 'Victor')).
% Carleton
says('Carleton', i('Carleton')).
says('Carleton', t('Arthur', 'Victor')).
says('Carleton', t('Bertram', 'Victor')).
% Rules:
holds(X) :- says(Y, X), \+m(Y).
holds(i(X)) :- p(X), \+m(X).
holds(f(X,Y)) :- p(X), p(Y), holds(f(Y,X)).
holds(f(X,Y)) :- p(X), p(Y), \+holds(nk(X,Y)).
holds(o(X)) :- p(X), p(Y), holds(t(X,Y)).
holds(o(X)) :- p(X), \+m(X).
holds(nk(X,Y)) :- p(X), p(Y), \+holds(nk(Y,X)).
holds(nk(X,Y)) :- p(X), p(Y), \+holds(f(X,Y)).
holds(t(X,Y)) :- p(X), p(Y), holds(t(Y,X)).
holds(t(X,Y)) :- p(X), p(Y), p(Z), holds(t(X,Z)), holds(t(Z,Y)).
m(X) :- p(X).
The answer is suppose to be Bertram, but I kept on getting Arthur. Dont know what am I doing wrong.
I'm fairly sure that Rules will be far more simpler than that.
For instance, what does mean m(X) :- p(X)., given that p(X) is always true ? Does Victor have something to say ?
In logic it's essential to stick to Occam's Razor. Programming logic it's not an exception, albeit the term has a more practical connotation - see KISS principle.
I think we can only agree that the murder should be the person that contradicts other two. There is only a fact in question: whether or not a person known Victor.
Then what we know about the crime can be summarized:
t(a) :- k(b), k(c).
t(b) :- \+ k(b).
t(c) :- k(a), k(b).
k(_).
where t(X) stands for X testimony that, and k(X) stands for X known Victor.
We don't really know about k(X), then we must add k(_).
With that, Prolog can suggest:
?- t(X).
X = a ;
X = c.
I.e. only a or b can be true.
EDIT: because Prolog isn't propositive when it came to negation, here is a way to solicit the solution:
m(X) :- member(X, [a,b,c]), \+ t(X).
But let's take a more explicit approach:
Instead of clausal form, that leads to immediate availability of Prolog execution, as shown above, our fact base could also expressed:
say(a, know_victim(b, yes)).
say(a, know_victim(c, yes)).
say(b, know_victim(b, no)).
say(c, know_victim(a, yes)).
say(c, know_victim(b, yes)).
now let's see if some some individual says the opposite of others
liar(I) :-
select(I, [a,b,c], Js),
say(I, Fact),
maplist(negate(Fact), Js).
negate(know_victim(I, X), J) :-
say(J, know_victim(I, Y)),
X \= Y.
yields
?- liar(I).
I = b ;
false.
https://github.com/Anniepoo/prolog-examples
contains several different ways of solving this.