norman
norman

Reputation: 5556

New to gprolog - how can I make this short program reach the correct conclusion?

I have the following gprolog program:

father(charles, harry). 
daughter(elizabeth, george).
son(william, charles). 
father(X, Y) :- son(Y, X).
father(X, Y) :- daughter(Y, X).
daughter(X, Y) :- \+son(X, Y), father(Y, X).
son(X, Y) :- \+daughter(X, Y), father(Y, X).

Given what I have, I tried this query:

| ?- son(harry, charles).

...and got a no (a.k.a., from what I understand, "Prolog can't prove this."). When I ran a trace on it, it didn't seem too helpful:

{trace}
| ?- son(harry, charles).
      1    1  Call: son(harry,charles) ? 
      1    1  Fail: son(harry,charles) ? 

Since son(harry, charles) should match up to the last line of my code, I figured the program would simply start by checking the first part: \+daughter(X, Y) ("Prolog can't prove that Harry is the daughter of Charles", right?). Indeed:

| ?- \+daughter(harry, charles).
      1    1  Call: \+daughter(harry,charles) ? 
      2    2  Call: daughter(harry,charles) ? 
      2    2  Fail: daughter(harry,charles) ? 
      1    1  Exit: \+daughter(harry,charles) ? 

(1 ms) yes

So then it would proceed to the second part, right? It would check for father(Y, X), i.e., father(charles, harry), which was given as a fact!

| ?- father(charles, harry).
      1    1  Call: father(charles,harry) ? 
      1    1  Exit: father(charles,harry) ? 

(1 ms) yes

With both of these true, why doesn't it give a yes for son(harry, charles)? As an important note, this did compile with discontiguous predicate warnings:

compiling /Users/nicolejulian/Dropbox/AI/test.pl for byte code...
/Users/nicolejulian/Dropbox/AI/test.pl:4: warning: discontiguous predicate father/2 - clause ignored
/Users/nicolejulian/Dropbox/AI/test.pl:5: warning: discontiguous predicate father/2 - clause ignored
/Users/nicolejulian/Dropbox/AI/test.pl:6: warning: discontiguous predicate daughter/2 - clause ignored
/Users/nicolejulian/Dropbox/AI/test.pl:7: warning: discontiguous predicate son/2 - clause ignored
/Users/nicolejulian/Dropbox/AI/test.pl compiled, 8 lines read - 617 bytes written, 11 ms

(1 ms) yes

A few earlier experiments made it seem like I basically had a choice between warnings and infinite loops, so I went along with this as-is. (for example, grouping all of the left-side labels removes the warnings but then causes the query | ?- father(elizabeth, george). to crash).

At any rate, provided that I can't just 'cheat' and add son(harry, charles) in as a fact, what am I not understanding about Prolog's execution steps?

Upvotes: 2

Views: 253

Answers (1)

lurker
lurker

Reputation: 58244

The key phrase in the warnings you show is clause ignored. So your father/son logic, everything past father(charles, harry), has been ignored. Try making them contiguous:

father(charles, harry). 
father(X, Y) :- son(Y, X).
father(X, Y) :- daughter(Y, X).

daughter(elizabeth, george).
daughter(X, Y) :- \+son(X, Y), father(Y, X).

son(william, charles). 
son(X, Y) :- \+daughter(X, Y), father(Y, X).

Then you'll get true as an answer to your query.

But there's a further issue in the logic if you type a after the true (asking for all solutions). Rather than ending gracefully, it goes into a loop and overflows the stack. It's due to the circular logic you have between father, son, and daughter. So you might want to think through that part.

To get around the circular logic, consider the example given in this tutorial. This case uses asserted facts for person (giving names, genders, and each parent, and then uses predicates to establish those and other relationships, avoiding the loops by landing on facts rather than looping back around to other predicates infinitely. There are probably other similar approaches, but this is one example.

Upvotes: 1

Related Questions