gprolog的新手 - 如何让这个简短的程序得出正确的结论?

时间:2013-06-28 00:11:36

标签: prolog logic

我有以下gprolog程序:

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

鉴于我所拥有的,我尝试了这个问题:

| ?- son(harry, charles).

...得到了一个no(据我所知,a.k.a。,“Prolog无法证明这一点。”)。当我对它进行跟踪时,它似乎没有太大帮助:

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

由于son(harry, charles)应与我的代码的最后一行匹配,我认为程序只需从检查第一部分开始:\+daughter(X, Y)(“Prolog无法证明Harry是女儿查尔斯“,对吧?”事实上:

| ?- \+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

那么它会进入第二部分,对吗?它会检查father(Y, X),即father(charles, harry),这是事实!

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

(1 ms) yes

这两个都是真的,为什么不为yes提供son(harry, charles)?作为一个重要的注释,这确实编译了不连贯的谓词警告:

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

一些早期的实验表明,我基本上可以在警告和无限循环之间做出选择,所以我按原样进行了调查。 (例如,对所有左侧标签进行分组会删除警告,但会导致查询| ?- father(elizabeth, george).崩溃)。

无论如何,只要我不能“欺骗”并添加son(harry, charles)作为一个事实,我不了解Prolog的执行步骤?

1 个答案:

答案 0 :(得分: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).

然后,您将获得 true 作为查询的答案。

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

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