Question

Prolog newbie here. I wanted to know. If I have the following predicates:

lives in( Person, Place). has a car( Person).

This is the actual database of facts:

lives_in( julie, canterbury).
lives_in( pete, darwin).
lives_in( chris, eliot).
lives_in( samantha, darwin).
lives_in( james, whitstable).
lives_in( john, keynes).
lives_in( sue, canterbury).
lives_in( 'mary jane', darwin).
lives_in( rachael, sturry).
lives_in( brad, keynes).
lives_in( keith, whitstable).

% has_a_car( Person)
% ------------------
has_a_car( pete).
has_a_car( samantha).
has_a_car( james).
has_a_car( brad).

and I want to formulate a query that tells me the people who live in either darwin or keynes and have a car

why does my query:

lives_in(X,darwin);lives_in(X,keynes),has_a_car(X).

not work? This query gives me 'mary jane' who lives in darwin, but does not have a car. Would not X have to unify with either darwin or keynes and then has a car?

thank you in advance

Was it helpful?

Solution

You need to read up on operator precedence and associativity.

;/2 (logical OR) has different precedence than does ,/2 (logical AND). That means your expression doesn't bind the way you think it does. An expression like

A ; B , C

could bind as either

  • ( A ; B ) , C
  • A ; ( B , C )

And the binding is controlled by operator precedence and associativity. Given your problem statement, "This query gives me 'mary jane' who lives in darwin, but does not have a car.", which binding do you think you got?

Try using parentheses to make your intent explicit. Even better, don't use ';/2'. Say something like this:

has_a_car(X) , lives_in(X,City) , member(City,[darwin,keynes]).

It should be noted that you'd have the same problem in most languages other than prolog as well. For instance, C/C++/C#/Java etc., an expression like

if ( A || B && C ) ...

will have exactly the same issue.

OTHER TIPS

Your query should be:

lives_in(X):- lives_in(X,darwin), has_a_car(X); lives_in(X,keynes), has_a_car(X).

This query means:

X who lives in darwin and X has a car OR X who lives in keynes and X has a car.

Τhe results for this query are:

3 ?- lives_in(X).
X = pete ;
X = samantha ;
X = brad.

Just like we wanted to.

Your query

lives_in(X,darwin);lives_in(X,keynes),has_a_car(X).

Means:

X who lives in darwin OR X who lives in keynes and X has a car

and not

(X who lives in darwin OR X who lives in keynes) and X has a car

I can understand why you made this mistake. This query would be:

lives_in(X):- (lives_in(X,darwin); lives_in(X,keynes)), has_a_car(X).

You had to add a pair of parentheses.

In Prolog, when you write ;, it is like saying OR. The comma (,) means AND.

Αlso, a little tip: It might be confusing to have two predicates with the same name (lives_in), so you could rename one of them.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top