How to debug "operator expected" in this Prolog program? - prolog

I'm trying to run a query for a family tree but when I enter all the information, I'm getting a syntax error: operator expected. I'm new to Prolog.
domains
name=symbol
predicates
parent(name,name)
female(name)
male(name)
sister(name,name)
son(name,name)
father(name)
grandmother(name)
clauses
female(stella).
female(lizzy).
female(emily).
female(mia).
female(alice).
male(hubert).
male(ben).
male(john).
male(danny).
male(sam).
parent(stella,ben).
parent(stella,mia).
parent(hubert,ben).
parent(hubert,mia).
parent(lizzy,emily).
parent(lizzy,john).
parent(ben,emily).
parent(ben,john).
parent(mia,sam).
parent(mia,alice).
parent(danny,sam).
parent(danny,alice).
sister(X,Y):-female(X),parent(Par,X),parent(Par,Y),X\==XY.
son(X,Y):-parent(Z,X),parent(Z,Y),male(X),X\==Y.
father(X,Y):-parent(X,Y),male(X).
grandmother(X,Y):-parent(X,Y),female(X)

There are two problems here:
you forgot a dot (.) at the end rhat signals the end of the clause; and
this is not really an error, but you write X\==XY in the sister/2 clause, since XY is a new variable, this will always succeed.
There is also a semantical problem with the grandmother/2 predicate: right now it defines a "mother" predicate. I leave this as an exercise.
I also advise to reformat your code (Prolog does not charge you per line, and it makes it more clear where a clause ends and what it does).
sister(X,Y) :-
female(X),
parent(Par,X),
parent(Par,Y),
X \== Y.
son(X,Y) :-
parent(Z,X),
parent(Z,Y),
male(X),
X \== Y.
father(X,Y) :-
parent(X,Y),
male(X).
grandmother(X,Y) :-
parent(X,Y),
female(X).

Related

negation \+ and vanilla meta-interpreter

The following is the classic "textbook" vanilla meta-interpreter for prolog.
% simplest meta-interpreter
solve(true) :- !.
solve((A,B)):- !, solve(A), solve(B).
solve(A) :- clause(A,B), solve(B).
The following is simple program which establishes facts two relations which are "positive" and one relation which makes use of negation by failure \+.
% fruit
fruit(apple).
fruit(orange).
fruit(banana).
% colour
yellow(banana).
% Mary likes all fruit
likes(mary, X) :- fruit(X).
% James likes all fruit, as long as it is yellow
likes(james, X) :- fruit(X), yellow(X).
% Sally likes all fruit, except yellow fruit
likes(sally, X) :- fruit(X), \+ (yellow(X)).
The meta-interpeter can handle goals related to the first two relations ?-solve(likes(mary,X)) and ?- solve(likes(james,X)_.
However it fails with a goal related to the third relation ?- solve(likes(sally,X). The swi-prolog reports a stack limit being reached before the program crashes.
Question 1: What is causing the meta-interpreter to fail? Can it be easily adjusted to cope with the \+ negation? Is this related to the sometimes discussed issue of built-ins not being executed by the vanilla meta-interpreter?
Question 2: Where can I read about the need for those cuts in the vanilla meta-interpreter?
Tracing suggests the goal is being grown endlessly:
clause(\+call(call(call(call(yellow(apple))))),_5488)
Exit:clause(\+call(call(call(call(yellow(apple))))),\+call(call(call(call(call(yellow(apple)))))))
Call:solve(\+call(call(call(call(call(yellow(apple)))))))
Call:clause(\+call(call(call(call(call(yellow(apple)))))),_5508)
Exit:clause(\+call(call(call(call(call(yellow(apple)))))),\+call(call(call(call(call(call(yellow(apple))))))))
Call:solve(\+call(call(call(call(call(call(yellow(apple))))))))
Change solve(A) into:
solve(Goal) :-
writeln(Goal),
sleep(1),
clause(Goal, Body),
solve(Body).
... and we see:
?- solve_mi(likes(sally,X)).
likes(sally,_8636)
fruit(_8636)
\+yellow(apple)
\+call(yellow(apple))
\+call(call(yellow(apple)))
\+call(call(call(yellow(apple))))
...
clause/2 determines the body of \+yellow(apple) to be \+call(yellow(apple)), which is not a simplification.
Can use instead:
solve_mi(true) :-
!.
solve_mi((Goal1, Goal2)):-
!,
solve_mi(Goal1),
solve_mi(Goal2).
solve_mi(\+ Goal) :-
!,
\+ solve_mi(Goal).
solve_mi(Goal) :-
clause(Goal, Body),
solve_mi(Body).
Result in swi-prolog:
?- solve_mi(likes(sally,X)).
X = apple ;
X = orange ;
false.
I'm using solve_mi because solve conflicts with e.g. clpBNR, and I'm not using variable names A and B because they convey no meaning.
For understanding the cuts, I'd recommend gtrace, to see the unwanted unification with other goals that would otherwise take place.

What does _ (Underscore) mean in this context in Prolog Amzi

I have been trying to learn some Prolog Amzi. This is an example question and can't quite wrap my head around this question.
This is the code.
/* Facts */
parent(mary,tom).
parent(john,tom).
parent(mary,alice).
parent(john,alice).
sex(mary, female).
sex(john, male).
sex(tom, male).
sex(alice, female).
/* Rules */
mother(X):-
sex(X,female),
parent(X,_).
father(X):-
sex(X, male),
parent(X,_).
sibling(X,Y):-
parent(M,X),
sex(M,female),
parent(F,X),
sex(F,male),
parent(M,Y),
parent(F,Y).
sibling1(X,Y):-
parent(M,X),
sex(M,female),
parent(F,X),
sex(F,male),
parent(M,Y),
parent(F,Y),
X \= Y.
go:-
nl, nl,
write('Hello there .....'), nl,
write('Testing on Prolog2.'), nl,
write('End Job'), n1.
The question asks what the function of the underscore in the rules mother(X) and father(X) is with examples of output.
I don't seem to understand what the underscore means in this context and what it means by example output.
In any context, an anonymous variable (denoted by _) represents an argument whose specific value is irrelevant.
For example, the rule mother(X) :- sex(X, female), parent(X, _). states that for X to be a mother, X must be female and also be the parent of someone (whose name is irrelevant and must represented by an anonymous variable).
The anonymous variable (_) does not bind to values, and multiple occurrences of it do not imply equal values.
Consider, for example, the following facts:
parent(mary, tom).
parent(mary, alice).
parent(john, tom).
parent(john, alice).
To find out who Mary's children are, you can ask:
?- parent(mary, Who).
Who = tom ;
Who = alice.
To find out whether Mary is someone's parent, you can ask:
?- parent(mary, _).
true .
To find out whether there is someone who is someone else's parent, you can ask:
?- parent(_, _).
true .
To find out whether there are people who are their own parents, you can ask:
?- parent(X, X).
false.

Prolog - family tree

I am working on creating a family tree in prolog. Where I am running into trouble is when I call on sister or brother. The results I get are correct, where julie is the sister of mike, julie is the sister of amanda, amanda is the sister of mike and amanda is the sister of julie. But what happens rather than ending there, if i keep hitting the 'n' key it will loop back through the results again. Why is this happening?
parent(pete,mike).
parent(pete,julie).
parent(pete,amanda).
parent(mary,mike).
parent(mary,julie).
parent(mary,amanda).
female(mary).
female(julie).
female(amanda).
male(mike).
male(pete).
mother(X,Y):-
parent(X,Y),
female(X).
father(X,Y):-
parent(X,Y),
male(X).
sibling(X,Y):-
parent(Z,X),
parent(Z,Y),
X\=Y.
sister(X,Y):-
sibling(X,Y),
female(X).
brother(X,Y):-
sibling(X,Y),
male(X).
Every pair of siblings will have both the same father and the same mother (in the more conservative societies, at least, and in your program at the moment). This is where you get the double answers from. You could maybe say that siblings always share both parents?
As stated, you get double answers because you're checking if they have the same parent, and they have two of those. Moreover, you're getting even more solutions because e.g. mike is sibling of amanda, but also amanda is sibling of mike, and you do nothing to prevent both solutions to appear.
So instead of:
sibling(X, Y):-
parent(Z, X),
parent(Z, Y),
X\=Y.
to solve problem of two parents, you could say they always share both parents:
sibling(X, Y):-
mother(Z, X),
mother(Z, Y),
father(W, X),
father(W, Y),
X\=Y.
You could stop second problem (X=mike, Y=amanda; X=amanda, Y=mike) by introducing #<:
sibling(X, Y):-
mother(Z, X),
mother(Z, Y),
father(W, X),
father(W, Y),
X#<Y.
This way, only one set of solutions is appearing, but you have to be careful with it, as it might not get you want you want, depending on what you want to achieve (X=julie, Y=amanda would not be true in this case).
Depending on the need, perhaps more elegant and general solution (not requiring both parents to be same) would be to use setof (http://www.swi-prolog.org/pldoc/doc_for?object=setof/3) with your original sibling clause, but you would rework your brother/sister clauses, e.g.:
sibling(X, Y):-
parent(Z, X),
parent(Z, Y),
X\=Y.
sister(X,Y,L):-
female(X),
setof([X, Y], (sibling(X, Y)), L).
brother(X,Y,L):-
male(X),
setof([X, Y], (sibling(X, Y)), L).
This would get you a list of unique pairs in list L, e.g. for sister(X, Y, L) you get:
X = julie
L = [[julie, amanda], [julie, mike]]
X = amanda
L = [[amanda, julie], [amanda, mike]]
Play with it a little to get exactly what you need.

Match database items exactly once in Prolog?

Let's say there is a simple database of people in Prolog
person(john).
person(mary).
person(john).
person(susan).
I need to match the entires exactly once:
john-mary, john-john, john-susan, mary-john, mary-susan, john-susan
I tried coming up with something like this:
match:- person(X),!,person(Y), write(X),write(-), write(Y),nl.
run:- person(X), match(X), fail.
But it's matching many times, and matches a person to him/herself, which shouldn't be.
Basically, what I need is to iterate over all Xs and make Prolog to look strictly "below" for Ys.
A quick solution would be to number your people:
person(1, john).
person(2, mary).
person(3, john).
person(4, susan).
Then you could match people like this:
match(X-Y) :-
person(I, X), person(J, Y), I < J.
Since you have two john entries, I'm not sure any other solution is going to work. Normally you could fake an ordering using #>/2 but that would require your atoms to be unique, and since they aren't, it would prevent the john-john solution.
Edit: Since we're willing to use findall/3 to materialize the database of people, we can treat this as a list problem and find a functional solution. Let's get all the combinations in a list:
combinations([X|Rest], X, Y) :- member(Y, Rest).
combinations([_|Rest], X, Y) :- combinations(Rest, X, Y).
With this predicate in hand, we can find the solution:
combined_folks(People) :-
findall(P, person(P), Persons),
findall(X-Y, combinations(Persons, X, Y), People).
?- combined_folks(X).
X = [john-mary, john-john, john-susan, mary-john, mary-susan, john-susan].
That actually turned out to be pretty clean!
person(john).
person(mary).
person(john).
person(susan).
match :- findall(P,person(P),People), match_all(People).
match_all([_]) :- !.
match_all([P|People]) :- match_2(P,People), match_all(People).
match_2(_,[]) :- !.
match_2(P1,[P2|People]) :- format('~a-~a~n',[P1,P2]), match_2(P1,People).
?- match.

Prolog read compound term and treating it like an expression

The following code isn't working
:- arithmetic_function(i/2).
i(X,Y,Z) :-
Z is X+Y.
calcola :-
write('Give me an expression'),nl,
read(ESP),
Z is ESP,nl,nl,
write(Z).
but the following is
:- arithmetic_function(i/2).
i(X,Y,Z) :-
Z is X+Y.
calcola :-
write('Give me an expression'),nl,
Z is 4 i 2,nl,nl,
write(Z).
Why is that? Seems like the "read" function isn't working properly
from SWI-Prolog mailing list ([SWIPL] Ann: SWI-Prolog 5.11.23, 23 Jun):
MODIFIED: User-defined arithmetic functions have been removed from
the kernel. There is a new library(arithmetic) that emulates the
old behaviour PARTIALLY. Notably:
This library must be loaded before arithmetic_function/1 is
used.
It only covers arithmetic functions that are visible as an argument
to is/2, >/2, etc. at compile-time.
A new predicate arithmetic_expression_value/2 can be used to
evaluate expressions with embedded user arithmetic that become
instantiated at runtime.
Well as a lead, when I test it with is/2 it fails but when I use arithmetic_expression_value/2 it succeeds :
:- arithmetic_function(i/2).
:- op(20, xfx, i).
i(X, Y, Z) :-
Z is X + Y.
calcola :-
writeln('Give me an expression'),
read(ESP),
arithmetic_expression_value(ESP, Z), nl,
write(Z).
For #gusbro, it works out of the box. I'm using windows swi-pl here, for the record !
Others may have clues about why it fails for us !

Resources