Prolog predicate - prolog

Hello I am a newbie to Prolog with basic question. I would like to know why these Prolog predicates daughter_of/2 and son_of/2 do not work as I want them to. For example, if I ask
16 ?- daughter_of(alice, X).
true.
(Why true? What predicate would I need to get Victoria and Albert?)
Thank you.
male(albert).
male(edward).
female(alice).
female(victoria).
parents(edward, victoria, albert).
parents(alice, victoria, albert).
sister_of(X,Y):-
female(X),
parents(X,M,F),
parents(Y,M,F).
brother_of(X,Y):-
male(X),
parents(X,M,F),
parents(Y,M,F).
daughter_of(X,Y):-
female(X),
parents(X,M,F).
son_of(X,_Y):-
male(X),
parents(X,M,F).

The problem is the definition of your doughter_of predicate.
daughter_of(X,Y):-
female(X),
parents(X,M,F).
It should be
daughter_of(X,Y):-
female(X),
parents(X,Y,_).
daughter_of(X,Y):-
female(X),
parents(X,_,Y).
So that the Y parameter is passed on to the parents predicate. Otherwise it would not be used (and even gives me a warning when loading the file). Then prolog could only tell you that X is female and X has parents, but the actual parents would be discarded because M and F are no output parameters of your predicate.
Notice that i have defined the daughter_of predicate twice to work with the father as well as with the mother.
The same applies to son_of.

Related

Use a rule if a fact doesn't exist in prolog?

I'm new to prolog.
The idea of my project is to say "The room X is free if none is a guest of X, while X is taken if a family lives in X".
I use a predicate
guest(FamilySurname,RoomTaken)
So this mean that a family has taken that room.
taken(X) :- guest(_,X).
So if a family lives in room X, then X is taken.
My problem is how could i say that the room X is free? I should use a kind of NOT, like:
free(X) :- "NOT EXIST" guest(_,X).
How could i translate that "NOT EXIST" in prolog?
I have tried with ! but it doesn't work properly... maybe I'm placing it in the wrong way.
Sorry for my english.
Check the following code:
taken(X, Y) :- guest(Y,X).
free(X) :- \+ guest(_,X).
I made the a little change to taken, now it shows you who is on that room.
guest(albert, 123).
?- taken(123, R).
R = albert.
And the free() predicate it's pretty straightforward, I used the negation operator, you can check How to negate in Prolog
The code in the first answer does not seem to be a solution, i.e. the query ?- free(X) will not give an answer, where as the query ?- free(foo) will be successful. One needs to consider query floundering in Prolog into account, i.e. all variables
Consider the following code in which two alternatives for presenting the free predicate.
room(123).
room(124).
guest(albert, 123).
taken(Room) :- guest(_, Room).
free2(Room) :- room(Room),
\+ taken(Room).
free(Room) :- room(Room),
forall(guest(_, RoomTaken),
RoomTaken \= Room).

Is this logically and syntactically correct -- Nested Fact?

I am trying to write the rule that D is my(me's) son-in-law if they are male and my daughter is the spouse of D. I do not get any errors when I run this on swish except for a few singleton variable warnings. Still, i'm not convinced I wrote this correctly..can someone clarify for me if this even makes sense? Thank you.
male(X).
male(me).
female(X).
child(X,Y).
spouse(X,Y).
daughter(A,me) :-
female(A), child(me, A).
mother(A,me) :-
female(A), child(me, A).
son_in_law(D,me) :-
male(D), spouse(daughter(A,me), D).
A fact is an always true predicate. So,
male(X).
means that every X is a male. Clearly, not a correct axiom for your domain. When you get the warning about the singleton X, you should not ignore it, but attempt to understand what it means.
Also, syntactically, nested predicates don't make sense. You should rewrite this clause
..., spouse(daughter(A,me), D).
'lifting up' the 'join' variables, for instance
..., daughter(A,me), spouse(A, D).

Sorting program for SWI Prolog

Why this program answers False in SWI-PROLOG?
sor(x, y):- sorted(y), perm(x, y).
sorted([]).
sorted([x, []]).
sorted([x, y, z]):- mi(x, y), sorted([y, z]).
perm([], []).
perm([x,y],[u,v]):- delete(u,[x,u],z), perm(z,v).
delete(x,[x,y],y].
delete(x, [y, z], [y, w]):- delete(x,z,w).
mi(0, x).
mi(s(x), s(y)):- mi(x, y).
for the query ?-
sor([s(s(s(s(s(0))))), s(s(s(s(s(s(0)))))), s(s(s(0))), s(s(0)), []], y).
This is an adaptation to SWIProlog of an inefficient sorting-program used as example in the book Foundations of Logic Programming, by Loyd (you can find the original SLOWSORT program example in this pdf, on page 9)
SWI Prolog is a standard Prolog, isn't it?
Edit
Now I have tried to correct the program (looking a little to the lists syntax in Prolog)
sor(X, Y):- perm(X, Y), sorted(Y).
sorted([]).
sorted([X|[]]).
sorted([X|[Y|Z]]):- mi(X, Y), sorted([Y|Z]).
perm([], []).
perm([X|Y],[U|V]):- delete(U,[X|Y],Z), perm(Z, V).
delete(X,[X|Y],Y).
delete(X, [Y|Z], [Y|W]):- delete(X, Z, W).
mi(0, X).
mi(s(X), s(Y)):- mi(X, Y).
and changing the query in
sor([s(s(s(s(s(0)))))|[ s(s(s(s(s(s(0))))))|[s(s(s(0)))|[ s(s(0))|[]]]]], Y).
Well, Prolog now gives success, but it gives this substitution
Y = [s(s(0)), s(s(s(0))), s(s(s(s(s(0))))), s(s(s(s(s(s(...))))))]
and I don't understand the meaning of (...): Why not (0)?
Edit2
I notice that after giving the command swipl -s slowsort.pl I obtain this error message
Warning: /home/navigazione/Scrivania/slowsort.pl:3:
Singleton variables: [X]
Warning: /home/navigazione/Scrivania/slowsort.pl:9:
Singleton variables: [X]
It seems to refer to 3th and 9th rows of the program, but I don't understand what it means.
Great, you managed to translate it to correct Prolog :)
What you see is the top level trying to make things readable by omitting stuff (the ... means there is stuff there that is not shown). See this question and answers for different ways you can tell the top level to show the complete term instead of hiding parts of it.
As for the singleton variable warnings, it just tells you that you have logical variables (on lines 3 and 9) that you have only mentioned once in their syntactical scope. You can write _X instead of X to make it explicit that you are not using the value of the variable in that scope.

Prolog Chaining winners?

I'm trying to compare two people and from those 2 people if the person had played someone before and won then lost to the newer person then that person technically is above from everyone else.
For example, It's set up like this:
Example of how it's set up: winner(won, lost).
winner(john, jacob).
winner(mike, john).
winner(scott, mike).
winner(matt, scott).
winner(X, Z) :- winner(X, Y), winner(Y, Z).
If I call: winner(matt, mike). It'll return true since matt beat scott which means he also beats mike since mike lost to scott.
Essentially I want to be able to call winner(matt, jacob). and it'll return true.
I have it only querying on tier down with that current rule, how would I go about querying through unlimited tiers? I'm confused on how to approach this.
You need two predicates. One for the basic facts, winner/2, and another for the transitive relation. For example:
transitive_winner(X, Y) :-
winner(X, Y).
transitive_winner(X, Z) :-
winner(X, Y),
transitive_winner(Y, Z).
With this definition and your winner/2 facts, you can ask e.g.
?- transitive_winner(mike, Y).
Y = john ;
Y = jacob ;
false.
You need to be careful when defining this transitive relations, however, to avoid left-recursion as in:
transitive_winner(X, Z) :-
transitive_winner(Y, Z),
winner(X, Y).
In Prolog systems that don't support tabling, a call to transitive_winner/2 would result in a stack overflow error.

Unbroken loops loops

Hi I have this problem that I can not solve.
I am a Prolog rookie and I've seen a ton of these family tree examples but none seem to address my problem.
Say I have
son(X, Y) :-
\+daughter(X, Y),
father(Y, X).
father(Y, X) :-
male(X),
son(X, Y).
and I call one of them, it will go back and forth between the conditions because each one would satisfy the one before, therefore resulting in a local stack error.
Most seem to recommend removing one of the definitions, but I need to answer father and son queries. Please, help, this seems so simple, but I just can not figure it out. How can I break after looping once?
TIA
You could:
1) you could use a wrapper predicate:
father(Y,X):-
male(X),
son_data(X,Y).
son(X,Y):-
son_data(X,Y).
son(X,Y):-
\+daughter(X, Y),
father(Y, X).
your database should look like
son_data(mike,steph).
....
father(nick,john).
....
(no son/2 entries)
2) use a prolog version that supports tabling (such as XSB) (or implement it; not such a good idea ofc)

Resources