2

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?

4

1 回答 1

1

您显示的警告中的关键短语是被忽略的子句。所以你的父子逻辑,过去的一切father(charles, harry),都被忽略了。尝试使它们连续:

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).

然后你会得到真实的答案作为你的查询。

但是,如果您atrue(要求所有解决方案)之后键入,则逻辑中存在进一步的问题。它没有优雅地结束,而是进入循环并溢出堆栈。这是由于父亲、儿子和女儿之间的循环逻辑。所以你可能想考虑一下这部分。

要绕过循环逻辑,请考虑本教程中给出的示例。这个案例使用断言的事实person(给出名字、性别和每个父母,然后使用谓词来建立这些和其他关系,通过登陆事实而不是无限循环回到其他谓词来避免循环。可能还有其他类似的方法,但这是一个例子。

于 2013-06-28T02:15:55.910 回答